1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * V4L2 context helper functions.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
5cabdff1aSopenharmony_ci * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * This file is part of FFmpeg.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
10cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
11cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
12cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
15cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
16cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17cabdff1aSopenharmony_ci * Lesser General Public License for more details.
18cabdff1aSopenharmony_ci *
19cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
20cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
21cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22cabdff1aSopenharmony_ci */
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include <linux/videodev2.h>
25cabdff1aSopenharmony_ci#include <sys/ioctl.h>
26cabdff1aSopenharmony_ci#include <sys/mman.h>
27cabdff1aSopenharmony_ci#include <unistd.h>
28cabdff1aSopenharmony_ci#include <fcntl.h>
29cabdff1aSopenharmony_ci#include <poll.h>
30cabdff1aSopenharmony_ci#include "libavcodec/avcodec.h"
31cabdff1aSopenharmony_ci#include "libavcodec/internal.h"
32cabdff1aSopenharmony_ci#include "v4l2_buffers.h"
33cabdff1aSopenharmony_ci#include "v4l2_fmt.h"
34cabdff1aSopenharmony_ci#include "v4l2_m2m.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_cistruct v4l2_format_update {
37cabdff1aSopenharmony_ci    uint32_t v4l2_fmt;
38cabdff1aSopenharmony_ci    int update_v4l2;
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_ci    enum AVPixelFormat av_fmt;
41cabdff1aSopenharmony_ci    int update_avfmt;
42cabdff1aSopenharmony_ci};
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_cistatic inline V4L2m2mContext *ctx_to_m2mctx(V4L2Context *ctx)
45cabdff1aSopenharmony_ci{
46cabdff1aSopenharmony_ci    return V4L2_TYPE_IS_OUTPUT(ctx->type) ?
47cabdff1aSopenharmony_ci        container_of(ctx, V4L2m2mContext, output) :
48cabdff1aSopenharmony_ci        container_of(ctx, V4L2m2mContext, capture);
49cabdff1aSopenharmony_ci}
50cabdff1aSopenharmony_ci
51cabdff1aSopenharmony_cistatic inline AVCodecContext *logger(V4L2Context *ctx)
52cabdff1aSopenharmony_ci{
53cabdff1aSopenharmony_ci    return ctx_to_m2mctx(ctx)->avctx;
54cabdff1aSopenharmony_ci}
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_cistatic inline unsigned int v4l2_get_width(struct v4l2_format *fmt)
57cabdff1aSopenharmony_ci{
58cabdff1aSopenharmony_ci    return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.width : fmt->fmt.pix.width;
59cabdff1aSopenharmony_ci}
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_cistatic inline unsigned int v4l2_get_height(struct v4l2_format *fmt)
62cabdff1aSopenharmony_ci{
63cabdff1aSopenharmony_ci    return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height;
64cabdff1aSopenharmony_ci}
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_cistatic AVRational v4l2_get_sar(V4L2Context *ctx)
67cabdff1aSopenharmony_ci{
68cabdff1aSopenharmony_ci    struct AVRational sar = { 0, 1 };
69cabdff1aSopenharmony_ci    struct v4l2_cropcap cropcap;
70cabdff1aSopenharmony_ci    int ret;
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_ci    memset(&cropcap, 0, sizeof(cropcap));
73cabdff1aSopenharmony_ci    cropcap.type = ctx->type;
74cabdff1aSopenharmony_ci
75cabdff1aSopenharmony_ci    ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_CROPCAP, &cropcap);
76cabdff1aSopenharmony_ci    if (ret)
77cabdff1aSopenharmony_ci        return sar;
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci    sar.num = cropcap.pixelaspect.numerator;
80cabdff1aSopenharmony_ci    sar.den = cropcap.pixelaspect.denominator;
81cabdff1aSopenharmony_ci    return sar;
82cabdff1aSopenharmony_ci}
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_cistatic inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct v4l2_format *fmt2)
85cabdff1aSopenharmony_ci{
86cabdff1aSopenharmony_ci    struct v4l2_format *fmt1 = &ctx->format;
87cabdff1aSopenharmony_ci    int ret =  V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ?
88cabdff1aSopenharmony_ci        fmt1->fmt.pix_mp.width != fmt2->fmt.pix_mp.width ||
89cabdff1aSopenharmony_ci        fmt1->fmt.pix_mp.height != fmt2->fmt.pix_mp.height
90cabdff1aSopenharmony_ci        :
91cabdff1aSopenharmony_ci        fmt1->fmt.pix.width != fmt2->fmt.pix.width ||
92cabdff1aSopenharmony_ci        fmt1->fmt.pix.height != fmt2->fmt.pix.height;
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci    if (ret)
95cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_DEBUG, "%s changed (%dx%d) -> (%dx%d)\n",
96cabdff1aSopenharmony_ci            ctx->name,
97cabdff1aSopenharmony_ci            v4l2_get_width(fmt1), v4l2_get_height(fmt1),
98cabdff1aSopenharmony_ci            v4l2_get_width(fmt2), v4l2_get_height(fmt2));
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_ci    return ret;
101cabdff1aSopenharmony_ci}
102cabdff1aSopenharmony_ci
103cabdff1aSopenharmony_cistatic inline int v4l2_type_supported(V4L2Context *ctx)
104cabdff1aSopenharmony_ci{
105cabdff1aSopenharmony_ci    return ctx->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
106cabdff1aSopenharmony_ci        ctx->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
107cabdff1aSopenharmony_ci        ctx->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
108cabdff1aSopenharmony_ci        ctx->type == V4L2_BUF_TYPE_VIDEO_OUTPUT;
109cabdff1aSopenharmony_ci}
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_cistatic inline int v4l2_get_framesize_compressed(V4L2Context* ctx, int width, int height)
112cabdff1aSopenharmony_ci{
113cabdff1aSopenharmony_ci    V4L2m2mContext *s = ctx_to_m2mctx(ctx);
114cabdff1aSopenharmony_ci    const int SZ_4K = 0x1000;
115cabdff1aSopenharmony_ci    int size;
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci    if (s->avctx && av_codec_is_decoder(s->avctx->codec))
118cabdff1aSopenharmony_ci        return ((width * height * 3 / 2) / 2) + 128;
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_ci    /* encoder */
121cabdff1aSopenharmony_ci    size = FFALIGN(height, 32) * FFALIGN(width, 32) * 3 / 2 / 2;
122cabdff1aSopenharmony_ci    return FFALIGN(size, SZ_4K);
123cabdff1aSopenharmony_ci}
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_cistatic inline void v4l2_save_to_context(V4L2Context* ctx, struct v4l2_format_update *fmt)
126cabdff1aSopenharmony_ci{
127cabdff1aSopenharmony_ci    ctx->format.type = ctx->type;
128cabdff1aSopenharmony_ci
129cabdff1aSopenharmony_ci    if (fmt->update_avfmt)
130cabdff1aSopenharmony_ci        ctx->av_pix_fmt = fmt->av_fmt;
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
133cabdff1aSopenharmony_ci        /* update the sizes to handle the reconfiguration of the capture stream at runtime */
134cabdff1aSopenharmony_ci        ctx->format.fmt.pix_mp.height = ctx->height;
135cabdff1aSopenharmony_ci        ctx->format.fmt.pix_mp.width = ctx->width;
136cabdff1aSopenharmony_ci        if (fmt->update_v4l2) {
137cabdff1aSopenharmony_ci            ctx->format.fmt.pix_mp.pixelformat = fmt->v4l2_fmt;
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci            /* s5p-mfc requires the user to specify a buffer size */
140cabdff1aSopenharmony_ci            ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage =
141cabdff1aSopenharmony_ci                v4l2_get_framesize_compressed(ctx, ctx->width, ctx->height);
142cabdff1aSopenharmony_ci        }
143cabdff1aSopenharmony_ci    } else {
144cabdff1aSopenharmony_ci        ctx->format.fmt.pix.height = ctx->height;
145cabdff1aSopenharmony_ci        ctx->format.fmt.pix.width = ctx->width;
146cabdff1aSopenharmony_ci        if (fmt->update_v4l2) {
147cabdff1aSopenharmony_ci            ctx->format.fmt.pix.pixelformat = fmt->v4l2_fmt;
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci            /* s5p-mfc requires the user to specify a buffer size */
150cabdff1aSopenharmony_ci            ctx->format.fmt.pix.sizeimage =
151cabdff1aSopenharmony_ci                v4l2_get_framesize_compressed(ctx, ctx->width, ctx->height);
152cabdff1aSopenharmony_ci        }
153cabdff1aSopenharmony_ci    }
154cabdff1aSopenharmony_ci}
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_cistatic int v4l2_start_decode(V4L2Context *ctx)
157cabdff1aSopenharmony_ci{
158cabdff1aSopenharmony_ci    struct v4l2_decoder_cmd cmd = {
159cabdff1aSopenharmony_ci        .cmd = V4L2_DEC_CMD_START,
160cabdff1aSopenharmony_ci        .flags = 0,
161cabdff1aSopenharmony_ci    };
162cabdff1aSopenharmony_ci    int ret;
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DECODER_CMD, &cmd);
165cabdff1aSopenharmony_ci    if (ret)
166cabdff1aSopenharmony_ci        return AVERROR(errno);
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    return 0;
169cabdff1aSopenharmony_ci}
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci/**
172cabdff1aSopenharmony_ci * handle resolution change event and end of stream event
173cabdff1aSopenharmony_ci * returns 1 if reinit was successful, negative if it failed
174cabdff1aSopenharmony_ci * returns 0 if reinit was not executed
175cabdff1aSopenharmony_ci */
176cabdff1aSopenharmony_cistatic int v4l2_handle_event(V4L2Context *ctx)
177cabdff1aSopenharmony_ci{
178cabdff1aSopenharmony_ci    V4L2m2mContext *s = ctx_to_m2mctx(ctx);
179cabdff1aSopenharmony_ci    struct v4l2_format cap_fmt = s->capture.format;
180cabdff1aSopenharmony_ci    struct v4l2_event evt = { 0 };
181cabdff1aSopenharmony_ci    int ret;
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    ret = ioctl(s->fd, VIDIOC_DQEVENT, &evt);
184cabdff1aSopenharmony_ci    if (ret < 0) {
185cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_DQEVENT\n", ctx->name);
186cabdff1aSopenharmony_ci        return 0;
187cabdff1aSopenharmony_ci    }
188cabdff1aSopenharmony_ci
189cabdff1aSopenharmony_ci    if (evt.type == V4L2_EVENT_EOS) {
190cabdff1aSopenharmony_ci        ctx->done = 1;
191cabdff1aSopenharmony_ci        return 0;
192cabdff1aSopenharmony_ci    }
193cabdff1aSopenharmony_ci
194cabdff1aSopenharmony_ci    if (evt.type != V4L2_EVENT_SOURCE_CHANGE)
195cabdff1aSopenharmony_ci        return 0;
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_fmt);
198cabdff1aSopenharmony_ci    if (ret) {
199cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT\n", s->capture.name);
200cabdff1aSopenharmony_ci        return 0;
201cabdff1aSopenharmony_ci    }
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_ci    if (v4l2_resolution_changed(&s->capture, &cap_fmt)) {
204cabdff1aSopenharmony_ci        s->capture.height = v4l2_get_height(&cap_fmt);
205cabdff1aSopenharmony_ci        s->capture.width = v4l2_get_width(&cap_fmt);
206cabdff1aSopenharmony_ci        s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture);
207cabdff1aSopenharmony_ci    } else {
208cabdff1aSopenharmony_ci        v4l2_start_decode(ctx);
209cabdff1aSopenharmony_ci        return 0;
210cabdff1aSopenharmony_ci    }
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci    s->reinit = 1;
213cabdff1aSopenharmony_ci
214cabdff1aSopenharmony_ci    if (s->avctx)
215cabdff1aSopenharmony_ci        ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
216cabdff1aSopenharmony_ci    if (ret < 0)
217cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_WARNING, "update avcodec height and width\n");
218cabdff1aSopenharmony_ci
219cabdff1aSopenharmony_ci    ret = ff_v4l2_m2m_codec_reinit(s);
220cabdff1aSopenharmony_ci    if (ret) {
221cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "v4l2_m2m_codec_reinit\n");
222cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
223cabdff1aSopenharmony_ci    }
224cabdff1aSopenharmony_ci
225cabdff1aSopenharmony_ci    /* reinit executed */
226cabdff1aSopenharmony_ci    return 1;
227cabdff1aSopenharmony_ci}
228cabdff1aSopenharmony_ci
229cabdff1aSopenharmony_cistatic int v4l2_stop_decode(V4L2Context *ctx)
230cabdff1aSopenharmony_ci{
231cabdff1aSopenharmony_ci    struct v4l2_decoder_cmd cmd = {
232cabdff1aSopenharmony_ci        .cmd = V4L2_DEC_CMD_STOP,
233cabdff1aSopenharmony_ci        .flags = 0,
234cabdff1aSopenharmony_ci    };
235cabdff1aSopenharmony_ci    int ret;
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci    ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DECODER_CMD, &cmd);
238cabdff1aSopenharmony_ci    if (ret) {
239cabdff1aSopenharmony_ci        /* DECODER_CMD is optional */
240cabdff1aSopenharmony_ci        if (errno == ENOTTY)
241cabdff1aSopenharmony_ci            return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
242cabdff1aSopenharmony_ci        else
243cabdff1aSopenharmony_ci            return AVERROR(errno);
244cabdff1aSopenharmony_ci    }
245cabdff1aSopenharmony_ci
246cabdff1aSopenharmony_ci    return 0;
247cabdff1aSopenharmony_ci}
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_cistatic int v4l2_stop_encode(V4L2Context *ctx)
250cabdff1aSopenharmony_ci{
251cabdff1aSopenharmony_ci    struct v4l2_encoder_cmd cmd = {
252cabdff1aSopenharmony_ci        .cmd = V4L2_ENC_CMD_STOP,
253cabdff1aSopenharmony_ci        .flags = 0,
254cabdff1aSopenharmony_ci    };
255cabdff1aSopenharmony_ci    int ret;
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci    ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENCODER_CMD, &cmd);
258cabdff1aSopenharmony_ci    if (ret) {
259cabdff1aSopenharmony_ci        /* ENCODER_CMD is optional */
260cabdff1aSopenharmony_ci        if (errno == ENOTTY)
261cabdff1aSopenharmony_ci            return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
262cabdff1aSopenharmony_ci        else
263cabdff1aSopenharmony_ci            return AVERROR(errno);
264cabdff1aSopenharmony_ci    }
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    return 0;
267cabdff1aSopenharmony_ci}
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_cistatic V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout)
270cabdff1aSopenharmony_ci{
271cabdff1aSopenharmony_ci    struct v4l2_plane planes[VIDEO_MAX_PLANES];
272cabdff1aSopenharmony_ci    struct v4l2_buffer buf = { 0 };
273cabdff1aSopenharmony_ci    V4L2Buffer *avbuf;
274cabdff1aSopenharmony_ci    struct pollfd pfd = {
275cabdff1aSopenharmony_ci        .events =  POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM, /* default blocking capture */
276cabdff1aSopenharmony_ci        .fd = ctx_to_m2mctx(ctx)->fd,
277cabdff1aSopenharmony_ci    };
278cabdff1aSopenharmony_ci    int i, ret;
279cabdff1aSopenharmony_ci
280cabdff1aSopenharmony_ci    if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx->buffers) {
281cabdff1aSopenharmony_ci        for (i = 0; i < ctx->num_buffers; i++) {
282cabdff1aSopenharmony_ci            if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER)
283cabdff1aSopenharmony_ci                break;
284cabdff1aSopenharmony_ci        }
285cabdff1aSopenharmony_ci        if (i == ctx->num_buffers)
286cabdff1aSopenharmony_ci            av_log(logger(ctx), AV_LOG_WARNING, "All capture buffers returned to "
287cabdff1aSopenharmony_ci                                                "userspace. Increase num_capture_buffers "
288cabdff1aSopenharmony_ci                                                "to prevent device deadlock or dropped "
289cabdff1aSopenharmony_ci                                                "packets/frames.\n");
290cabdff1aSopenharmony_ci    }
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_ci    /* if we are draining and there are no more capture buffers queued in the driver we are done */
293cabdff1aSopenharmony_ci    if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) {
294cabdff1aSopenharmony_ci        for (i = 0; i < ctx->num_buffers; i++) {
295cabdff1aSopenharmony_ci            /* capture buffer initialization happens during decode hence
296cabdff1aSopenharmony_ci             * detection happens at runtime
297cabdff1aSopenharmony_ci             */
298cabdff1aSopenharmony_ci            if (!ctx->buffers)
299cabdff1aSopenharmony_ci                break;
300cabdff1aSopenharmony_ci
301cabdff1aSopenharmony_ci            if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER)
302cabdff1aSopenharmony_ci                goto start;
303cabdff1aSopenharmony_ci        }
304cabdff1aSopenharmony_ci        ctx->done = 1;
305cabdff1aSopenharmony_ci        return NULL;
306cabdff1aSopenharmony_ci    }
307cabdff1aSopenharmony_ci
308cabdff1aSopenharmony_cistart:
309cabdff1aSopenharmony_ci    if (V4L2_TYPE_IS_OUTPUT(ctx->type))
310cabdff1aSopenharmony_ci        pfd.events =  POLLOUT | POLLWRNORM;
311cabdff1aSopenharmony_ci    else {
312cabdff1aSopenharmony_ci        /* no need to listen to requests for more input while draining */
313cabdff1aSopenharmony_ci        if (ctx_to_m2mctx(ctx)->draining)
314cabdff1aSopenharmony_ci            pfd.events =  POLLIN | POLLRDNORM | POLLPRI;
315cabdff1aSopenharmony_ci    }
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci    for (;;) {
318cabdff1aSopenharmony_ci        ret = poll(&pfd, 1, timeout);
319cabdff1aSopenharmony_ci        if (ret > 0)
320cabdff1aSopenharmony_ci            break;
321cabdff1aSopenharmony_ci        if (errno == EINTR)
322cabdff1aSopenharmony_ci            continue;
323cabdff1aSopenharmony_ci        return NULL;
324cabdff1aSopenharmony_ci    }
325cabdff1aSopenharmony_ci
326cabdff1aSopenharmony_ci    /* 0. handle errors */
327cabdff1aSopenharmony_ci    if (pfd.revents & POLLERR) {
328cabdff1aSopenharmony_ci        /* if we are trying to get free buffers but none have been queued yet
329cabdff1aSopenharmony_ci           no need to raise a warning */
330cabdff1aSopenharmony_ci        if (timeout == 0) {
331cabdff1aSopenharmony_ci            for (i = 0; i < ctx->num_buffers; i++) {
332cabdff1aSopenharmony_ci                if (ctx->buffers[i].status != V4L2BUF_AVAILABLE)
333cabdff1aSopenharmony_ci                    av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name);
334cabdff1aSopenharmony_ci            }
335cabdff1aSopenharmony_ci        }
336cabdff1aSopenharmony_ci        else
337cabdff1aSopenharmony_ci            av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name);
338cabdff1aSopenharmony_ci
339cabdff1aSopenharmony_ci        return NULL;
340cabdff1aSopenharmony_ci    }
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci    /* 1. handle resolution changes */
343cabdff1aSopenharmony_ci    if (pfd.revents & POLLPRI) {
344cabdff1aSopenharmony_ci        ret = v4l2_handle_event(ctx);
345cabdff1aSopenharmony_ci        if (ret < 0) {
346cabdff1aSopenharmony_ci            /* if re-init failed, abort */
347cabdff1aSopenharmony_ci            ctx->done = 1;
348cabdff1aSopenharmony_ci            return NULL;
349cabdff1aSopenharmony_ci        }
350cabdff1aSopenharmony_ci        if (ret) {
351cabdff1aSopenharmony_ci            /* if re-init was successful drop the buffer (if there was one)
352cabdff1aSopenharmony_ci             * since we had to reconfigure capture (unmap all buffers)
353cabdff1aSopenharmony_ci             */
354cabdff1aSopenharmony_ci            return NULL;
355cabdff1aSopenharmony_ci        }
356cabdff1aSopenharmony_ci    }
357cabdff1aSopenharmony_ci
358cabdff1aSopenharmony_ci    /* 2. dequeue the buffer */
359cabdff1aSopenharmony_ci    if (pfd.revents & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM)) {
360cabdff1aSopenharmony_ci
361cabdff1aSopenharmony_ci        if (!V4L2_TYPE_IS_OUTPUT(ctx->type)) {
362cabdff1aSopenharmony_ci            /* there is a capture buffer ready */
363cabdff1aSopenharmony_ci            if (pfd.revents & (POLLIN | POLLRDNORM))
364cabdff1aSopenharmony_ci                goto dequeue;
365cabdff1aSopenharmony_ci
366cabdff1aSopenharmony_ci            /* the driver is ready to accept more input; instead of waiting for the capture
367cabdff1aSopenharmony_ci             * buffer to complete we return NULL so input can proceed (we are single threaded)
368cabdff1aSopenharmony_ci             */
369cabdff1aSopenharmony_ci            if (pfd.revents & (POLLOUT | POLLWRNORM))
370cabdff1aSopenharmony_ci                return NULL;
371cabdff1aSopenharmony_ci        }
372cabdff1aSopenharmony_ci
373cabdff1aSopenharmony_cidequeue:
374cabdff1aSopenharmony_ci        memset(&buf, 0, sizeof(buf));
375cabdff1aSopenharmony_ci        buf.memory = V4L2_MEMORY_MMAP;
376cabdff1aSopenharmony_ci        buf.type = ctx->type;
377cabdff1aSopenharmony_ci        if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
378cabdff1aSopenharmony_ci            memset(planes, 0, sizeof(planes));
379cabdff1aSopenharmony_ci            buf.length = VIDEO_MAX_PLANES;
380cabdff1aSopenharmony_ci            buf.m.planes = planes;
381cabdff1aSopenharmony_ci        }
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci        ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf);
384cabdff1aSopenharmony_ci        if (ret) {
385cabdff1aSopenharmony_ci            if (errno != EAGAIN) {
386cabdff1aSopenharmony_ci                ctx->done = 1;
387cabdff1aSopenharmony_ci                if (errno != EPIPE)
388cabdff1aSopenharmony_ci                    av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n",
389cabdff1aSopenharmony_ci                        ctx->name, av_err2str(AVERROR(errno)));
390cabdff1aSopenharmony_ci            }
391cabdff1aSopenharmony_ci            return NULL;
392cabdff1aSopenharmony_ci        }
393cabdff1aSopenharmony_ci
394cabdff1aSopenharmony_ci        if (ctx_to_m2mctx(ctx)->draining && !V4L2_TYPE_IS_OUTPUT(ctx->type)) {
395cabdff1aSopenharmony_ci            int bytesused = V4L2_TYPE_IS_MULTIPLANAR(buf.type) ?
396cabdff1aSopenharmony_ci                            buf.m.planes[0].bytesused : buf.bytesused;
397cabdff1aSopenharmony_ci            if (bytesused == 0) {
398cabdff1aSopenharmony_ci                ctx->done = 1;
399cabdff1aSopenharmony_ci                return NULL;
400cabdff1aSopenharmony_ci            }
401cabdff1aSopenharmony_ci#ifdef V4L2_BUF_FLAG_LAST
402cabdff1aSopenharmony_ci            if (buf.flags & V4L2_BUF_FLAG_LAST)
403cabdff1aSopenharmony_ci                ctx->done = 1;
404cabdff1aSopenharmony_ci#endif
405cabdff1aSopenharmony_ci        }
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci        avbuf = &ctx->buffers[buf.index];
408cabdff1aSopenharmony_ci        avbuf->status = V4L2BUF_AVAILABLE;
409cabdff1aSopenharmony_ci        avbuf->buf = buf;
410cabdff1aSopenharmony_ci        if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
411cabdff1aSopenharmony_ci            memcpy(avbuf->planes, planes, sizeof(planes));
412cabdff1aSopenharmony_ci            avbuf->buf.m.planes = avbuf->planes;
413cabdff1aSopenharmony_ci        }
414cabdff1aSopenharmony_ci        return avbuf;
415cabdff1aSopenharmony_ci    }
416cabdff1aSopenharmony_ci
417cabdff1aSopenharmony_ci    return NULL;
418cabdff1aSopenharmony_ci}
419cabdff1aSopenharmony_ci
420cabdff1aSopenharmony_cistatic V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx)
421cabdff1aSopenharmony_ci{
422cabdff1aSopenharmony_ci    int timeout = 0; /* return when no more buffers to dequeue */
423cabdff1aSopenharmony_ci    int i;
424cabdff1aSopenharmony_ci
425cabdff1aSopenharmony_ci    /* get back as many output buffers as possible */
426cabdff1aSopenharmony_ci    if (V4L2_TYPE_IS_OUTPUT(ctx->type)) {
427cabdff1aSopenharmony_ci          do {
428cabdff1aSopenharmony_ci          } while (v4l2_dequeue_v4l2buf(ctx, timeout));
429cabdff1aSopenharmony_ci    }
430cabdff1aSopenharmony_ci
431cabdff1aSopenharmony_ci    for (i = 0; i < ctx->num_buffers; i++) {
432cabdff1aSopenharmony_ci        if (ctx->buffers[i].status == V4L2BUF_AVAILABLE)
433cabdff1aSopenharmony_ci            return &ctx->buffers[i];
434cabdff1aSopenharmony_ci    }
435cabdff1aSopenharmony_ci
436cabdff1aSopenharmony_ci    return NULL;
437cabdff1aSopenharmony_ci}
438cabdff1aSopenharmony_ci
439cabdff1aSopenharmony_cistatic int v4l2_release_buffers(V4L2Context* ctx)
440cabdff1aSopenharmony_ci{
441cabdff1aSopenharmony_ci    struct v4l2_requestbuffers req = {
442cabdff1aSopenharmony_ci        .memory = V4L2_MEMORY_MMAP,
443cabdff1aSopenharmony_ci        .type = ctx->type,
444cabdff1aSopenharmony_ci        .count = 0, /* 0 -> unmaps buffers from the driver */
445cabdff1aSopenharmony_ci    };
446cabdff1aSopenharmony_ci    int i, j;
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci    for (i = 0; i < ctx->num_buffers; i++) {
449cabdff1aSopenharmony_ci        V4L2Buffer *buffer = &ctx->buffers[i];
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci        for (j = 0; j < buffer->num_planes; j++) {
452cabdff1aSopenharmony_ci            struct V4L2Plane_info *p = &buffer->plane_info[j];
453cabdff1aSopenharmony_ci            if (p->mm_addr && p->length)
454cabdff1aSopenharmony_ci                if (munmap(p->mm_addr, p->length) < 0)
455cabdff1aSopenharmony_ci                    av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno)));
456cabdff1aSopenharmony_ci        }
457cabdff1aSopenharmony_ci    }
458cabdff1aSopenharmony_ci
459cabdff1aSopenharmony_ci    return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req);
460cabdff1aSopenharmony_ci}
461cabdff1aSopenharmony_ci
462cabdff1aSopenharmony_cistatic inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt)
463cabdff1aSopenharmony_ci{
464cabdff1aSopenharmony_ci    struct v4l2_format *fmt = &ctx->format;
465cabdff1aSopenharmony_ci    uint32_t v4l2_fmt;
466cabdff1aSopenharmony_ci    int ret;
467cabdff1aSopenharmony_ci
468cabdff1aSopenharmony_ci    v4l2_fmt = ff_v4l2_format_avfmt_to_v4l2(pixfmt);
469cabdff1aSopenharmony_ci    if (!v4l2_fmt)
470cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
471cabdff1aSopenharmony_ci
472cabdff1aSopenharmony_ci    if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type))
473cabdff1aSopenharmony_ci        fmt->fmt.pix_mp.pixelformat = v4l2_fmt;
474cabdff1aSopenharmony_ci    else
475cabdff1aSopenharmony_ci        fmt->fmt.pix.pixelformat = v4l2_fmt;
476cabdff1aSopenharmony_ci
477cabdff1aSopenharmony_ci    fmt->type = ctx->type;
478cabdff1aSopenharmony_ci
479cabdff1aSopenharmony_ci    ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_TRY_FMT, fmt);
480cabdff1aSopenharmony_ci    if (ret)
481cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
482cabdff1aSopenharmony_ci
483cabdff1aSopenharmony_ci    return 0;
484cabdff1aSopenharmony_ci}
485cabdff1aSopenharmony_ci
486cabdff1aSopenharmony_cistatic int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
487cabdff1aSopenharmony_ci{
488cabdff1aSopenharmony_ci    enum AVPixelFormat pixfmt = ctx->av_pix_fmt;
489cabdff1aSopenharmony_ci    struct v4l2_fmtdesc fdesc;
490cabdff1aSopenharmony_ci    int ret;
491cabdff1aSopenharmony_ci
492cabdff1aSopenharmony_ci    memset(&fdesc, 0, sizeof(fdesc));
493cabdff1aSopenharmony_ci    fdesc.type = ctx->type;
494cabdff1aSopenharmony_ci
495cabdff1aSopenharmony_ci    if (pixfmt != AV_PIX_FMT_NONE) {
496cabdff1aSopenharmony_ci        ret = v4l2_try_raw_format(ctx, pixfmt);
497cabdff1aSopenharmony_ci        if (!ret)
498cabdff1aSopenharmony_ci            return 0;
499cabdff1aSopenharmony_ci    }
500cabdff1aSopenharmony_ci
501cabdff1aSopenharmony_ci    for (;;) {
502cabdff1aSopenharmony_ci        ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENUM_FMT, &fdesc);
503cabdff1aSopenharmony_ci        if (ret)
504cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
505cabdff1aSopenharmony_ci
506cabdff1aSopenharmony_ci        pixfmt = ff_v4l2_format_v4l2_to_avfmt(fdesc.pixelformat, AV_CODEC_ID_RAWVIDEO);
507cabdff1aSopenharmony_ci        ret = v4l2_try_raw_format(ctx, pixfmt);
508cabdff1aSopenharmony_ci        if (ret){
509cabdff1aSopenharmony_ci            fdesc.index++;
510cabdff1aSopenharmony_ci            continue;
511cabdff1aSopenharmony_ci        }
512cabdff1aSopenharmony_ci
513cabdff1aSopenharmony_ci        *p = pixfmt;
514cabdff1aSopenharmony_ci
515cabdff1aSopenharmony_ci        return 0;
516cabdff1aSopenharmony_ci    }
517cabdff1aSopenharmony_ci
518cabdff1aSopenharmony_ci    return AVERROR(EINVAL);
519cabdff1aSopenharmony_ci}
520cabdff1aSopenharmony_ci
521cabdff1aSopenharmony_cistatic int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p)
522cabdff1aSopenharmony_ci{
523cabdff1aSopenharmony_ci    struct v4l2_fmtdesc fdesc;
524cabdff1aSopenharmony_ci    uint32_t v4l2_fmt;
525cabdff1aSopenharmony_ci    int ret;
526cabdff1aSopenharmony_ci
527cabdff1aSopenharmony_ci    /* translate to a valid v4l2 format */
528cabdff1aSopenharmony_ci    v4l2_fmt = ff_v4l2_format_avcodec_to_v4l2(ctx->av_codec_id);
529cabdff1aSopenharmony_ci    if (!v4l2_fmt)
530cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
531cabdff1aSopenharmony_ci
532cabdff1aSopenharmony_ci    /* check if the driver supports this format */
533cabdff1aSopenharmony_ci    memset(&fdesc, 0, sizeof(fdesc));
534cabdff1aSopenharmony_ci    fdesc.type = ctx->type;
535cabdff1aSopenharmony_ci
536cabdff1aSopenharmony_ci    for (;;) {
537cabdff1aSopenharmony_ci        ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_ENUM_FMT, &fdesc);
538cabdff1aSopenharmony_ci        if (ret)
539cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
540cabdff1aSopenharmony_ci
541cabdff1aSopenharmony_ci        if (fdesc.pixelformat == v4l2_fmt)
542cabdff1aSopenharmony_ci            break;
543cabdff1aSopenharmony_ci
544cabdff1aSopenharmony_ci        fdesc.index++;
545cabdff1aSopenharmony_ci    }
546cabdff1aSopenharmony_ci
547cabdff1aSopenharmony_ci    *p = v4l2_fmt;
548cabdff1aSopenharmony_ci
549cabdff1aSopenharmony_ci    return 0;
550cabdff1aSopenharmony_ci}
551cabdff1aSopenharmony_ci
552cabdff1aSopenharmony_ci /*****************************************************************************
553cabdff1aSopenharmony_ci  *
554cabdff1aSopenharmony_ci  *             V4L2 Context Interface
555cabdff1aSopenharmony_ci  *
556cabdff1aSopenharmony_ci  *****************************************************************************/
557cabdff1aSopenharmony_ci
558cabdff1aSopenharmony_ciint ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd)
559cabdff1aSopenharmony_ci{
560cabdff1aSopenharmony_ci    int type = ctx->type;
561cabdff1aSopenharmony_ci    int ret;
562cabdff1aSopenharmony_ci
563cabdff1aSopenharmony_ci    ret = ioctl(ctx_to_m2mctx(ctx)->fd, cmd, &type);
564cabdff1aSopenharmony_ci    if (ret < 0)
565cabdff1aSopenharmony_ci        return AVERROR(errno);
566cabdff1aSopenharmony_ci
567cabdff1aSopenharmony_ci    ctx->streamon = (cmd == VIDIOC_STREAMON);
568cabdff1aSopenharmony_ci
569cabdff1aSopenharmony_ci    return 0;
570cabdff1aSopenharmony_ci}
571cabdff1aSopenharmony_ci
572cabdff1aSopenharmony_ciint ff_v4l2_context_enqueue_frame(V4L2Context* ctx, const AVFrame* frame)
573cabdff1aSopenharmony_ci{
574cabdff1aSopenharmony_ci    V4L2m2mContext *s = ctx_to_m2mctx(ctx);
575cabdff1aSopenharmony_ci    V4L2Buffer* avbuf;
576cabdff1aSopenharmony_ci    int ret;
577cabdff1aSopenharmony_ci
578cabdff1aSopenharmony_ci    if (!frame) {
579cabdff1aSopenharmony_ci        ret = v4l2_stop_encode(ctx);
580cabdff1aSopenharmony_ci        if (ret)
581cabdff1aSopenharmony_ci            av_log(logger(ctx), AV_LOG_ERROR, "%s stop_encode\n", ctx->name);
582cabdff1aSopenharmony_ci        s->draining= 1;
583cabdff1aSopenharmony_ci        return 0;
584cabdff1aSopenharmony_ci    }
585cabdff1aSopenharmony_ci
586cabdff1aSopenharmony_ci    avbuf = v4l2_getfree_v4l2buf(ctx);
587cabdff1aSopenharmony_ci    if (!avbuf)
588cabdff1aSopenharmony_ci        return AVERROR(EAGAIN);
589cabdff1aSopenharmony_ci
590cabdff1aSopenharmony_ci    ret = ff_v4l2_buffer_avframe_to_buf(frame, avbuf);
591cabdff1aSopenharmony_ci    if (ret)
592cabdff1aSopenharmony_ci        return ret;
593cabdff1aSopenharmony_ci
594cabdff1aSopenharmony_ci    return ff_v4l2_buffer_enqueue(avbuf);
595cabdff1aSopenharmony_ci}
596cabdff1aSopenharmony_ci
597cabdff1aSopenharmony_ciint ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt)
598cabdff1aSopenharmony_ci{
599cabdff1aSopenharmony_ci    V4L2m2mContext *s = ctx_to_m2mctx(ctx);
600cabdff1aSopenharmony_ci    V4L2Buffer* avbuf;
601cabdff1aSopenharmony_ci    int ret;
602cabdff1aSopenharmony_ci
603cabdff1aSopenharmony_ci    if (!pkt->size) {
604cabdff1aSopenharmony_ci        ret = v4l2_stop_decode(ctx);
605cabdff1aSopenharmony_ci        if (ret)
606cabdff1aSopenharmony_ci            av_log(logger(ctx), AV_LOG_ERROR, "%s stop_decode\n", ctx->name);
607cabdff1aSopenharmony_ci        s->draining = 1;
608cabdff1aSopenharmony_ci        return 0;
609cabdff1aSopenharmony_ci    }
610cabdff1aSopenharmony_ci
611cabdff1aSopenharmony_ci    avbuf = v4l2_getfree_v4l2buf(ctx);
612cabdff1aSopenharmony_ci    if (!avbuf)
613cabdff1aSopenharmony_ci        return AVERROR(EAGAIN);
614cabdff1aSopenharmony_ci
615cabdff1aSopenharmony_ci    ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf);
616cabdff1aSopenharmony_ci    if (ret)
617cabdff1aSopenharmony_ci        return ret;
618cabdff1aSopenharmony_ci
619cabdff1aSopenharmony_ci    return ff_v4l2_buffer_enqueue(avbuf);
620cabdff1aSopenharmony_ci}
621cabdff1aSopenharmony_ci
622cabdff1aSopenharmony_ciint ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout)
623cabdff1aSopenharmony_ci{
624cabdff1aSopenharmony_ci    V4L2Buffer *avbuf;
625cabdff1aSopenharmony_ci
626cabdff1aSopenharmony_ci    /*
627cabdff1aSopenharmony_ci     * timeout=-1 blocks until:
628cabdff1aSopenharmony_ci     *  1. decoded frame available
629cabdff1aSopenharmony_ci     *  2. an input buffer is ready to be dequeued
630cabdff1aSopenharmony_ci     */
631cabdff1aSopenharmony_ci    avbuf = v4l2_dequeue_v4l2buf(ctx, timeout);
632cabdff1aSopenharmony_ci    if (!avbuf) {
633cabdff1aSopenharmony_ci        if (ctx->done)
634cabdff1aSopenharmony_ci            return AVERROR_EOF;
635cabdff1aSopenharmony_ci
636cabdff1aSopenharmony_ci        return AVERROR(EAGAIN);
637cabdff1aSopenharmony_ci    }
638cabdff1aSopenharmony_ci
639cabdff1aSopenharmony_ci    return ff_v4l2_buffer_buf_to_avframe(frame, avbuf);
640cabdff1aSopenharmony_ci}
641cabdff1aSopenharmony_ci
642cabdff1aSopenharmony_ciint ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt)
643cabdff1aSopenharmony_ci{
644cabdff1aSopenharmony_ci    V4L2Buffer *avbuf;
645cabdff1aSopenharmony_ci
646cabdff1aSopenharmony_ci    /*
647cabdff1aSopenharmony_ci     * blocks until:
648cabdff1aSopenharmony_ci     *  1. encoded packet available
649cabdff1aSopenharmony_ci     *  2. an input buffer ready to be dequeued
650cabdff1aSopenharmony_ci     */
651cabdff1aSopenharmony_ci    avbuf = v4l2_dequeue_v4l2buf(ctx, -1);
652cabdff1aSopenharmony_ci    if (!avbuf) {
653cabdff1aSopenharmony_ci        if (ctx->done)
654cabdff1aSopenharmony_ci            return AVERROR_EOF;
655cabdff1aSopenharmony_ci
656cabdff1aSopenharmony_ci        return AVERROR(EAGAIN);
657cabdff1aSopenharmony_ci    }
658cabdff1aSopenharmony_ci
659cabdff1aSopenharmony_ci    return ff_v4l2_buffer_buf_to_avpkt(pkt, avbuf);
660cabdff1aSopenharmony_ci}
661cabdff1aSopenharmony_ci
662cabdff1aSopenharmony_ciint ff_v4l2_context_get_format(V4L2Context* ctx, int probe)
663cabdff1aSopenharmony_ci{
664cabdff1aSopenharmony_ci    struct v4l2_format_update fmt = { 0 };
665cabdff1aSopenharmony_ci    int ret;
666cabdff1aSopenharmony_ci
667cabdff1aSopenharmony_ci    if  (ctx->av_codec_id == AV_CODEC_ID_RAWVIDEO) {
668cabdff1aSopenharmony_ci        ret = v4l2_get_raw_format(ctx, &fmt.av_fmt);
669cabdff1aSopenharmony_ci        if (ret)
670cabdff1aSopenharmony_ci            return ret;
671cabdff1aSopenharmony_ci
672cabdff1aSopenharmony_ci        fmt.update_avfmt = !probe;
673cabdff1aSopenharmony_ci        v4l2_save_to_context(ctx, &fmt);
674cabdff1aSopenharmony_ci
675cabdff1aSopenharmony_ci        /* format has been tried already */
676cabdff1aSopenharmony_ci        return ret;
677cabdff1aSopenharmony_ci    }
678cabdff1aSopenharmony_ci
679cabdff1aSopenharmony_ci    ret = v4l2_get_coded_format(ctx, &fmt.v4l2_fmt);
680cabdff1aSopenharmony_ci    if (ret)
681cabdff1aSopenharmony_ci        return ret;
682cabdff1aSopenharmony_ci
683cabdff1aSopenharmony_ci    fmt.update_v4l2 = 1;
684cabdff1aSopenharmony_ci    v4l2_save_to_context(ctx, &fmt);
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci    return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_TRY_FMT, &ctx->format);
687cabdff1aSopenharmony_ci}
688cabdff1aSopenharmony_ci
689cabdff1aSopenharmony_ciint ff_v4l2_context_set_format(V4L2Context* ctx)
690cabdff1aSopenharmony_ci{
691cabdff1aSopenharmony_ci    return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_S_FMT, &ctx->format);
692cabdff1aSopenharmony_ci}
693cabdff1aSopenharmony_ci
694cabdff1aSopenharmony_civoid ff_v4l2_context_release(V4L2Context* ctx)
695cabdff1aSopenharmony_ci{
696cabdff1aSopenharmony_ci    int ret;
697cabdff1aSopenharmony_ci
698cabdff1aSopenharmony_ci    if (!ctx->buffers)
699cabdff1aSopenharmony_ci        return;
700cabdff1aSopenharmony_ci
701cabdff1aSopenharmony_ci    ret = v4l2_release_buffers(ctx);
702cabdff1aSopenharmony_ci    if (ret)
703cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_WARNING, "V4L2 failed to unmap the %s buffers\n", ctx->name);
704cabdff1aSopenharmony_ci
705cabdff1aSopenharmony_ci    av_freep(&ctx->buffers);
706cabdff1aSopenharmony_ci}
707cabdff1aSopenharmony_ci
708cabdff1aSopenharmony_ciint ff_v4l2_context_init(V4L2Context* ctx)
709cabdff1aSopenharmony_ci{
710cabdff1aSopenharmony_ci    V4L2m2mContext *s = ctx_to_m2mctx(ctx);
711cabdff1aSopenharmony_ci    struct v4l2_requestbuffers req;
712cabdff1aSopenharmony_ci    int ret, i;
713cabdff1aSopenharmony_ci
714cabdff1aSopenharmony_ci    if (!v4l2_type_supported(ctx)) {
715cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "type %i not supported\n", ctx->type);
716cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
717cabdff1aSopenharmony_ci    }
718cabdff1aSopenharmony_ci
719cabdff1aSopenharmony_ci    ret = ioctl(s->fd, VIDIOC_G_FMT, &ctx->format);
720cabdff1aSopenharmony_ci    if (ret)
721cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_G_FMT failed\n", ctx->name);
722cabdff1aSopenharmony_ci
723cabdff1aSopenharmony_ci    memset(&req, 0, sizeof(req));
724cabdff1aSopenharmony_ci    req.count = ctx->num_buffers;
725cabdff1aSopenharmony_ci    req.memory = V4L2_MEMORY_MMAP;
726cabdff1aSopenharmony_ci    req.type = ctx->type;
727cabdff1aSopenharmony_ci    ret = ioctl(s->fd, VIDIOC_REQBUFS, &req);
728cabdff1aSopenharmony_ci    if (ret < 0) {
729cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_REQBUFS failed: %s\n", ctx->name, strerror(errno));
730cabdff1aSopenharmony_ci        return AVERROR(errno);
731cabdff1aSopenharmony_ci    }
732cabdff1aSopenharmony_ci
733cabdff1aSopenharmony_ci    ctx->num_buffers = req.count;
734cabdff1aSopenharmony_ci    ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer));
735cabdff1aSopenharmony_ci    if (!ctx->buffers) {
736cabdff1aSopenharmony_ci        av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name);
737cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
738cabdff1aSopenharmony_ci    }
739cabdff1aSopenharmony_ci
740cabdff1aSopenharmony_ci    for (i = 0; i < req.count; i++) {
741cabdff1aSopenharmony_ci        ctx->buffers[i].context = ctx;
742cabdff1aSopenharmony_ci        ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i);
743cabdff1aSopenharmony_ci        if (ret < 0) {
744cabdff1aSopenharmony_ci            av_log(logger(ctx), AV_LOG_ERROR, "%s buffer[%d] initialization (%s)\n", ctx->name, i, av_err2str(ret));
745cabdff1aSopenharmony_ci            goto error;
746cabdff1aSopenharmony_ci        }
747cabdff1aSopenharmony_ci    }
748cabdff1aSopenharmony_ci
749cabdff1aSopenharmony_ci    av_log(logger(ctx), AV_LOG_DEBUG, "%s: %s %02d buffers initialized: %04ux%04u, sizeimage %08u, bytesperline %08u\n", ctx->name,
750cabdff1aSopenharmony_ci        V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? av_fourcc2str(ctx->format.fmt.pix_mp.pixelformat) : av_fourcc2str(ctx->format.fmt.pix.pixelformat),
751cabdff1aSopenharmony_ci        req.count,
752cabdff1aSopenharmony_ci        v4l2_get_width(&ctx->format),
753cabdff1aSopenharmony_ci        v4l2_get_height(&ctx->format),
754cabdff1aSopenharmony_ci        V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage : ctx->format.fmt.pix.sizeimage,
755cabdff1aSopenharmony_ci        V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline);
756cabdff1aSopenharmony_ci
757cabdff1aSopenharmony_ci    return 0;
758cabdff1aSopenharmony_ci
759cabdff1aSopenharmony_cierror:
760cabdff1aSopenharmony_ci    v4l2_release_buffers(ctx);
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_ci    av_freep(&ctx->buffers);
763cabdff1aSopenharmony_ci
764cabdff1aSopenharmony_ci    return ret;
765cabdff1aSopenharmony_ci}
766