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