1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * V4L mem2mem
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 <dirent.h>
29cabdff1aSopenharmony_ci#include <fcntl.h>
30cabdff1aSopenharmony_ci#include "libavcodec/avcodec.h"
31cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
32cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
33cabdff1aSopenharmony_ci#include "libavutil/pixfmt.h"
34cabdff1aSopenharmony_ci#include "v4l2_context.h"
35cabdff1aSopenharmony_ci#include "v4l2_fmt.h"
36cabdff1aSopenharmony_ci#include "v4l2_m2m.h"
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_cistatic inline int v4l2_splane_video(struct v4l2_capability *cap)
39cabdff1aSopenharmony_ci{
40cabdff1aSopenharmony_ci    if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) &&
41cabdff1aSopenharmony_ci        cap->capabilities & V4L2_CAP_STREAMING)
42cabdff1aSopenharmony_ci        return 1;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    if (cap->capabilities & V4L2_CAP_VIDEO_M2M)
45cabdff1aSopenharmony_ci        return 1;
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    return 0;
48cabdff1aSopenharmony_ci}
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_cistatic inline int v4l2_mplane_video(struct v4l2_capability *cap)
51cabdff1aSopenharmony_ci{
52cabdff1aSopenharmony_ci    if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
53cabdff1aSopenharmony_ci        cap->capabilities & V4L2_CAP_STREAMING)
54cabdff1aSopenharmony_ci        return 1;
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci    if (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
57cabdff1aSopenharmony_ci        return 1;
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_ci    return 0;
60cabdff1aSopenharmony_ci}
61cabdff1aSopenharmony_ci
62cabdff1aSopenharmony_cistatic int v4l2_prepare_contexts(V4L2m2mContext *s, int probe)
63cabdff1aSopenharmony_ci{
64cabdff1aSopenharmony_ci    struct v4l2_capability cap;
65cabdff1aSopenharmony_ci    void *log_ctx = s->avctx;
66cabdff1aSopenharmony_ci    int ret;
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    s->capture.done = s->output.done = 0;
69cabdff1aSopenharmony_ci    s->capture.name = "capture";
70cabdff1aSopenharmony_ci    s->output.name = "output";
71cabdff1aSopenharmony_ci    atomic_init(&s->refcount, 0);
72cabdff1aSopenharmony_ci    sem_init(&s->refsync, 0, 0);
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    memset(&cap, 0, sizeof(cap));
75cabdff1aSopenharmony_ci    ret = ioctl(s->fd, VIDIOC_QUERYCAP, &cap);
76cabdff1aSopenharmony_ci    if (ret < 0)
77cabdff1aSopenharmony_ci        return ret;
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_ci    av_log(log_ctx, probe ? AV_LOG_DEBUG : AV_LOG_INFO,
80cabdff1aSopenharmony_ci                     "driver '%s' on card '%s' in %s mode\n", cap.driver, cap.card,
81cabdff1aSopenharmony_ci                     v4l2_mplane_video(&cap) ? "mplane" :
82cabdff1aSopenharmony_ci                     v4l2_splane_video(&cap) ? "splane" : "unknown");
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci    if (v4l2_mplane_video(&cap)) {
85cabdff1aSopenharmony_ci        s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
86cabdff1aSopenharmony_ci        s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
87cabdff1aSopenharmony_ci        return 0;
88cabdff1aSopenharmony_ci    }
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci    if (v4l2_splane_video(&cap)) {
91cabdff1aSopenharmony_ci        s->capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
92cabdff1aSopenharmony_ci        s->output.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
93cabdff1aSopenharmony_ci        return 0;
94cabdff1aSopenharmony_ci    }
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci    return AVERROR(EINVAL);
97cabdff1aSopenharmony_ci}
98cabdff1aSopenharmony_ci
99cabdff1aSopenharmony_cistatic int v4l2_probe_driver(V4L2m2mContext *s)
100cabdff1aSopenharmony_ci{
101cabdff1aSopenharmony_ci    void *log_ctx = s->avctx;
102cabdff1aSopenharmony_ci    int ret;
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
105cabdff1aSopenharmony_ci    if (s->fd < 0)
106cabdff1aSopenharmony_ci        return AVERROR(errno);
107cabdff1aSopenharmony_ci
108cabdff1aSopenharmony_ci    ret = v4l2_prepare_contexts(s, 1);
109cabdff1aSopenharmony_ci    if (ret < 0)
110cabdff1aSopenharmony_ci        goto done;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    ret = ff_v4l2_context_get_format(&s->output, 1);
113cabdff1aSopenharmony_ci    if (ret) {
114cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
115cabdff1aSopenharmony_ci        goto done;
116cabdff1aSopenharmony_ci    }
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    ret = ff_v4l2_context_get_format(&s->capture, 1);
119cabdff1aSopenharmony_ci    if (ret) {
120cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
121cabdff1aSopenharmony_ci        goto done;
122cabdff1aSopenharmony_ci    }
123cabdff1aSopenharmony_ci
124cabdff1aSopenharmony_cidone:
125cabdff1aSopenharmony_ci    if (close(s->fd) < 0) {
126cabdff1aSopenharmony_ci        ret = AVERROR(errno);
127cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
128cabdff1aSopenharmony_ci    }
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ci    s->fd = -1;
131cabdff1aSopenharmony_ci
132cabdff1aSopenharmony_ci    return ret;
133cabdff1aSopenharmony_ci}
134cabdff1aSopenharmony_ci
135cabdff1aSopenharmony_cistatic int v4l2_configure_contexts(V4L2m2mContext *s)
136cabdff1aSopenharmony_ci{
137cabdff1aSopenharmony_ci    void *log_ctx = s->avctx;
138cabdff1aSopenharmony_ci    int ret;
139cabdff1aSopenharmony_ci    struct v4l2_format ofmt, cfmt;
140cabdff1aSopenharmony_ci
141cabdff1aSopenharmony_ci    s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
142cabdff1aSopenharmony_ci    if (s->fd < 0)
143cabdff1aSopenharmony_ci        return AVERROR(errno);
144cabdff1aSopenharmony_ci
145cabdff1aSopenharmony_ci    ret = v4l2_prepare_contexts(s, 0);
146cabdff1aSopenharmony_ci    if (ret < 0)
147cabdff1aSopenharmony_ci        goto error;
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci    ofmt = s->output.format;
150cabdff1aSopenharmony_ci    cfmt = s->capture.format;
151cabdff1aSopenharmony_ci    av_log(log_ctx, AV_LOG_INFO, "requesting formats: output=%s capture=%s\n",
152cabdff1aSopenharmony_ci                                 av_fourcc2str(V4L2_TYPE_IS_MULTIPLANAR(ofmt.type) ?
153cabdff1aSopenharmony_ci                                               ofmt.fmt.pix_mp.pixelformat :
154cabdff1aSopenharmony_ci                                               ofmt.fmt.pix.pixelformat),
155cabdff1aSopenharmony_ci                                 av_fourcc2str(V4L2_TYPE_IS_MULTIPLANAR(cfmt.type) ?
156cabdff1aSopenharmony_ci                                               cfmt.fmt.pix_mp.pixelformat :
157cabdff1aSopenharmony_ci                                               cfmt.fmt.pix.pixelformat));
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    ret = ff_v4l2_context_set_format(&s->output);
160cabdff1aSopenharmony_ci    if (ret) {
161cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "can't set v4l2 output format\n");
162cabdff1aSopenharmony_ci        goto error;
163cabdff1aSopenharmony_ci    }
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_ci    ret = ff_v4l2_context_set_format(&s->capture);
166cabdff1aSopenharmony_ci    if (ret) {
167cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "can't to set v4l2 capture format\n");
168cabdff1aSopenharmony_ci        goto error;
169cabdff1aSopenharmony_ci    }
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci    ret = ff_v4l2_context_init(&s->output);
172cabdff1aSopenharmony_ci    if (ret) {
173cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "no v4l2 output context's buffers\n");
174cabdff1aSopenharmony_ci        goto error;
175cabdff1aSopenharmony_ci    }
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci    /* decoder's buffers need to be updated at a later stage */
178cabdff1aSopenharmony_ci    if (s->avctx && !av_codec_is_decoder(s->avctx->codec)) {
179cabdff1aSopenharmony_ci        ret = ff_v4l2_context_init(&s->capture);
180cabdff1aSopenharmony_ci        if (ret) {
181cabdff1aSopenharmony_ci            av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
182cabdff1aSopenharmony_ci            goto error;
183cabdff1aSopenharmony_ci        }
184cabdff1aSopenharmony_ci    }
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci    return 0;
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_cierror:
189cabdff1aSopenharmony_ci    if (close(s->fd) < 0) {
190cabdff1aSopenharmony_ci        ret = AVERROR(errno);
191cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n",
192cabdff1aSopenharmony_ci            s->devname, av_err2str(AVERROR(errno)));
193cabdff1aSopenharmony_ci    }
194cabdff1aSopenharmony_ci    s->fd = -1;
195cabdff1aSopenharmony_ci
196cabdff1aSopenharmony_ci    return ret;
197cabdff1aSopenharmony_ci}
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci/******************************************************************************
200cabdff1aSopenharmony_ci *
201cabdff1aSopenharmony_ci *                  V4L2 M2M Interface
202cabdff1aSopenharmony_ci *
203cabdff1aSopenharmony_ci ******************************************************************************/
204cabdff1aSopenharmony_ciint ff_v4l2_m2m_codec_reinit(V4L2m2mContext *s)
205cabdff1aSopenharmony_ci{
206cabdff1aSopenharmony_ci    void *log_ctx = s->avctx;
207cabdff1aSopenharmony_ci    int ret;
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    av_log(log_ctx, AV_LOG_DEBUG, "reinit context\n");
210cabdff1aSopenharmony_ci
211cabdff1aSopenharmony_ci    /* 1. streamoff */
212cabdff1aSopenharmony_ci    ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
213cabdff1aSopenharmony_ci    if (ret)
214cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
215cabdff1aSopenharmony_ci
216cabdff1aSopenharmony_ci    /* 2. unmap the capture buffers (v4l2 and ffmpeg):
217cabdff1aSopenharmony_ci     *    we must wait for all references to be released before being allowed
218cabdff1aSopenharmony_ci     *    to queue new buffers.
219cabdff1aSopenharmony_ci     */
220cabdff1aSopenharmony_ci    av_log(log_ctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
221cabdff1aSopenharmony_ci    if (atomic_load(&s->refcount))
222cabdff1aSopenharmony_ci        while(sem_wait(&s->refsync) == -1 && errno == EINTR);
223cabdff1aSopenharmony_ci
224cabdff1aSopenharmony_ci    ff_v4l2_context_release(&s->capture);
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci    /* 3. get the new capture format */
227cabdff1aSopenharmony_ci    ret = ff_v4l2_context_get_format(&s->capture, 0);
228cabdff1aSopenharmony_ci    if (ret) {
229cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "query the new capture format\n");
230cabdff1aSopenharmony_ci        return ret;
231cabdff1aSopenharmony_ci    }
232cabdff1aSopenharmony_ci
233cabdff1aSopenharmony_ci    /* 4. set the capture format */
234cabdff1aSopenharmony_ci    ret = ff_v4l2_context_set_format(&s->capture);
235cabdff1aSopenharmony_ci    if (ret) {
236cabdff1aSopenharmony_ci        av_log(log_ctx, AV_LOG_ERROR, "setting capture format\n");
237cabdff1aSopenharmony_ci        return ret;
238cabdff1aSopenharmony_ci    }
239cabdff1aSopenharmony_ci
240cabdff1aSopenharmony_ci    /* 5. complete reinit */
241cabdff1aSopenharmony_ci    s->draining = 0;
242cabdff1aSopenharmony_ci    s->reinit = 0;
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    return 0;
245cabdff1aSopenharmony_ci}
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_cistatic void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
248cabdff1aSopenharmony_ci{
249cabdff1aSopenharmony_ci    V4L2m2mContext *s = (V4L2m2mContext*)context;
250cabdff1aSopenharmony_ci
251cabdff1aSopenharmony_ci    ff_v4l2_context_release(&s->capture);
252cabdff1aSopenharmony_ci    sem_destroy(&s->refsync);
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci    if (s->fd >= 0)
255cabdff1aSopenharmony_ci        close(s->fd);
256cabdff1aSopenharmony_ci    av_frame_unref(s->frame);
257cabdff1aSopenharmony_ci    av_frame_free(&s->frame);
258cabdff1aSopenharmony_ci    av_packet_unref(&s->buf_pkt);
259cabdff1aSopenharmony_ci
260cabdff1aSopenharmony_ci    av_free(s);
261cabdff1aSopenharmony_ci}
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ciint ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
264cabdff1aSopenharmony_ci{
265cabdff1aSopenharmony_ci    V4L2m2mContext *s = priv->context;
266cabdff1aSopenharmony_ci    int ret;
267cabdff1aSopenharmony_ci
268cabdff1aSopenharmony_ci    if (!s)
269cabdff1aSopenharmony_ci        return 0;
270cabdff1aSopenharmony_ci
271cabdff1aSopenharmony_ci    if (s->fd >= 0) {
272cabdff1aSopenharmony_ci        ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
273cabdff1aSopenharmony_ci        if (ret)
274cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
275cabdff1aSopenharmony_ci
276cabdff1aSopenharmony_ci        ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
277cabdff1aSopenharmony_ci        if (ret)
278cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
279cabdff1aSopenharmony_ci    }
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_ci    ff_v4l2_context_release(&s->output);
282cabdff1aSopenharmony_ci
283cabdff1aSopenharmony_ci    s->self_ref = NULL;
284cabdff1aSopenharmony_ci    av_buffer_unref(&priv->context_ref);
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ci    return 0;
287cabdff1aSopenharmony_ci}
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ciint ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv)
290cabdff1aSopenharmony_ci{
291cabdff1aSopenharmony_ci    int ret = AVERROR(EINVAL);
292cabdff1aSopenharmony_ci    struct dirent *entry;
293cabdff1aSopenharmony_ci    DIR *dirp;
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_ci    V4L2m2mContext *s = priv->context;
296cabdff1aSopenharmony_ci
297cabdff1aSopenharmony_ci    dirp = opendir("/dev");
298cabdff1aSopenharmony_ci    if (!dirp)
299cabdff1aSopenharmony_ci        return AVERROR(errno);
300cabdff1aSopenharmony_ci
301cabdff1aSopenharmony_ci    for (entry = readdir(dirp); entry; entry = readdir(dirp)) {
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ci        if (strncmp(entry->d_name, "video", 5))
304cabdff1aSopenharmony_ci            continue;
305cabdff1aSopenharmony_ci
306cabdff1aSopenharmony_ci        snprintf(s->devname, sizeof(s->devname), "/dev/%s", entry->d_name);
307cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", s->devname);
308cabdff1aSopenharmony_ci        ret = v4l2_probe_driver(s);
309cabdff1aSopenharmony_ci        if (!ret)
310cabdff1aSopenharmony_ci            break;
311cabdff1aSopenharmony_ci    }
312cabdff1aSopenharmony_ci
313cabdff1aSopenharmony_ci    closedir(dirp);
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci    if (ret) {
316cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
317cabdff1aSopenharmony_ci        memset(s->devname, 0, sizeof(s->devname));
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_ci        return ret;
320cabdff1aSopenharmony_ci    }
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci    av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", s->devname);
323cabdff1aSopenharmony_ci
324cabdff1aSopenharmony_ci    return v4l2_configure_contexts(s);
325cabdff1aSopenharmony_ci}
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ciint ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
328cabdff1aSopenharmony_ci{
329cabdff1aSopenharmony_ci    *s = av_mallocz(sizeof(V4L2m2mContext));
330cabdff1aSopenharmony_ci    if (!*s)
331cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
332cabdff1aSopenharmony_ci
333cabdff1aSopenharmony_ci    priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext),
334cabdff1aSopenharmony_ci                                         &v4l2_m2m_destroy_context, NULL, 0);
335cabdff1aSopenharmony_ci    if (!priv->context_ref) {
336cabdff1aSopenharmony_ci        av_freep(s);
337cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
338cabdff1aSopenharmony_ci    }
339cabdff1aSopenharmony_ci
340cabdff1aSopenharmony_ci    /* assign the context */
341cabdff1aSopenharmony_ci    priv->context = *s;
342cabdff1aSopenharmony_ci    (*s)->priv = priv;
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_ci    /* populate it */
345cabdff1aSopenharmony_ci    priv->context->capture.num_buffers = priv->num_capture_buffers;
346cabdff1aSopenharmony_ci    priv->context->output.num_buffers  = priv->num_output_buffers;
347cabdff1aSopenharmony_ci    priv->context->self_ref = priv->context_ref;
348cabdff1aSopenharmony_ci    priv->context->fd = -1;
349cabdff1aSopenharmony_ci
350cabdff1aSopenharmony_ci    priv->context->frame = av_frame_alloc();
351cabdff1aSopenharmony_ci    if (!priv->context->frame) {
352cabdff1aSopenharmony_ci        av_buffer_unref(&priv->context_ref);
353cabdff1aSopenharmony_ci        *s = NULL; /* freed when unreferencing context_ref */
354cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
355cabdff1aSopenharmony_ci    }
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci    return 0;
358cabdff1aSopenharmony_ci}
359