1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * V4L2 mem2mem encoders 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 <search.h> 27cabdff1aSopenharmony_ci#include "encode.h" 28cabdff1aSopenharmony_ci#include "libavcodec/avcodec.h" 29cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h" 30cabdff1aSopenharmony_ci#include "libavutil/pixfmt.h" 31cabdff1aSopenharmony_ci#include "libavutil/opt.h" 32cabdff1aSopenharmony_ci#include "codec_internal.h" 33cabdff1aSopenharmony_ci#include "profiles.h" 34cabdff1aSopenharmony_ci#include "v4l2_context.h" 35cabdff1aSopenharmony_ci#include "v4l2_m2m.h" 36cabdff1aSopenharmony_ci#include "v4l2_fmt.h" 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_ci#define MPEG_CID(x) V4L2_CID_MPEG_VIDEO_##x 39cabdff1aSopenharmony_ci#define MPEG_VIDEO(x) V4L2_MPEG_VIDEO_##x 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_cistatic inline void v4l2_set_timeperframe(V4L2m2mContext *s, unsigned int num, unsigned int den) 42cabdff1aSopenharmony_ci{ 43cabdff1aSopenharmony_ci struct v4l2_streamparm parm = { 0 }; 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_ci parm.type = V4L2_TYPE_IS_MULTIPLANAR(s->output.type) ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT; 46cabdff1aSopenharmony_ci parm.parm.output.timeperframe.denominator = den; 47cabdff1aSopenharmony_ci parm.parm.output.timeperframe.numerator = num; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci if (ioctl(s->fd, VIDIOC_S_PARM, &parm) < 0) 50cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_WARNING, "Failed to set timeperframe"); 51cabdff1aSopenharmony_ci} 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_cistatic inline void v4l2_set_ext_ctrl(V4L2m2mContext *s, unsigned int id, signed int value, const char *name, int log_warning) 54cabdff1aSopenharmony_ci{ 55cabdff1aSopenharmony_ci struct v4l2_ext_controls ctrls = { { 0 } }; 56cabdff1aSopenharmony_ci struct v4l2_ext_control ctrl = { 0 }; 57cabdff1aSopenharmony_ci 58cabdff1aSopenharmony_ci /* set ctrls */ 59cabdff1aSopenharmony_ci ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; 60cabdff1aSopenharmony_ci ctrls.controls = &ctrl; 61cabdff1aSopenharmony_ci ctrls.count = 1; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_ci /* set ctrl*/ 64cabdff1aSopenharmony_ci ctrl.value = value; 65cabdff1aSopenharmony_ci ctrl.id = id; 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci if (ioctl(s->fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0) 68cabdff1aSopenharmony_ci av_log(s->avctx, log_warning || errno != EINVAL ? AV_LOG_WARNING : AV_LOG_DEBUG, 69cabdff1aSopenharmony_ci "Failed to set %s: %s\n", name, strerror(errno)); 70cabdff1aSopenharmony_ci else 71cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_DEBUG, "Encoder: %s = %d\n", name, value); 72cabdff1aSopenharmony_ci} 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_cistatic inline int v4l2_get_ext_ctrl(V4L2m2mContext *s, unsigned int id, signed int *value, const char *name, int log_warning) 75cabdff1aSopenharmony_ci{ 76cabdff1aSopenharmony_ci struct v4l2_ext_controls ctrls = { { 0 } }; 77cabdff1aSopenharmony_ci struct v4l2_ext_control ctrl = { 0 }; 78cabdff1aSopenharmony_ci int ret; 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci /* set ctrls */ 81cabdff1aSopenharmony_ci ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG; 82cabdff1aSopenharmony_ci ctrls.controls = &ctrl; 83cabdff1aSopenharmony_ci ctrls.count = 1; 84cabdff1aSopenharmony_ci 85cabdff1aSopenharmony_ci /* set ctrl*/ 86cabdff1aSopenharmony_ci ctrl.id = id ; 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci ret = ioctl(s->fd, VIDIOC_G_EXT_CTRLS, &ctrls); 89cabdff1aSopenharmony_ci if (ret < 0) { 90cabdff1aSopenharmony_ci av_log(s->avctx, log_warning || errno != EINVAL ? AV_LOG_WARNING : AV_LOG_DEBUG, 91cabdff1aSopenharmony_ci "Failed to get %s\n", name); 92cabdff1aSopenharmony_ci return ret; 93cabdff1aSopenharmony_ci } 94cabdff1aSopenharmony_ci 95cabdff1aSopenharmony_ci *value = ctrl.value; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci return 0; 98cabdff1aSopenharmony_ci} 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_cistatic inline unsigned int v4l2_h264_profile_from_ff(int p) 101cabdff1aSopenharmony_ci{ 102cabdff1aSopenharmony_ci static const struct h264_profile { 103cabdff1aSopenharmony_ci unsigned int ffmpeg_val; 104cabdff1aSopenharmony_ci unsigned int v4l2_val; 105cabdff1aSopenharmony_ci } profile[] = { 106cabdff1aSopenharmony_ci { FF_PROFILE_H264_CONSTRAINED_BASELINE, MPEG_VIDEO(H264_PROFILE_CONSTRAINED_BASELINE) }, 107cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH_444_PREDICTIVE, MPEG_VIDEO(H264_PROFILE_HIGH_444_PREDICTIVE) }, 108cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH_422_INTRA, MPEG_VIDEO(H264_PROFILE_HIGH_422_INTRA) }, 109cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH_444_INTRA, MPEG_VIDEO(H264_PROFILE_HIGH_444_INTRA) }, 110cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH_10_INTRA, MPEG_VIDEO(H264_PROFILE_HIGH_10_INTRA) }, 111cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH_422, MPEG_VIDEO(H264_PROFILE_HIGH_422) }, 112cabdff1aSopenharmony_ci { FF_PROFILE_H264_BASELINE, MPEG_VIDEO(H264_PROFILE_BASELINE) }, 113cabdff1aSopenharmony_ci { FF_PROFILE_H264_EXTENDED, MPEG_VIDEO(H264_PROFILE_EXTENDED) }, 114cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH_10, MPEG_VIDEO(H264_PROFILE_HIGH_10) }, 115cabdff1aSopenharmony_ci { FF_PROFILE_H264_MAIN, MPEG_VIDEO(H264_PROFILE_MAIN) }, 116cabdff1aSopenharmony_ci { FF_PROFILE_H264_HIGH, MPEG_VIDEO(H264_PROFILE_HIGH) }, 117cabdff1aSopenharmony_ci }; 118cabdff1aSopenharmony_ci int i; 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(profile); i++) { 121cabdff1aSopenharmony_ci if (profile[i].ffmpeg_val == p) 122cabdff1aSopenharmony_ci return profile[i].v4l2_val; 123cabdff1aSopenharmony_ci } 124cabdff1aSopenharmony_ci return AVERROR(ENOENT); 125cabdff1aSopenharmony_ci} 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_cistatic inline int v4l2_mpeg4_profile_from_ff(int p) 128cabdff1aSopenharmony_ci{ 129cabdff1aSopenharmony_ci static const struct mpeg4_profile { 130cabdff1aSopenharmony_ci unsigned int ffmpeg_val; 131cabdff1aSopenharmony_ci unsigned int v4l2_val; 132cabdff1aSopenharmony_ci } profile[] = { 133cabdff1aSopenharmony_ci { FF_PROFILE_MPEG4_ADVANCED_CODING, MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY) }, 134cabdff1aSopenharmony_ci { FF_PROFILE_MPEG4_ADVANCED_SIMPLE, MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_SIMPLE) }, 135cabdff1aSopenharmony_ci { FF_PROFILE_MPEG4_SIMPLE_SCALABLE, MPEG_VIDEO(MPEG4_PROFILE_SIMPLE_SCALABLE) }, 136cabdff1aSopenharmony_ci { FF_PROFILE_MPEG4_SIMPLE, MPEG_VIDEO(MPEG4_PROFILE_SIMPLE) }, 137cabdff1aSopenharmony_ci { FF_PROFILE_MPEG4_CORE, MPEG_VIDEO(MPEG4_PROFILE_CORE) }, 138cabdff1aSopenharmony_ci }; 139cabdff1aSopenharmony_ci int i; 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(profile); i++) { 142cabdff1aSopenharmony_ci if (profile[i].ffmpeg_val == p) 143cabdff1aSopenharmony_ci return profile[i].v4l2_val; 144cabdff1aSopenharmony_ci } 145cabdff1aSopenharmony_ci return AVERROR(ENOENT); 146cabdff1aSopenharmony_ci} 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_cistatic int v4l2_check_b_frame_support(V4L2m2mContext *s) 149cabdff1aSopenharmony_ci{ 150cabdff1aSopenharmony_ci if (s->avctx->max_b_frames) 151cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_WARNING, "Encoder does not support b-frames yet\n"); 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(B_FRAMES), 0, "number of B-frames", 0); 154cabdff1aSopenharmony_ci v4l2_get_ext_ctrl(s, MPEG_CID(B_FRAMES), &s->avctx->max_b_frames, "number of B-frames", 0); 155cabdff1aSopenharmony_ci if (s->avctx->max_b_frames == 0) 156cabdff1aSopenharmony_ci return 0; 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci avpriv_report_missing_feature(s->avctx, "DTS/PTS calculation for V4L2 encoding"); 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci return AVERROR_PATCHWELCOME; 161cabdff1aSopenharmony_ci} 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_cistatic inline void v4l2_subscribe_eos_event(V4L2m2mContext *s) 164cabdff1aSopenharmony_ci{ 165cabdff1aSopenharmony_ci struct v4l2_event_subscription sub; 166cabdff1aSopenharmony_ci 167cabdff1aSopenharmony_ci memset(&sub, 0, sizeof(sub)); 168cabdff1aSopenharmony_ci sub.type = V4L2_EVENT_EOS; 169cabdff1aSopenharmony_ci if (ioctl(s->fd, VIDIOC_SUBSCRIBE_EVENT, &sub) < 0) 170cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_WARNING, 171cabdff1aSopenharmony_ci "the v4l2 driver does not support end of stream VIDIOC_SUBSCRIBE_EVENT\n"); 172cabdff1aSopenharmony_ci} 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_cistatic int v4l2_prepare_encoder(V4L2m2mContext *s) 175cabdff1aSopenharmony_ci{ 176cabdff1aSopenharmony_ci AVCodecContext *avctx = s->avctx; 177cabdff1aSopenharmony_ci int qmin_cid, qmax_cid, qmin, qmax; 178cabdff1aSopenharmony_ci int ret, val; 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_ci /** 181cabdff1aSopenharmony_ci * requirements 182cabdff1aSopenharmony_ci */ 183cabdff1aSopenharmony_ci v4l2_subscribe_eos_event(s); 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_ci ret = v4l2_check_b_frame_support(s); 186cabdff1aSopenharmony_ci if (ret) 187cabdff1aSopenharmony_ci return ret; 188cabdff1aSopenharmony_ci 189cabdff1aSopenharmony_ci /** 190cabdff1aSopenharmony_ci * settingss 191cabdff1aSopenharmony_ci */ 192cabdff1aSopenharmony_ci if (avctx->framerate.num || avctx->framerate.den) 193cabdff1aSopenharmony_ci v4l2_set_timeperframe(s, avctx->framerate.den, avctx->framerate.num); 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_ci /* set ext ctrls */ 196cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(HEADER_MODE), MPEG_VIDEO(HEADER_MODE_SEPARATE), "header mode", 0); 197cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(BITRATE) , avctx->bit_rate, "bit rate", 1); 198cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(FRAME_RC_ENABLE), 1, "frame level rate control", 0); 199cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(GOP_SIZE), avctx->gop_size,"gop size", 1); 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_DEBUG, 202cabdff1aSopenharmony_ci "Encoder Context: id (%d), profile (%d), frame rate(%d/%d), number b-frames (%d), " 203cabdff1aSopenharmony_ci "gop size (%d), bit rate (%"PRId64"), qmin (%d), qmax (%d)\n", 204cabdff1aSopenharmony_ci avctx->codec_id, avctx->profile, avctx->framerate.num, avctx->framerate.den, 205cabdff1aSopenharmony_ci avctx->max_b_frames, avctx->gop_size, avctx->bit_rate, avctx->qmin, avctx->qmax); 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci switch (avctx->codec_id) { 208cabdff1aSopenharmony_ci case AV_CODEC_ID_H264: 209cabdff1aSopenharmony_ci if (avctx->profile != FF_PROFILE_UNKNOWN) { 210cabdff1aSopenharmony_ci val = v4l2_h264_profile_from_ff(avctx->profile); 211cabdff1aSopenharmony_ci if (val < 0) 212cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "h264 profile not found\n"); 213cabdff1aSopenharmony_ci else 214cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(H264_PROFILE), val, "h264 profile", 1); 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci qmin_cid = MPEG_CID(H264_MIN_QP); 217cabdff1aSopenharmony_ci qmax_cid = MPEG_CID(H264_MAX_QP); 218cabdff1aSopenharmony_ci qmin = 0; 219cabdff1aSopenharmony_ci qmax = 51; 220cabdff1aSopenharmony_ci break; 221cabdff1aSopenharmony_ci case AV_CODEC_ID_MPEG4: 222cabdff1aSopenharmony_ci if (avctx->profile != FF_PROFILE_UNKNOWN) { 223cabdff1aSopenharmony_ci val = v4l2_mpeg4_profile_from_ff(avctx->profile); 224cabdff1aSopenharmony_ci if (val < 0) 225cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "mpeg4 profile not found\n"); 226cabdff1aSopenharmony_ci else 227cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile", 1); 228cabdff1aSopenharmony_ci } 229cabdff1aSopenharmony_ci qmin_cid = MPEG_CID(MPEG4_MIN_QP); 230cabdff1aSopenharmony_ci qmax_cid = MPEG_CID(MPEG4_MAX_QP); 231cabdff1aSopenharmony_ci if (avctx->flags & AV_CODEC_FLAG_QPEL) 232cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_QPEL), 1, "qpel", 1); 233cabdff1aSopenharmony_ci qmin = 1; 234cabdff1aSopenharmony_ci qmax = 31; 235cabdff1aSopenharmony_ci break; 236cabdff1aSopenharmony_ci case AV_CODEC_ID_H263: 237cabdff1aSopenharmony_ci qmin_cid = MPEG_CID(H263_MIN_QP); 238cabdff1aSopenharmony_ci qmax_cid = MPEG_CID(H263_MAX_QP); 239cabdff1aSopenharmony_ci qmin = 1; 240cabdff1aSopenharmony_ci qmax = 31; 241cabdff1aSopenharmony_ci break; 242cabdff1aSopenharmony_ci case AV_CODEC_ID_VP8: 243cabdff1aSopenharmony_ci qmin_cid = MPEG_CID(VPX_MIN_QP); 244cabdff1aSopenharmony_ci qmax_cid = MPEG_CID(VPX_MAX_QP); 245cabdff1aSopenharmony_ci qmin = 0; 246cabdff1aSopenharmony_ci qmax = 127; 247cabdff1aSopenharmony_ci break; 248cabdff1aSopenharmony_ci case AV_CODEC_ID_VP9: 249cabdff1aSopenharmony_ci qmin_cid = MPEG_CID(VPX_MIN_QP); 250cabdff1aSopenharmony_ci qmax_cid = MPEG_CID(VPX_MAX_QP); 251cabdff1aSopenharmony_ci qmin = 0; 252cabdff1aSopenharmony_ci qmax = 255; 253cabdff1aSopenharmony_ci break; 254cabdff1aSopenharmony_ci default: 255cabdff1aSopenharmony_ci return 0; 256cabdff1aSopenharmony_ci } 257cabdff1aSopenharmony_ci 258cabdff1aSopenharmony_ci if (avctx->qmin >= 0 && avctx->qmax >= 0 && avctx->qmin > avctx->qmax) { 259cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "Invalid qmin:%d qmax:%d. qmin should not " 260cabdff1aSopenharmony_ci "exceed qmax\n", avctx->qmin, avctx->qmax); 261cabdff1aSopenharmony_ci } else { 262cabdff1aSopenharmony_ci qmin = avctx->qmin >= 0 ? avctx->qmin : qmin; 263cabdff1aSopenharmony_ci qmax = avctx->qmax >= 0 ? avctx->qmax : qmax; 264cabdff1aSopenharmony_ci } 265cabdff1aSopenharmony_ci 266cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, qmin_cid, qmin, "minimum video quantizer scale", 267cabdff1aSopenharmony_ci avctx->qmin >= 0); 268cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, qmax_cid, qmax, "maximum video quantizer scale", 269cabdff1aSopenharmony_ci avctx->qmax >= 0); 270cabdff1aSopenharmony_ci 271cabdff1aSopenharmony_ci return 0; 272cabdff1aSopenharmony_ci} 273cabdff1aSopenharmony_ci 274cabdff1aSopenharmony_cistatic int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame) 275cabdff1aSopenharmony_ci{ 276cabdff1aSopenharmony_ci V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; 277cabdff1aSopenharmony_ci V4L2Context *const output = &s->output; 278cabdff1aSopenharmony_ci 279cabdff1aSopenharmony_ci#ifdef V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME 280cabdff1aSopenharmony_ci if (frame && frame->pict_type == AV_PICTURE_TYPE_I) 281cabdff1aSopenharmony_ci v4l2_set_ext_ctrl(s, MPEG_CID(FORCE_KEY_FRAME), 0, "force key frame", 1); 282cabdff1aSopenharmony_ci#endif 283cabdff1aSopenharmony_ci 284cabdff1aSopenharmony_ci return ff_v4l2_context_enqueue_frame(output, frame); 285cabdff1aSopenharmony_ci} 286cabdff1aSopenharmony_ci 287cabdff1aSopenharmony_cistatic int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) 288cabdff1aSopenharmony_ci{ 289cabdff1aSopenharmony_ci V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; 290cabdff1aSopenharmony_ci V4L2Context *const capture = &s->capture; 291cabdff1aSopenharmony_ci V4L2Context *const output = &s->output; 292cabdff1aSopenharmony_ci AVFrame *frame = s->frame; 293cabdff1aSopenharmony_ci int ret; 294cabdff1aSopenharmony_ci 295cabdff1aSopenharmony_ci if (s->draining) 296cabdff1aSopenharmony_ci goto dequeue; 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_ci if (!frame->buf[0]) { 299cabdff1aSopenharmony_ci ret = ff_encode_get_frame(avctx, frame); 300cabdff1aSopenharmony_ci if (ret < 0 && ret != AVERROR_EOF) 301cabdff1aSopenharmony_ci return ret; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci if (ret == AVERROR_EOF) 304cabdff1aSopenharmony_ci frame = NULL; 305cabdff1aSopenharmony_ci } 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci ret = v4l2_send_frame(avctx, frame); 308cabdff1aSopenharmony_ci if (ret != AVERROR(EAGAIN)) 309cabdff1aSopenharmony_ci av_frame_unref(frame); 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci if (ret < 0 && ret != AVERROR(EAGAIN)) 312cabdff1aSopenharmony_ci return ret; 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci if (!output->streamon) { 315cabdff1aSopenharmony_ci ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON); 316cabdff1aSopenharmony_ci if (ret) { 317cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on output context\n"); 318cabdff1aSopenharmony_ci return ret; 319cabdff1aSopenharmony_ci } 320cabdff1aSopenharmony_ci } 321cabdff1aSopenharmony_ci 322cabdff1aSopenharmony_ci if (!capture->streamon) { 323cabdff1aSopenharmony_ci ret = ff_v4l2_context_set_status(capture, VIDIOC_STREAMON); 324cabdff1aSopenharmony_ci if (ret) { 325cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on capture context\n"); 326cabdff1aSopenharmony_ci return ret; 327cabdff1aSopenharmony_ci } 328cabdff1aSopenharmony_ci } 329cabdff1aSopenharmony_ci 330cabdff1aSopenharmony_cidequeue: 331cabdff1aSopenharmony_ci return ff_v4l2_context_dequeue_packet(capture, avpkt); 332cabdff1aSopenharmony_ci} 333cabdff1aSopenharmony_ci 334cabdff1aSopenharmony_cistatic av_cold int v4l2_encode_init(AVCodecContext *avctx) 335cabdff1aSopenharmony_ci{ 336cabdff1aSopenharmony_ci V4L2Context *capture, *output; 337cabdff1aSopenharmony_ci V4L2m2mContext *s; 338cabdff1aSopenharmony_ci V4L2m2mPriv *priv = avctx->priv_data; 339cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt_output; 340cabdff1aSopenharmony_ci uint32_t v4l2_fmt_output; 341cabdff1aSopenharmony_ci int ret; 342cabdff1aSopenharmony_ci 343cabdff1aSopenharmony_ci ret = ff_v4l2_m2m_create_context(priv, &s); 344cabdff1aSopenharmony_ci if (ret < 0) 345cabdff1aSopenharmony_ci return ret; 346cabdff1aSopenharmony_ci 347cabdff1aSopenharmony_ci capture = &s->capture; 348cabdff1aSopenharmony_ci output = &s->output; 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci /* common settings output/capture */ 351cabdff1aSopenharmony_ci output->height = capture->height = avctx->height; 352cabdff1aSopenharmony_ci output->width = capture->width = avctx->width; 353cabdff1aSopenharmony_ci 354cabdff1aSopenharmony_ci /* output context */ 355cabdff1aSopenharmony_ci output->av_codec_id = AV_CODEC_ID_RAWVIDEO; 356cabdff1aSopenharmony_ci output->av_pix_fmt = avctx->pix_fmt; 357cabdff1aSopenharmony_ci 358cabdff1aSopenharmony_ci /* capture context */ 359cabdff1aSopenharmony_ci capture->av_codec_id = avctx->codec_id; 360cabdff1aSopenharmony_ci capture->av_pix_fmt = AV_PIX_FMT_NONE; 361cabdff1aSopenharmony_ci 362cabdff1aSopenharmony_ci s->avctx = avctx; 363cabdff1aSopenharmony_ci ret = ff_v4l2_m2m_codec_init(priv); 364cabdff1aSopenharmony_ci if (ret) { 365cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "can't configure encoder\n"); 366cabdff1aSopenharmony_ci return ret; 367cabdff1aSopenharmony_ci } 368cabdff1aSopenharmony_ci 369cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_MULTIPLANAR(output->type)) 370cabdff1aSopenharmony_ci v4l2_fmt_output = output->format.fmt.pix_mp.pixelformat; 371cabdff1aSopenharmony_ci else 372cabdff1aSopenharmony_ci v4l2_fmt_output = output->format.fmt.pix.pixelformat; 373cabdff1aSopenharmony_ci 374cabdff1aSopenharmony_ci pix_fmt_output = ff_v4l2_format_v4l2_to_avfmt(v4l2_fmt_output, AV_CODEC_ID_RAWVIDEO); 375cabdff1aSopenharmony_ci if (pix_fmt_output != avctx->pix_fmt) { 376cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt_output); 377cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_ERROR, "Encoder requires %s pixel format.\n", desc->name); 378cabdff1aSopenharmony_ci return AVERROR(EINVAL); 379cabdff1aSopenharmony_ci } 380cabdff1aSopenharmony_ci 381cabdff1aSopenharmony_ci return v4l2_prepare_encoder(s); 382cabdff1aSopenharmony_ci} 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_cistatic av_cold int v4l2_encode_close(AVCodecContext *avctx) 385cabdff1aSopenharmony_ci{ 386cabdff1aSopenharmony_ci return ff_v4l2_m2m_codec_end(avctx->priv_data); 387cabdff1aSopenharmony_ci} 388cabdff1aSopenharmony_ci 389cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(V4L2m2mPriv, x) 390cabdff1aSopenharmony_ci#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM 391cabdff1aSopenharmony_ci 392cabdff1aSopenharmony_ci#define V4L_M2M_CAPTURE_OPTS \ 393cabdff1aSopenharmony_ci V4L_M2M_DEFAULT_OPTS,\ 394cabdff1aSopenharmony_ci { "num_capture_buffers", "Number of buffers in the capture context", \ 395cabdff1aSopenharmony_ci OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS } 396cabdff1aSopenharmony_ci 397cabdff1aSopenharmony_cistatic const AVOption mpeg4_options[] = { 398cabdff1aSopenharmony_ci V4L_M2M_CAPTURE_OPTS, 399cabdff1aSopenharmony_ci FF_MPEG4_PROFILE_OPTS 400cabdff1aSopenharmony_ci { NULL }, 401cabdff1aSopenharmony_ci}; 402cabdff1aSopenharmony_ci 403cabdff1aSopenharmony_cistatic const AVOption options[] = { 404cabdff1aSopenharmony_ci V4L_M2M_CAPTURE_OPTS, 405cabdff1aSopenharmony_ci { NULL }, 406cabdff1aSopenharmony_ci}; 407cabdff1aSopenharmony_ci 408cabdff1aSopenharmony_cistatic const FFCodecDefault v4l2_m2m_defaults[] = { 409cabdff1aSopenharmony_ci { "qmin", "-1" }, 410cabdff1aSopenharmony_ci { "qmax", "-1" }, 411cabdff1aSopenharmony_ci { NULL }, 412cabdff1aSopenharmony_ci}; 413cabdff1aSopenharmony_ci 414cabdff1aSopenharmony_ci#define M2MENC_CLASS(NAME, OPTIONS_NAME) \ 415cabdff1aSopenharmony_ci static const AVClass v4l2_m2m_ ## NAME ## _enc_class = { \ 416cabdff1aSopenharmony_ci .class_name = #NAME "_v4l2m2m_encoder", \ 417cabdff1aSopenharmony_ci .item_name = av_default_item_name, \ 418cabdff1aSopenharmony_ci .option = OPTIONS_NAME, \ 419cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, \ 420cabdff1aSopenharmony_ci }; 421cabdff1aSopenharmony_ci 422cabdff1aSopenharmony_ci#define M2MENC(NAME, LONGNAME, OPTIONS_NAME, CODEC) \ 423cabdff1aSopenharmony_ci M2MENC_CLASS(NAME, OPTIONS_NAME) \ 424cabdff1aSopenharmony_ci const FFCodec ff_ ## NAME ## _v4l2m2m_encoder = { \ 425cabdff1aSopenharmony_ci .p.name = #NAME "_v4l2m2m" , \ 426cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"), \ 427cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, \ 428cabdff1aSopenharmony_ci .p.id = CODEC , \ 429cabdff1aSopenharmony_ci .priv_data_size = sizeof(V4L2m2mPriv), \ 430cabdff1aSopenharmony_ci .p.priv_class = &v4l2_m2m_ ## NAME ##_enc_class, \ 431cabdff1aSopenharmony_ci .init = v4l2_encode_init, \ 432cabdff1aSopenharmony_ci FF_CODEC_RECEIVE_PACKET_CB(v4l2_receive_packet), \ 433cabdff1aSopenharmony_ci .close = v4l2_encode_close, \ 434cabdff1aSopenharmony_ci .defaults = v4l2_m2m_defaults, \ 435cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ 436cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, \ 437cabdff1aSopenharmony_ci .p.wrapper_name = "v4l2m2m", \ 438cabdff1aSopenharmony_ci } 439cabdff1aSopenharmony_ci 440cabdff1aSopenharmony_ciM2MENC(mpeg4,"MPEG4", mpeg4_options, AV_CODEC_ID_MPEG4); 441cabdff1aSopenharmony_ciM2MENC(h263, "H.263", options, AV_CODEC_ID_H263); 442cabdff1aSopenharmony_ciM2MENC(h264, "H.264", options, AV_CODEC_ID_H264); 443cabdff1aSopenharmony_ciM2MENC(hevc, "HEVC", options, AV_CODEC_ID_HEVC); 444cabdff1aSopenharmony_ciM2MENC(vp8, "VP8", options, AV_CODEC_ID_VP8); 445