1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * V4L2 buffer 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 "libavutil/pixdesc.h" 32cabdff1aSopenharmony_ci#include "v4l2_context.h" 33cabdff1aSopenharmony_ci#include "v4l2_buffers.h" 34cabdff1aSopenharmony_ci#include "v4l2_m2m.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci#define USEC_PER_SEC 1000000 37cabdff1aSopenharmony_cistatic AVRational v4l2_timebase = { 1, USEC_PER_SEC }; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_cistatic inline V4L2m2mContext *buf_to_m2mctx(V4L2Buffer *buf) 40cabdff1aSopenharmony_ci{ 41cabdff1aSopenharmony_ci return V4L2_TYPE_IS_OUTPUT(buf->context->type) ? 42cabdff1aSopenharmony_ci container_of(buf->context, V4L2m2mContext, output) : 43cabdff1aSopenharmony_ci container_of(buf->context, V4L2m2mContext, capture); 44cabdff1aSopenharmony_ci} 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_cistatic inline AVCodecContext *logger(V4L2Buffer *buf) 47cabdff1aSopenharmony_ci{ 48cabdff1aSopenharmony_ci return buf_to_m2mctx(buf)->avctx; 49cabdff1aSopenharmony_ci} 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_cistatic inline AVRational v4l2_get_timebase(V4L2Buffer *avbuf) 52cabdff1aSopenharmony_ci{ 53cabdff1aSopenharmony_ci V4L2m2mContext *s = buf_to_m2mctx(avbuf); 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_ci if (s->avctx->pkt_timebase.num) 56cabdff1aSopenharmony_ci return s->avctx->pkt_timebase; 57cabdff1aSopenharmony_ci return s->avctx->time_base; 58cabdff1aSopenharmony_ci} 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_cistatic inline void v4l2_set_pts(V4L2Buffer *out, int64_t pts) 61cabdff1aSopenharmony_ci{ 62cabdff1aSopenharmony_ci int64_t v4l2_pts; 63cabdff1aSopenharmony_ci 64cabdff1aSopenharmony_ci if (pts == AV_NOPTS_VALUE) 65cabdff1aSopenharmony_ci pts = 0; 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci /* convert pts to v4l2 timebase */ 68cabdff1aSopenharmony_ci v4l2_pts = av_rescale_q(pts, v4l2_get_timebase(out), v4l2_timebase); 69cabdff1aSopenharmony_ci out->buf.timestamp.tv_usec = v4l2_pts % USEC_PER_SEC; 70cabdff1aSopenharmony_ci out->buf.timestamp.tv_sec = v4l2_pts / USEC_PER_SEC; 71cabdff1aSopenharmony_ci} 72cabdff1aSopenharmony_ci 73cabdff1aSopenharmony_cistatic inline int64_t v4l2_get_pts(V4L2Buffer *avbuf) 74cabdff1aSopenharmony_ci{ 75cabdff1aSopenharmony_ci int64_t v4l2_pts; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci /* convert pts back to encoder timebase */ 78cabdff1aSopenharmony_ci v4l2_pts = (int64_t)avbuf->buf.timestamp.tv_sec * USEC_PER_SEC + 79cabdff1aSopenharmony_ci avbuf->buf.timestamp.tv_usec; 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_ci return av_rescale_q(v4l2_pts, v4l2_timebase, v4l2_get_timebase(avbuf)); 82cabdff1aSopenharmony_ci} 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_cistatic enum AVColorPrimaries v4l2_get_color_primaries(V4L2Buffer *buf) 85cabdff1aSopenharmony_ci{ 86cabdff1aSopenharmony_ci enum v4l2_ycbcr_encoding ycbcr; 87cabdff1aSopenharmony_ci enum v4l2_colorspace cs; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 90cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.colorspace : 91cabdff1aSopenharmony_ci buf->context->format.fmt.pix.colorspace; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 94cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.ycbcr_enc: 95cabdff1aSopenharmony_ci buf->context->format.fmt.pix.ycbcr_enc; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci switch(ycbcr) { 98cabdff1aSopenharmony_ci case V4L2_YCBCR_ENC_XV709: 99cabdff1aSopenharmony_ci case V4L2_YCBCR_ENC_709: return AVCOL_PRI_BT709; 100cabdff1aSopenharmony_ci case V4L2_YCBCR_ENC_XV601: 101cabdff1aSopenharmony_ci case V4L2_YCBCR_ENC_601:return AVCOL_PRI_BT470M; 102cabdff1aSopenharmony_ci default: 103cabdff1aSopenharmony_ci break; 104cabdff1aSopenharmony_ci } 105cabdff1aSopenharmony_ci 106cabdff1aSopenharmony_ci switch(cs) { 107cabdff1aSopenharmony_ci case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_PRI_BT470BG; 108cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SMPTE170M: return AVCOL_PRI_SMPTE170M; 109cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SMPTE240M: return AVCOL_PRI_SMPTE240M; 110cabdff1aSopenharmony_ci case V4L2_COLORSPACE_BT2020: return AVCOL_PRI_BT2020; 111cabdff1aSopenharmony_ci default: 112cabdff1aSopenharmony_ci break; 113cabdff1aSopenharmony_ci } 114cabdff1aSopenharmony_ci 115cabdff1aSopenharmony_ci return AVCOL_PRI_UNSPECIFIED; 116cabdff1aSopenharmony_ci} 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_cistatic enum AVColorRange v4l2_get_color_range(V4L2Buffer *buf) 119cabdff1aSopenharmony_ci{ 120cabdff1aSopenharmony_ci enum v4l2_quantization qt; 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci qt = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 123cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.quantization : 124cabdff1aSopenharmony_ci buf->context->format.fmt.pix.quantization; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci switch (qt) { 127cabdff1aSopenharmony_ci case V4L2_QUANTIZATION_LIM_RANGE: return AVCOL_RANGE_MPEG; 128cabdff1aSopenharmony_ci case V4L2_QUANTIZATION_FULL_RANGE: return AVCOL_RANGE_JPEG; 129cabdff1aSopenharmony_ci default: 130cabdff1aSopenharmony_ci break; 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci return AVCOL_RANGE_UNSPECIFIED; 134cabdff1aSopenharmony_ci} 135cabdff1aSopenharmony_ci 136cabdff1aSopenharmony_cistatic enum AVColorSpace v4l2_get_color_space(V4L2Buffer *buf) 137cabdff1aSopenharmony_ci{ 138cabdff1aSopenharmony_ci enum v4l2_ycbcr_encoding ycbcr; 139cabdff1aSopenharmony_ci enum v4l2_colorspace cs; 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 142cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.colorspace : 143cabdff1aSopenharmony_ci buf->context->format.fmt.pix.colorspace; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 146cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.ycbcr_enc: 147cabdff1aSopenharmony_ci buf->context->format.fmt.pix.ycbcr_enc; 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_ci switch(cs) { 150cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SRGB: return AVCOL_SPC_RGB; 151cabdff1aSopenharmony_ci case V4L2_COLORSPACE_REC709: return AVCOL_SPC_BT709; 152cabdff1aSopenharmony_ci case V4L2_COLORSPACE_470_SYSTEM_M: return AVCOL_SPC_FCC; 153cabdff1aSopenharmony_ci case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_SPC_BT470BG; 154cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SMPTE170M: return AVCOL_SPC_SMPTE170M; 155cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SMPTE240M: return AVCOL_SPC_SMPTE240M; 156cabdff1aSopenharmony_ci case V4L2_COLORSPACE_BT2020: 157cabdff1aSopenharmony_ci if (ycbcr == V4L2_YCBCR_ENC_BT2020_CONST_LUM) 158cabdff1aSopenharmony_ci return AVCOL_SPC_BT2020_CL; 159cabdff1aSopenharmony_ci else 160cabdff1aSopenharmony_ci return AVCOL_SPC_BT2020_NCL; 161cabdff1aSopenharmony_ci default: 162cabdff1aSopenharmony_ci break; 163cabdff1aSopenharmony_ci } 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci return AVCOL_SPC_UNSPECIFIED; 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_cistatic enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) 169cabdff1aSopenharmony_ci{ 170cabdff1aSopenharmony_ci enum v4l2_ycbcr_encoding ycbcr; 171cabdff1aSopenharmony_ci enum v4l2_xfer_func xfer; 172cabdff1aSopenharmony_ci enum v4l2_colorspace cs; 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci cs = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 175cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.colorspace : 176cabdff1aSopenharmony_ci buf->context->format.fmt.pix.colorspace; 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci ycbcr = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 179cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.ycbcr_enc: 180cabdff1aSopenharmony_ci buf->context->format.fmt.pix.ycbcr_enc; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci xfer = V4L2_TYPE_IS_MULTIPLANAR(buf->buf.type) ? 183cabdff1aSopenharmony_ci buf->context->format.fmt.pix_mp.xfer_func: 184cabdff1aSopenharmony_ci buf->context->format.fmt.pix.xfer_func; 185cabdff1aSopenharmony_ci 186cabdff1aSopenharmony_ci switch (xfer) { 187cabdff1aSopenharmony_ci case V4L2_XFER_FUNC_709: return AVCOL_TRC_BT709; 188cabdff1aSopenharmony_ci case V4L2_XFER_FUNC_SRGB: return AVCOL_TRC_IEC61966_2_1; 189cabdff1aSopenharmony_ci default: 190cabdff1aSopenharmony_ci break; 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci switch (cs) { 194cabdff1aSopenharmony_ci case V4L2_COLORSPACE_470_SYSTEM_M: return AVCOL_TRC_GAMMA22; 195cabdff1aSopenharmony_ci case V4L2_COLORSPACE_470_SYSTEM_BG: return AVCOL_TRC_GAMMA28; 196cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SMPTE170M: return AVCOL_TRC_SMPTE170M; 197cabdff1aSopenharmony_ci case V4L2_COLORSPACE_SMPTE240M: return AVCOL_TRC_SMPTE240M; 198cabdff1aSopenharmony_ci default: 199cabdff1aSopenharmony_ci break; 200cabdff1aSopenharmony_ci } 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci switch (ycbcr) { 203cabdff1aSopenharmony_ci case V4L2_YCBCR_ENC_XV709: 204cabdff1aSopenharmony_ci case V4L2_YCBCR_ENC_XV601: return AVCOL_TRC_BT1361_ECG; 205cabdff1aSopenharmony_ci default: 206cabdff1aSopenharmony_ci break; 207cabdff1aSopenharmony_ci } 208cabdff1aSopenharmony_ci 209cabdff1aSopenharmony_ci return AVCOL_TRC_UNSPECIFIED; 210cabdff1aSopenharmony_ci} 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_cistatic void v4l2_free_buffer(void *opaque, uint8_t *unused) 213cabdff1aSopenharmony_ci{ 214cabdff1aSopenharmony_ci V4L2Buffer* avbuf = opaque; 215cabdff1aSopenharmony_ci V4L2m2mContext *s = buf_to_m2mctx(avbuf); 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci if (atomic_fetch_sub(&avbuf->context_refcount, 1) == 1) { 218cabdff1aSopenharmony_ci atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel); 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci if (s->reinit) { 221cabdff1aSopenharmony_ci if (!atomic_load(&s->refcount)) 222cabdff1aSopenharmony_ci sem_post(&s->refsync); 223cabdff1aSopenharmony_ci } else { 224cabdff1aSopenharmony_ci if (s->draining && V4L2_TYPE_IS_OUTPUT(avbuf->context->type)) { 225cabdff1aSopenharmony_ci /* no need to queue more buffers to the driver */ 226cabdff1aSopenharmony_ci avbuf->status = V4L2BUF_AVAILABLE; 227cabdff1aSopenharmony_ci } 228cabdff1aSopenharmony_ci else if (avbuf->context->streamon) 229cabdff1aSopenharmony_ci ff_v4l2_buffer_enqueue(avbuf); 230cabdff1aSopenharmony_ci } 231cabdff1aSopenharmony_ci 232cabdff1aSopenharmony_ci av_buffer_unref(&avbuf->context_ref); 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci} 235cabdff1aSopenharmony_ci 236cabdff1aSopenharmony_cistatic int v4l2_buf_increase_ref(V4L2Buffer *in) 237cabdff1aSopenharmony_ci{ 238cabdff1aSopenharmony_ci V4L2m2mContext *s = buf_to_m2mctx(in); 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ci if (in->context_ref) 241cabdff1aSopenharmony_ci atomic_fetch_add(&in->context_refcount, 1); 242cabdff1aSopenharmony_ci else { 243cabdff1aSopenharmony_ci in->context_ref = av_buffer_ref(s->self_ref); 244cabdff1aSopenharmony_ci if (!in->context_ref) 245cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci in->context_refcount = 1; 248cabdff1aSopenharmony_ci } 249cabdff1aSopenharmony_ci 250cabdff1aSopenharmony_ci in->status = V4L2BUF_RET_USER; 251cabdff1aSopenharmony_ci atomic_fetch_add_explicit(&s->refcount, 1, memory_order_relaxed); 252cabdff1aSopenharmony_ci 253cabdff1aSopenharmony_ci return 0; 254cabdff1aSopenharmony_ci} 255cabdff1aSopenharmony_ci 256cabdff1aSopenharmony_cistatic int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) 257cabdff1aSopenharmony_ci{ 258cabdff1aSopenharmony_ci int ret; 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci if (plane >= in->num_planes) 261cabdff1aSopenharmony_ci return AVERROR(EINVAL); 262cabdff1aSopenharmony_ci 263cabdff1aSopenharmony_ci /* even though most encoders return 0 in data_offset encoding vp8 does require this value */ 264cabdff1aSopenharmony_ci *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset, 265cabdff1aSopenharmony_ci in->plane_info[plane].length, v4l2_free_buffer, in, 0); 266cabdff1aSopenharmony_ci if (!*buf) 267cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 268cabdff1aSopenharmony_ci 269cabdff1aSopenharmony_ci ret = v4l2_buf_increase_ref(in); 270cabdff1aSopenharmony_ci if (ret) 271cabdff1aSopenharmony_ci av_buffer_unref(buf); 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci return ret; 274cabdff1aSopenharmony_ci} 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_cistatic int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, int offset) 277cabdff1aSopenharmony_ci{ 278cabdff1aSopenharmony_ci unsigned int bytesused, length; 279cabdff1aSopenharmony_ci 280cabdff1aSopenharmony_ci if (plane >= out->num_planes) 281cabdff1aSopenharmony_ci return AVERROR(EINVAL); 282cabdff1aSopenharmony_ci 283cabdff1aSopenharmony_ci length = out->plane_info[plane].length; 284cabdff1aSopenharmony_ci bytesused = FFMIN(size+offset, length); 285cabdff1aSopenharmony_ci 286cabdff1aSopenharmony_ci memcpy((uint8_t*)out->plane_info[plane].mm_addr+offset, data, FFMIN(size, length-offset)); 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) { 289cabdff1aSopenharmony_ci out->planes[plane].bytesused = bytesused; 290cabdff1aSopenharmony_ci out->planes[plane].length = length; 291cabdff1aSopenharmony_ci } else { 292cabdff1aSopenharmony_ci out->buf.bytesused = bytesused; 293cabdff1aSopenharmony_ci out->buf.length = length; 294cabdff1aSopenharmony_ci } 295cabdff1aSopenharmony_ci 296cabdff1aSopenharmony_ci return 0; 297cabdff1aSopenharmony_ci} 298cabdff1aSopenharmony_ci 299cabdff1aSopenharmony_cistatic int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf) 300cabdff1aSopenharmony_ci{ 301cabdff1aSopenharmony_ci int i, ret; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci frame->format = avbuf->context->av_pix_fmt; 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci for (i = 0; i < avbuf->num_planes; i++) { 306cabdff1aSopenharmony_ci ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); 307cabdff1aSopenharmony_ci if (ret) 308cabdff1aSopenharmony_ci return ret; 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ci frame->linesize[i] = avbuf->plane_info[i].bytesperline; 311cabdff1aSopenharmony_ci frame->data[i] = frame->buf[i]->data; 312cabdff1aSopenharmony_ci } 313cabdff1aSopenharmony_ci 314cabdff1aSopenharmony_ci /* fixup special cases */ 315cabdff1aSopenharmony_ci switch (avbuf->context->av_pix_fmt) { 316cabdff1aSopenharmony_ci case AV_PIX_FMT_NV12: 317cabdff1aSopenharmony_ci case AV_PIX_FMT_NV21: 318cabdff1aSopenharmony_ci if (avbuf->num_planes > 1) 319cabdff1aSopenharmony_ci break; 320cabdff1aSopenharmony_ci frame->linesize[1] = avbuf->plane_info[0].bytesperline; 321cabdff1aSopenharmony_ci frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height; 322cabdff1aSopenharmony_ci break; 323cabdff1aSopenharmony_ci 324cabdff1aSopenharmony_ci case AV_PIX_FMT_YUV420P: 325cabdff1aSopenharmony_ci if (avbuf->num_planes > 1) 326cabdff1aSopenharmony_ci break; 327cabdff1aSopenharmony_ci frame->linesize[1] = avbuf->plane_info[0].bytesperline >> 1; 328cabdff1aSopenharmony_ci frame->linesize[2] = avbuf->plane_info[0].bytesperline >> 1; 329cabdff1aSopenharmony_ci frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height; 330cabdff1aSopenharmony_ci frame->data[2] = frame->data[1] + ((avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height) >> 2); 331cabdff1aSopenharmony_ci break; 332cabdff1aSopenharmony_ci 333cabdff1aSopenharmony_ci default: 334cabdff1aSopenharmony_ci break; 335cabdff1aSopenharmony_ci } 336cabdff1aSopenharmony_ci 337cabdff1aSopenharmony_ci return 0; 338cabdff1aSopenharmony_ci} 339cabdff1aSopenharmony_ci 340cabdff1aSopenharmony_cistatic int v4l2_buffer_swframe_to_buf(const AVFrame *frame, V4L2Buffer *out) 341cabdff1aSopenharmony_ci{ 342cabdff1aSopenharmony_ci int i, ret; 343cabdff1aSopenharmony_ci struct v4l2_format fmt = out->context->format; 344cabdff1aSopenharmony_ci int pixel_format = V4L2_TYPE_IS_MULTIPLANAR(fmt.type) ? 345cabdff1aSopenharmony_ci fmt.fmt.pix_mp.pixelformat : fmt.fmt.pix.pixelformat; 346cabdff1aSopenharmony_ci int height = V4L2_TYPE_IS_MULTIPLANAR(fmt.type) ? 347cabdff1aSopenharmony_ci fmt.fmt.pix_mp.height : fmt.fmt.pix.height; 348cabdff1aSopenharmony_ci int is_planar_format = 0; 349cabdff1aSopenharmony_ci 350cabdff1aSopenharmony_ci switch (pixel_format) { 351cabdff1aSopenharmony_ci case V4L2_PIX_FMT_YUV420M: 352cabdff1aSopenharmony_ci case V4L2_PIX_FMT_YVU420M: 353cabdff1aSopenharmony_ci#ifdef V4L2_PIX_FMT_YUV422M 354cabdff1aSopenharmony_ci case V4L2_PIX_FMT_YUV422M: 355cabdff1aSopenharmony_ci#endif 356cabdff1aSopenharmony_ci#ifdef V4L2_PIX_FMT_YVU422M 357cabdff1aSopenharmony_ci case V4L2_PIX_FMT_YVU422M: 358cabdff1aSopenharmony_ci#endif 359cabdff1aSopenharmony_ci#ifdef V4L2_PIX_FMT_YUV444M 360cabdff1aSopenharmony_ci case V4L2_PIX_FMT_YUV444M: 361cabdff1aSopenharmony_ci#endif 362cabdff1aSopenharmony_ci#ifdef V4L2_PIX_FMT_YVU444M 363cabdff1aSopenharmony_ci case V4L2_PIX_FMT_YVU444M: 364cabdff1aSopenharmony_ci#endif 365cabdff1aSopenharmony_ci case V4L2_PIX_FMT_NV12M: 366cabdff1aSopenharmony_ci case V4L2_PIX_FMT_NV21M: 367cabdff1aSopenharmony_ci case V4L2_PIX_FMT_NV12MT_16X16: 368cabdff1aSopenharmony_ci case V4L2_PIX_FMT_NV12MT: 369cabdff1aSopenharmony_ci case V4L2_PIX_FMT_NV16M: 370cabdff1aSopenharmony_ci case V4L2_PIX_FMT_NV61M: 371cabdff1aSopenharmony_ci is_planar_format = 1; 372cabdff1aSopenharmony_ci } 373cabdff1aSopenharmony_ci 374cabdff1aSopenharmony_ci if (!is_planar_format) { 375cabdff1aSopenharmony_ci const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); 376cabdff1aSopenharmony_ci int planes_nb = 0; 377cabdff1aSopenharmony_ci int offset = 0; 378cabdff1aSopenharmony_ci 379cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_components; i++) 380cabdff1aSopenharmony_ci planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1); 381cabdff1aSopenharmony_ci 382cabdff1aSopenharmony_ci for (i = 0; i < planes_nb; i++) { 383cabdff1aSopenharmony_ci int size, h = height; 384cabdff1aSopenharmony_ci if (i == 1 || i == 2) { 385cabdff1aSopenharmony_ci h = AV_CEIL_RSHIFT(h, desc->log2_chroma_h); 386cabdff1aSopenharmony_ci } 387cabdff1aSopenharmony_ci size = frame->linesize[i] * h; 388cabdff1aSopenharmony_ci ret = v4l2_bufref_to_buf(out, 0, frame->data[i], size, offset); 389cabdff1aSopenharmony_ci if (ret) 390cabdff1aSopenharmony_ci return ret; 391cabdff1aSopenharmony_ci offset += size; 392cabdff1aSopenharmony_ci } 393cabdff1aSopenharmony_ci return 0; 394cabdff1aSopenharmony_ci } 395cabdff1aSopenharmony_ci 396cabdff1aSopenharmony_ci for (i = 0; i < out->num_planes; i++) { 397cabdff1aSopenharmony_ci ret = v4l2_bufref_to_buf(out, i, frame->buf[i]->data, frame->buf[i]->size, 0); 398cabdff1aSopenharmony_ci if (ret) 399cabdff1aSopenharmony_ci return ret; 400cabdff1aSopenharmony_ci } 401cabdff1aSopenharmony_ci 402cabdff1aSopenharmony_ci return 0; 403cabdff1aSopenharmony_ci} 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_ci/****************************************************************************** 406cabdff1aSopenharmony_ci * 407cabdff1aSopenharmony_ci * V4L2Buffer interface 408cabdff1aSopenharmony_ci * 409cabdff1aSopenharmony_ci ******************************************************************************/ 410cabdff1aSopenharmony_ci 411cabdff1aSopenharmony_ciint ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer *out) 412cabdff1aSopenharmony_ci{ 413cabdff1aSopenharmony_ci v4l2_set_pts(out, frame->pts); 414cabdff1aSopenharmony_ci 415cabdff1aSopenharmony_ci return v4l2_buffer_swframe_to_buf(frame, out); 416cabdff1aSopenharmony_ci} 417cabdff1aSopenharmony_ci 418cabdff1aSopenharmony_ciint ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) 419cabdff1aSopenharmony_ci{ 420cabdff1aSopenharmony_ci int ret; 421cabdff1aSopenharmony_ci 422cabdff1aSopenharmony_ci av_frame_unref(frame); 423cabdff1aSopenharmony_ci 424cabdff1aSopenharmony_ci /* 1. get references to the actual data */ 425cabdff1aSopenharmony_ci ret = v4l2_buffer_buf_to_swframe(frame, avbuf); 426cabdff1aSopenharmony_ci if (ret) 427cabdff1aSopenharmony_ci return ret; 428cabdff1aSopenharmony_ci 429cabdff1aSopenharmony_ci /* 2. get frame information */ 430cabdff1aSopenharmony_ci frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME); 431cabdff1aSopenharmony_ci frame->color_primaries = v4l2_get_color_primaries(avbuf); 432cabdff1aSopenharmony_ci frame->colorspace = v4l2_get_color_space(avbuf); 433cabdff1aSopenharmony_ci frame->color_range = v4l2_get_color_range(avbuf); 434cabdff1aSopenharmony_ci frame->color_trc = v4l2_get_color_trc(avbuf); 435cabdff1aSopenharmony_ci frame->pts = v4l2_get_pts(avbuf); 436cabdff1aSopenharmony_ci frame->pkt_dts = AV_NOPTS_VALUE; 437cabdff1aSopenharmony_ci 438cabdff1aSopenharmony_ci /* these values are updated also during re-init in v4l2_process_driver_event */ 439cabdff1aSopenharmony_ci frame->height = avbuf->context->height; 440cabdff1aSopenharmony_ci frame->width = avbuf->context->width; 441cabdff1aSopenharmony_ci frame->sample_aspect_ratio = avbuf->context->sample_aspect_ratio; 442cabdff1aSopenharmony_ci 443cabdff1aSopenharmony_ci /* 3. report errors upstream */ 444cabdff1aSopenharmony_ci if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) { 445cabdff1aSopenharmony_ci av_log(logger(avbuf), AV_LOG_ERROR, "%s: driver decode error\n", avbuf->context->name); 446cabdff1aSopenharmony_ci frame->decode_error_flags |= FF_DECODE_ERROR_INVALID_BITSTREAM; 447cabdff1aSopenharmony_ci } 448cabdff1aSopenharmony_ci 449cabdff1aSopenharmony_ci return 0; 450cabdff1aSopenharmony_ci} 451cabdff1aSopenharmony_ci 452cabdff1aSopenharmony_ciint ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *avbuf) 453cabdff1aSopenharmony_ci{ 454cabdff1aSopenharmony_ci int ret; 455cabdff1aSopenharmony_ci 456cabdff1aSopenharmony_ci av_packet_unref(pkt); 457cabdff1aSopenharmony_ci ret = v4l2_buf_to_bufref(avbuf, 0, &pkt->buf); 458cabdff1aSopenharmony_ci if (ret) 459cabdff1aSopenharmony_ci return ret; 460cabdff1aSopenharmony_ci 461cabdff1aSopenharmony_ci pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused; 462cabdff1aSopenharmony_ci pkt->data = pkt->buf->data; 463cabdff1aSopenharmony_ci 464cabdff1aSopenharmony_ci if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME) 465cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 466cabdff1aSopenharmony_ci 467cabdff1aSopenharmony_ci if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) { 468cabdff1aSopenharmony_ci av_log(logger(avbuf), AV_LOG_ERROR, "%s driver encode error\n", avbuf->context->name); 469cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_CORRUPT; 470cabdff1aSopenharmony_ci } 471cabdff1aSopenharmony_ci 472cabdff1aSopenharmony_ci pkt->dts = pkt->pts = v4l2_get_pts(avbuf); 473cabdff1aSopenharmony_ci 474cabdff1aSopenharmony_ci return 0; 475cabdff1aSopenharmony_ci} 476cabdff1aSopenharmony_ci 477cabdff1aSopenharmony_ciint ff_v4l2_buffer_avpkt_to_buf(const AVPacket *pkt, V4L2Buffer *out) 478cabdff1aSopenharmony_ci{ 479cabdff1aSopenharmony_ci int ret; 480cabdff1aSopenharmony_ci 481cabdff1aSopenharmony_ci ret = v4l2_bufref_to_buf(out, 0, pkt->data, pkt->size, 0); 482cabdff1aSopenharmony_ci if (ret) 483cabdff1aSopenharmony_ci return ret; 484cabdff1aSopenharmony_ci 485cabdff1aSopenharmony_ci v4l2_set_pts(out, pkt->pts); 486cabdff1aSopenharmony_ci 487cabdff1aSopenharmony_ci if (pkt->flags & AV_PKT_FLAG_KEY) 488cabdff1aSopenharmony_ci out->flags = V4L2_BUF_FLAG_KEYFRAME; 489cabdff1aSopenharmony_ci 490cabdff1aSopenharmony_ci return 0; 491cabdff1aSopenharmony_ci} 492cabdff1aSopenharmony_ci 493cabdff1aSopenharmony_ciint ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) 494cabdff1aSopenharmony_ci{ 495cabdff1aSopenharmony_ci V4L2Context *ctx = avbuf->context; 496cabdff1aSopenharmony_ci int ret, i; 497cabdff1aSopenharmony_ci 498cabdff1aSopenharmony_ci avbuf->buf.memory = V4L2_MEMORY_MMAP; 499cabdff1aSopenharmony_ci avbuf->buf.type = ctx->type; 500cabdff1aSopenharmony_ci avbuf->buf.index = index; 501cabdff1aSopenharmony_ci 502cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { 503cabdff1aSopenharmony_ci avbuf->buf.length = VIDEO_MAX_PLANES; 504cabdff1aSopenharmony_ci avbuf->buf.m.planes = avbuf->planes; 505cabdff1aSopenharmony_ci } 506cabdff1aSopenharmony_ci 507cabdff1aSopenharmony_ci ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QUERYBUF, &avbuf->buf); 508cabdff1aSopenharmony_ci if (ret < 0) 509cabdff1aSopenharmony_ci return AVERROR(errno); 510cabdff1aSopenharmony_ci 511cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { 512cabdff1aSopenharmony_ci avbuf->num_planes = 0; 513cabdff1aSopenharmony_ci /* in MP, the V4L2 API states that buf.length means num_planes */ 514cabdff1aSopenharmony_ci for (i = 0; i < avbuf->buf.length; i++) { 515cabdff1aSopenharmony_ci if (avbuf->buf.m.planes[i].length) 516cabdff1aSopenharmony_ci avbuf->num_planes++; 517cabdff1aSopenharmony_ci } 518cabdff1aSopenharmony_ci } else 519cabdff1aSopenharmony_ci avbuf->num_planes = 1; 520cabdff1aSopenharmony_ci 521cabdff1aSopenharmony_ci for (i = 0; i < avbuf->num_planes; i++) { 522cabdff1aSopenharmony_ci 523cabdff1aSopenharmony_ci avbuf->plane_info[i].bytesperline = V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? 524cabdff1aSopenharmony_ci ctx->format.fmt.pix_mp.plane_fmt[i].bytesperline : 525cabdff1aSopenharmony_ci ctx->format.fmt.pix.bytesperline; 526cabdff1aSopenharmony_ci 527cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { 528cabdff1aSopenharmony_ci avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length; 529cabdff1aSopenharmony_ci avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length, 530cabdff1aSopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED, 531cabdff1aSopenharmony_ci buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset); 532cabdff1aSopenharmony_ci } else { 533cabdff1aSopenharmony_ci avbuf->plane_info[i].length = avbuf->buf.length; 534cabdff1aSopenharmony_ci avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length, 535cabdff1aSopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED, 536cabdff1aSopenharmony_ci buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset); 537cabdff1aSopenharmony_ci } 538cabdff1aSopenharmony_ci 539cabdff1aSopenharmony_ci if (avbuf->plane_info[i].mm_addr == MAP_FAILED) 540cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 541cabdff1aSopenharmony_ci } 542cabdff1aSopenharmony_ci 543cabdff1aSopenharmony_ci avbuf->status = V4L2BUF_AVAILABLE; 544cabdff1aSopenharmony_ci 545cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(ctx->type)) 546cabdff1aSopenharmony_ci return 0; 547cabdff1aSopenharmony_ci 548cabdff1aSopenharmony_ci if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { 549cabdff1aSopenharmony_ci avbuf->buf.m.planes = avbuf->planes; 550cabdff1aSopenharmony_ci avbuf->buf.length = avbuf->num_planes; 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_ci } else { 553cabdff1aSopenharmony_ci avbuf->buf.bytesused = avbuf->planes[0].bytesused; 554cabdff1aSopenharmony_ci avbuf->buf.length = avbuf->planes[0].length; 555cabdff1aSopenharmony_ci } 556cabdff1aSopenharmony_ci 557cabdff1aSopenharmony_ci return ff_v4l2_buffer_enqueue(avbuf); 558cabdff1aSopenharmony_ci} 559cabdff1aSopenharmony_ci 560cabdff1aSopenharmony_ciint ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf) 561cabdff1aSopenharmony_ci{ 562cabdff1aSopenharmony_ci int ret; 563cabdff1aSopenharmony_ci 564cabdff1aSopenharmony_ci avbuf->buf.flags = avbuf->flags; 565cabdff1aSopenharmony_ci 566cabdff1aSopenharmony_ci ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_QBUF, &avbuf->buf); 567cabdff1aSopenharmony_ci if (ret < 0) 568cabdff1aSopenharmony_ci return AVERROR(errno); 569cabdff1aSopenharmony_ci 570cabdff1aSopenharmony_ci avbuf->status = V4L2BUF_IN_DRIVER; 571cabdff1aSopenharmony_ci 572cabdff1aSopenharmony_ci return 0; 573cabdff1aSopenharmony_ci} 574