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