]>
Commit | Line | Data |
---|---|---|
80105e83 JP |
1 | From 5e154b0357829007566930846f880b9f5fb404d9 Mon Sep 17 00:00:00 2001 |
2 | From: Jonas Karlman <jonas@kwiboo.se> | |
3 | Date: Mon, 3 Dec 2018 23:48:04 +0100 | |
4 | Subject: [PATCH] avutil: add av_buffer_pool_flush() | |
5 | ||
6 | Used by V4L2 request API hwaccel | |
7 | ||
8 | Signed-off-by: Jonas Karlman <jonas@kwiboo.se> | |
9 | --- | |
10 | libavutil/buffer.c | 13 +++++++++++++ | |
11 | libavutil/buffer.h | 5 +++++ | |
12 | 2 files changed, 18 insertions(+) | |
13 | ||
14 | diff --git a/libavutil/buffer.c b/libavutil/buffer.c | |
15 | index 38a554208a90..b0fedabc3e7d 100644 | |
16 | --- a/libavutil/buffer.c | |
17 | +++ b/libavutil/buffer.c | |
18 | @@ -273,6 +273,19 @@ static void buffer_pool_free(AVBufferPool *pool) | |
19 | av_freep(&pool); | |
20 | } | |
21 | ||
22 | +void av_buffer_pool_flush(AVBufferPool *pool) | |
23 | +{ | |
24 | + ff_mutex_lock(&pool->mutex); | |
25 | + while (pool->pool) { | |
26 | + BufferPoolEntry *buf = pool->pool; | |
27 | + pool->pool = buf->next; | |
28 | + | |
29 | + buf->free(buf->opaque, buf->data); | |
30 | + av_freep(&buf); | |
31 | + } | |
32 | + ff_mutex_unlock(&pool->mutex); | |
33 | +} | |
34 | + | |
35 | void av_buffer_pool_uninit(AVBufferPool **ppool) | |
36 | { | |
37 | AVBufferPool *pool; | |
38 | diff --git a/libavutil/buffer.h b/libavutil/buffer.h | |
39 | index c0f3f6cc9abe..998beec9ac5b 100644 | |
40 | --- a/libavutil/buffer.h | |
41 | +++ b/libavutil/buffer.h | |
42 | @@ -267,6 +267,11 @@ AVBufferPool *av_buffer_pool_init2(int size, void *opaque, | |
60ce8543 | 43 | #endif |
80105e83 JP |
44 | void (*pool_free)(void *opaque)); |
45 | ||
46 | +/** | |
47 | + * Free all available buffers in a buffer pool. | |
48 | + */ | |
49 | + void av_buffer_pool_flush(AVBufferPool *pool); | |
50 | + | |
51 | /** | |
52 | * Mark the pool as being available for freeing. It will actually be freed only | |
53 | * once all the allocated buffers associated with the pool are released. Thus it | |
54 | From 01319970d90ffd3c073b054a3d2e4784f6ebea0d Mon Sep 17 00:00:00 2001 | |
55 | From: Jonas Karlman <jonas@kwiboo.se> | |
56 | Date: Sat, 15 Dec 2018 22:32:16 +0100 | |
57 | Subject: [PATCH] Add common V4L2 request API code | |
58 | ||
59 | Signed-off-by: Jonas Karlman <jonas@kwiboo.se> | |
60 | --- | |
61 | configure | 12 + | |
62 | libavcodec/Makefile | 1 + | |
63 | libavcodec/hwconfig.h | 2 + | |
64 | libavcodec/v4l2_request.c | 984 ++++++++++++++++++++++++++++++++++++++ | |
65 | libavcodec/v4l2_request.h | 77 +++ | |
66 | 5 files changed, 1076 insertions(+) | |
67 | create mode 100644 libavcodec/v4l2_request.c | |
68 | create mode 100644 libavcodec/v4l2_request.h | |
69 | ||
70 | diff --git a/configure b/configure | |
71 | index 8569a60bf827..9f9909a23696 100755 | |
72 | --- a/configure | |
73 | +++ b/configure | |
74 | @@ -274,6 +274,7 @@ External library support: | |
75 | --enable-libtls enable LibreSSL (via libtls), needed for https support | |
76 | if openssl, gnutls or mbedtls is not used [no] | |
77 | --enable-libtwolame enable MP2 encoding via libtwolame [no] | |
78 | + --enable-libudev enable libudev [no] | |
60ce8543 | 79 | --enable-libuavs3d enable AVS3 decoding via libuavs3d [no] |
80105e83 JP |
80 | --enable-libv4l2 enable libv4l2/v4l-utils [no] |
81 | --enable-libvidstab enable video stabilization using vid.stab [no] | |
80105e83 JP |
82 | @@ -342,6 +343,7 @@ External library support: |
83 | --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no] | |
84 | --enable-rkmpp enable Rockchip Media Process Platform code [no] | |
85 | --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect] | |
86 | + --enable-v4l2-request enable V4L2 request API code [no] | |
87 | --disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect] | |
88 | --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] | |
89 | --disable-videotoolbox disable VideoToolbox code [autodetect] | |
90 | @@ -1807,6 +1809,7 @@ EXTERNAL_LIBRARY_LIST=" | |
91 | libtesseract | |
92 | libtheora | |
93 | libtwolame | |
94 | + libudev | |
60ce8543 | 95 | libuavs3d |
80105e83 | 96 | libv4l2 |
60ce8543 | 97 | libvmaf |
80105e83 JP |
98 | @@ -1861,6 +1864,7 @@ HWACCEL_LIBRARY_LIST=" |
99 | mmal | |
100 | omx | |
101 | opencl | |
102 | + v4l2_request | |
103 | vulkan | |
104 | " | |
105 | ||
106 | @@ -2903,6 +2907,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" | |
107 | dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" | |
108 | ffnvcodec_deps_any="libdl LoadLibrary" | |
109 | nvdec_deps="ffnvcodec" | |
110 | +v4l2_request_deps="linux_videodev2_h linux_media_h v4l2_timeval_to_ns libdrm libudev" | |
111 | vaapi_x11_deps="xlib" | |
112 | videotoolbox_hwaccel_deps="videotoolbox pthreads" | |
113 | videotoolbox_hwaccel_extralibs="-framework QuartzCore" | |
114 | @@ -6376,6 +6381,7 @@ enabled libtls && require_pkg_config libtls libtls tls.h tls_configur | |
115 | enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame && | |
116 | { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame || | |
117 | die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } | |
118 | +enabled libudev && require_pkg_config libudev libudev libudev.h udev_new | |
60ce8543 | 119 | enabled libuavs3d && require_pkg_config libuavs3d "uavs3d >= 1.1.41" uavs3d.h uavs3d_decode |
80105e83 JP |
120 | enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl |
121 | enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit | |
80105e83 JP |
122 | @@ -6475,6 +6481,10 @@ enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/r |
123 | { enabled libdrm || | |
124 | die "ERROR: rkmpp requires --enable-libdrm"; } | |
125 | } | |
126 | +enabled v4l2_request && { enabled libdrm || | |
127 | + die "ERROR: v4l2-request requires --enable-libdrm"; } && | |
128 | + { enabled libudev || | |
129 | + die "ERROR: v4l2-request requires --enable-libudev"; } | |
130 | enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init | |
131 | ||
132 | ||
133 | @@ -6556,6 +6566,8 @@ if enabled v4l2_m2m; then | |
134 | check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" | |
135 | fi | |
136 | ||
137 | +check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns | |
138 | + | |
139 | check_headers sys/videoio.h | |
140 | test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete | |
141 | ||
142 | diff --git a/libavcodec/Makefile b/libavcodec/Makefile | |
143 | index 5a6ea59715af..d74220516826 100644 | |
144 | --- a/libavcodec/Makefile | |
145 | +++ b/libavcodec/Makefile | |
146 | @@ -153,6 +153,7 @@ OBJS-$(CONFIG_VP3DSP) += vp3dsp.o | |
147 | OBJS-$(CONFIG_VP56DSP) += vp56dsp.o | |
148 | OBJS-$(CONFIG_VP8DSP) += vp8dsp.o | |
149 | OBJS-$(CONFIG_V4L2_M2M) += v4l2_m2m.o v4l2_context.o v4l2_buffers.o v4l2_fmt.o | |
150 | +OBJS-$(CONFIG_V4L2_REQUEST) += v4l2_request.o | |
151 | OBJS-$(CONFIG_WMA_FREQS) += wma_freqs.o | |
152 | OBJS-$(CONFIG_WMV2DSP) += wmv2dsp.o | |
153 | ||
154 | diff --git a/libavcodec/hwconfig.h b/libavcodec/hwconfig.h | |
155 | index f421dc909f44..ee78d8ab8e89 100644 | |
156 | --- a/libavcodec/hwconfig.h | |
157 | +++ b/libavcodec/hwconfig.h | |
158 | @@ -80,6 +80,8 @@ typedef struct AVCodecHWConfigInternal { | |
159 | HW_CONFIG_HWACCEL(0, 0, 1, D3D11VA_VLD, NONE, ff_ ## codec ## _d3d11va_hwaccel) | |
160 | #define HWACCEL_XVMC(codec) \ | |
161 | HW_CONFIG_HWACCEL(0, 0, 1, XVMC, NONE, ff_ ## codec ## _xvmc_hwaccel) | |
162 | +#define HWACCEL_V4L2REQUEST(codec) \ | |
163 | + HW_CONFIG_HWACCEL(1, 0, 0, DRM_PRIME, DRM, ff_ ## codec ## _v4l2request_hwaccel) | |
164 | ||
165 | #define HW_CONFIG_ENCODER(device, frames, ad_hoc, format, device_type_) \ | |
166 | &(const AVCodecHWConfigInternal) { \ | |
167 | diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c | |
168 | new file mode 100644 | |
169 | index 000000000000..5234b5049b0d | |
170 | --- /dev/null | |
171 | +++ b/libavcodec/v4l2_request.c | |
172 | @@ -0,0 +1,984 @@ | |
173 | +/* | |
174 | + * This file is part of FFmpeg. | |
175 | + * | |
176 | + * FFmpeg is free software; you can redistribute it and/or | |
177 | + * modify it under the terms of the GNU Lesser General Public | |
178 | + * License as published by the Free Software Foundation; either | |
179 | + * version 2.1 of the License, or (at your option) any later version. | |
180 | + * | |
181 | + * FFmpeg is distributed in the hope that it will be useful, | |
182 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
183 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
184 | + * Lesser General Public License for more details. | |
185 | + * | |
186 | + * You should have received a copy of the GNU Lesser General Public | |
187 | + * License along with FFmpeg; if not, write to the Free Software | |
188 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
189 | + */ | |
190 | + | |
191 | +#include <drm_fourcc.h> | |
192 | +#include <linux/media.h> | |
193 | +#include <sys/mman.h> | |
194 | +#include <sys/types.h> | |
195 | +#include <sys/stat.h> | |
196 | +#include <fcntl.h> | |
197 | + | |
198 | +#include <sys/sysmacros.h> | |
199 | +#include <libudev.h> | |
200 | + | |
201 | +#include "decode.h" | |
202 | +#include "internal.h" | |
203 | +#include "v4l2_request.h" | |
204 | + | |
205 | +uint64_t ff_v4l2_request_get_capture_timestamp(AVFrame *frame) | |
206 | +{ | |
207 | + V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)frame->data[0]; | |
208 | + return req ? v4l2_timeval_to_ns(&req->capture.buffer.timestamp) : 0; | |
209 | +} | |
210 | + | |
211 | +int ff_v4l2_request_reset_frame(AVCodecContext *avctx, AVFrame *frame) | |
212 | +{ | |
213 | + V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)frame->data[0]; | |
214 | + memset(&req->drm, 0, sizeof(AVDRMFrameDescriptor)); | |
215 | + req->output.used = 0; | |
216 | + return 0; | |
217 | +} | |
218 | + | |
219 | +int ff_v4l2_request_append_output_buffer(AVCodecContext *avctx, AVFrame *frame, const uint8_t *data, uint32_t size) | |
220 | +{ | |
221 | + V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)frame->data[0]; | |
222 | + if (req->output.used + size + (AV_INPUT_BUFFER_PADDING_SIZE * 4) <= req->output.size) { | |
223 | + memcpy(req->output.addr + req->output.used, data, size); | |
224 | + req->output.used += size; | |
225 | + } else { | |
226 | + av_log(avctx, AV_LOG_ERROR, "%s: output.used=%u output.size=%u size=%u\n", __func__, req->output.used, req->output.size, size); | |
227 | + } | |
228 | + return 0; | |
229 | +} | |
230 | + | |
231 | +static int v4l2_request_controls(V4L2RequestContext *ctx, int request_fd, unsigned long type, struct v4l2_ext_control *control, int count) | |
232 | +{ | |
233 | + struct v4l2_ext_controls controls = { | |
234 | + .controls = control, | |
235 | + .count = count, | |
236 | + .request_fd = request_fd, | |
237 | + .which = (request_fd >= 0) ? V4L2_CTRL_WHICH_REQUEST_VAL : 0, | |
238 | + }; | |
239 | + | |
240 | + if (!control || !count) | |
241 | + return 0; | |
242 | + | |
243 | + return ioctl(ctx->video_fd, type, &controls); | |
244 | +} | |
245 | + | |
246 | +static int v4l2_request_set_controls(V4L2RequestContext *ctx, int request_fd, struct v4l2_ext_control *control, int count) | |
247 | +{ | |
248 | + return v4l2_request_controls(ctx, request_fd, VIDIOC_S_EXT_CTRLS, control, count); | |
249 | +} | |
250 | + | |
251 | +int ff_v4l2_request_set_controls(AVCodecContext *avctx, struct v4l2_ext_control *control, int count) | |
252 | +{ | |
253 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
254 | + int ret; | |
255 | + | |
256 | + ret = v4l2_request_controls(ctx, -1, VIDIOC_S_EXT_CTRLS, control, count); | |
257 | + if (ret < 0) { | |
258 | + av_log(avctx, AV_LOG_ERROR, "%s: set controls failed, %s (%d)\n", __func__, strerror(errno), errno); | |
259 | + return AVERROR(EINVAL); | |
260 | + } | |
261 | + | |
262 | + return ret; | |
263 | +} | |
264 | + | |
265 | +int ff_v4l2_request_get_controls(AVCodecContext *avctx, struct v4l2_ext_control *control, int count) | |
266 | +{ | |
267 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
268 | + int ret; | |
269 | + | |
270 | + ret = v4l2_request_controls(ctx, -1, VIDIOC_G_EXT_CTRLS, control, count); | |
271 | + if (ret < 0) { | |
272 | + av_log(avctx, AV_LOG_ERROR, "%s: get controls failed, %s (%d)\n", __func__, strerror(errno), errno); | |
273 | + return AVERROR(EINVAL); | |
274 | + } | |
275 | + | |
276 | + return ret; | |
277 | +} | |
278 | + | |
279 | +int ff_v4l2_request_query_control(AVCodecContext *avctx, struct v4l2_query_ext_ctrl *control) | |
280 | +{ | |
281 | + int ret; | |
282 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
283 | + | |
284 | + ret = ioctl(ctx->video_fd, VIDIOC_QUERY_EXT_CTRL, control); | |
285 | + if (ret < 0) { | |
286 | + av_log(avctx, AV_LOG_ERROR, "%s: query control failed, %s (%d)\n", __func__, strerror(errno), errno); | |
287 | + return AVERROR(EINVAL); | |
288 | + } | |
289 | + | |
290 | + return 0; | |
291 | +} | |
292 | + | |
293 | +int ff_v4l2_request_query_control_default_value(AVCodecContext *avctx, uint32_t id) | |
294 | +{ | |
295 | + int ret; | |
296 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
297 | + struct v4l2_queryctrl control = { | |
298 | + .id = id, | |
299 | + }; | |
300 | + | |
301 | + ret = ioctl(ctx->video_fd, VIDIOC_QUERYCTRL, &control); | |
302 | + if (ret < 0) { | |
303 | + av_log(avctx, AV_LOG_ERROR, "%s: query control failed, %s (%d)\n", __func__, strerror(errno), errno); | |
304 | + return AVERROR(EINVAL); | |
305 | + } | |
306 | + | |
307 | + return control.default_value; | |
308 | +} | |
309 | + | |
310 | +static int v4l2_request_queue_buffer(V4L2RequestContext *ctx, int request_fd, V4L2RequestBuffer *buf, uint32_t flags) | |
311 | +{ | |
312 | + struct v4l2_plane planes[1] = {}; | |
313 | + struct v4l2_buffer buffer = { | |
314 | + .type = buf->buffer.type, | |
315 | + .memory = buf->buffer.memory, | |
316 | + .index = buf->index, | |
317 | + .timestamp.tv_usec = ctx->timestamp, | |
318 | + .bytesused = buf->used, | |
319 | + .request_fd = request_fd, | |
320 | + .flags = ((request_fd >= 0) ? V4L2_BUF_FLAG_REQUEST_FD : 0) | flags, | |
321 | + }; | |
322 | + | |
323 | + buf->buffer.timestamp = buffer.timestamp; | |
324 | + | |
325 | + if (V4L2_TYPE_IS_MULTIPLANAR(buf->buffer.type)) { | |
326 | + planes[0].bytesused = buf->used; | |
327 | + buffer.bytesused = 0; | |
328 | + buffer.length = 1; | |
329 | + buffer.m.planes = planes; | |
330 | + } | |
331 | + | |
332 | + return ioctl(ctx->video_fd, VIDIOC_QBUF, &buffer); | |
333 | +} | |
334 | + | |
335 | +static int v4l2_request_dequeue_buffer(V4L2RequestContext *ctx, V4L2RequestBuffer *buf) | |
336 | +{ | |
337 | + int ret; | |
338 | + struct v4l2_plane planes[1] = {}; | |
339 | + struct v4l2_buffer buffer = { | |
340 | + .type = buf->buffer.type, | |
341 | + .memory = buf->buffer.memory, | |
342 | + .index = buf->index, | |
343 | + }; | |
344 | + | |
345 | + if (V4L2_TYPE_IS_MULTIPLANAR(buf->buffer.type)) { | |
346 | + buffer.length = 1; | |
347 | + buffer.m.planes = planes; | |
348 | + } | |
349 | + | |
350 | + ret = ioctl(ctx->video_fd, VIDIOC_DQBUF, &buffer); | |
351 | + if (ret < 0) | |
352 | + return ret; | |
353 | + | |
354 | + buf->buffer.timestamp = buffer.timestamp; | |
355 | + return 0; | |
356 | +} | |
357 | + | |
358 | +const uint32_t v4l2_request_capture_pixelformats[] = { | |
359 | + V4L2_PIX_FMT_NV12, | |
360 | +#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED | |
361 | + V4L2_PIX_FMT_SUNXI_TILED_NV12, | |
362 | +#endif | |
363 | +}; | |
364 | + | |
365 | +static int v4l2_request_set_drm_descriptor(V4L2RequestDescriptor *req, struct v4l2_format *format) | |
366 | +{ | |
367 | + AVDRMFrameDescriptor *desc = &req->drm; | |
368 | + AVDRMLayerDescriptor *layer = &desc->layers[0]; | |
369 | + uint32_t pixelformat = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? format->fmt.pix_mp.pixelformat : format->fmt.pix.pixelformat; | |
370 | + | |
371 | + switch (pixelformat) { | |
372 | + case V4L2_PIX_FMT_NV12: | |
373 | + layer->format = DRM_FORMAT_NV12; | |
374 | + desc->objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR; | |
375 | + break; | |
376 | +#ifdef DRM_FORMAT_MOD_ALLWINNER_TILED | |
377 | + case V4L2_PIX_FMT_SUNXI_TILED_NV12: | |
378 | + layer->format = DRM_FORMAT_NV12; | |
379 | + desc->objects[0].format_modifier = DRM_FORMAT_MOD_ALLWINNER_TILED; | |
380 | + break; | |
381 | +#endif | |
382 | + default: | |
383 | + return -1; | |
384 | + } | |
385 | + | |
386 | + desc->nb_objects = 1; | |
387 | + desc->objects[0].fd = req->capture.fd; | |
388 | + desc->objects[0].size = req->capture.size; | |
389 | + | |
390 | + desc->nb_layers = 1; | |
391 | + layer->nb_planes = 2; | |
392 | + | |
393 | + layer->planes[0].object_index = 0; | |
394 | + layer->planes[0].offset = 0; | |
395 | + layer->planes[0].pitch = V4L2_TYPE_IS_MULTIPLANAR(format->type) ? format->fmt.pix_mp.plane_fmt[0].bytesperline : format->fmt.pix.bytesperline; | |
396 | + | |
397 | + layer->planes[1].object_index = 0; | |
398 | + layer->planes[1].offset = layer->planes[0].pitch * (V4L2_TYPE_IS_MULTIPLANAR(format->type) ? format->fmt.pix_mp.height : format->fmt.pix.height); | |
399 | + layer->planes[1].pitch = layer->planes[0].pitch; | |
400 | + | |
401 | + return 0; | |
402 | +} | |
403 | + | |
404 | +static int v4l2_request_queue_decode(AVCodecContext *avctx, AVFrame *frame, struct v4l2_ext_control *control, int count, int first_slice, int last_slice) | |
405 | +{ | |
406 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
407 | + V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)frame->data[0]; | |
408 | + struct timeval tv = { 2, 0 }; | |
409 | + fd_set except_fds; | |
410 | + int ret; | |
411 | + | |
412 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p used=%u controls=%d index=%d fd=%d request_fd=%d first_slice=%d last_slice=%d\n", __func__, avctx, req->output.used, count, req->capture.index, req->capture.fd, req->request_fd, first_slice, last_slice); | |
413 | + | |
414 | + if (first_slice) | |
415 | + ctx->timestamp++; | |
416 | + | |
417 | + ret = v4l2_request_set_controls(ctx, req->request_fd, control, count); | |
418 | + if (ret < 0) { | |
419 | + av_log(avctx, AV_LOG_ERROR, "%s: set controls failed for request %d, %s (%d)\n", __func__, req->request_fd, strerror(errno), errno); | |
420 | + return -1; | |
421 | + } | |
422 | + | |
423 | + memset(req->output.addr + req->output.used, 0, AV_INPUT_BUFFER_PADDING_SIZE * 4); | |
424 | + | |
425 | + ret = v4l2_request_queue_buffer(ctx, req->request_fd, &req->output, last_slice ? 0 : V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF); | |
426 | + if (ret < 0) { | |
427 | + av_log(avctx, AV_LOG_ERROR, "%s: queue output buffer %d failed for request %d, %s (%d)\n", __func__, req->output.index, req->request_fd, strerror(errno), errno); | |
428 | + return -1; | |
429 | + } | |
430 | + | |
431 | + if (first_slice) { | |
432 | + ret = v4l2_request_queue_buffer(ctx, -1, &req->capture, 0); | |
433 | + if (ret < 0) { | |
434 | + av_log(avctx, AV_LOG_ERROR, "%s: queue capture buffer %d failed for request %d, %s (%d)\n", __func__, req->capture.index, req->request_fd, strerror(errno), errno); | |
435 | + return -1; | |
436 | + } | |
437 | + } | |
438 | + | |
439 | + // NOTE: do we need to dequeue when request fails/timeout? | |
440 | + | |
441 | + // 4. queue request and wait | |
442 | + ret = ioctl(req->request_fd, MEDIA_REQUEST_IOC_QUEUE, NULL); | |
443 | + if (ret < 0) { | |
444 | + av_log(avctx, AV_LOG_ERROR, "%s: queue request %d failed, %s (%d)\n", __func__, req->request_fd, strerror(errno), errno); | |
445 | + goto fail; | |
446 | + } | |
447 | + | |
448 | + FD_ZERO(&except_fds); | |
449 | + FD_SET(req->request_fd, &except_fds); | |
450 | + | |
451 | + ret = select(req->request_fd + 1, NULL, NULL, &except_fds, &tv); | |
452 | + if (ret == 0) { | |
453 | + av_log(avctx, AV_LOG_ERROR, "%s: request %d timeout\n", __func__, req->request_fd); | |
454 | + goto fail; | |
455 | + } else if (ret < 0) { | |
456 | + av_log(avctx, AV_LOG_ERROR, "%s: select request %d failed, %s (%d)\n", __func__, req->request_fd, strerror(errno), errno); | |
457 | + goto fail; | |
458 | + } | |
459 | + | |
460 | + ret = v4l2_request_dequeue_buffer(ctx, &req->output); | |
461 | + if (ret < 0) { | |
462 | + av_log(avctx, AV_LOG_ERROR, "%s: dequeue output buffer %d failed for request %d, %s (%d)\n", __func__, req->output.index, req->request_fd, strerror(errno), errno); | |
463 | + return -1; | |
464 | + } | |
465 | + | |
466 | + if (last_slice) { | |
467 | + ret = v4l2_request_dequeue_buffer(ctx, &req->capture); | |
468 | + if (ret < 0) { | |
469 | + av_log(avctx, AV_LOG_ERROR, "%s: dequeue capture buffer %d failed for request %d, %s (%d)\n", __func__, req->capture.index, req->request_fd, strerror(errno), errno); | |
470 | + return -1; | |
471 | + } | |
472 | + } | |
473 | + | |
474 | + // TODO: check errors | |
475 | + // buffer.flags & V4L2_BUF_FLAG_ERROR | |
476 | + | |
477 | + ret = ioctl(req->request_fd, MEDIA_REQUEST_IOC_REINIT, NULL); | |
478 | + if (ret < 0) { | |
479 | + av_log(avctx, AV_LOG_ERROR, "%s: reinit request %d failed, %s (%d)\n", __func__, req->request_fd, strerror(errno), errno); | |
480 | + return -1; | |
481 | + } | |
482 | + | |
483 | + if (last_slice) | |
484 | + return v4l2_request_set_drm_descriptor(req, &ctx->format); | |
485 | + | |
486 | + return 0; | |
487 | + | |
488 | +fail: | |
489 | + ret = v4l2_request_dequeue_buffer(ctx, &req->output); | |
490 | + if (ret < 0) | |
491 | + av_log(avctx, AV_LOG_ERROR, "%s: dequeue output buffer %d failed for request %d, %s (%d)\n", __func__, req->output.index, req->request_fd, strerror(errno), errno); | |
492 | + | |
493 | + ret = v4l2_request_dequeue_buffer(ctx, &req->capture); | |
494 | + if (ret < 0) | |
495 | + av_log(avctx, AV_LOG_ERROR, "%s: dequeue capture buffer %d failed for request %d, %s (%d)\n", __func__, req->capture.index, req->request_fd, strerror(errno), errno); | |
496 | + | |
497 | + ret = ioctl(req->request_fd, MEDIA_REQUEST_IOC_REINIT, NULL); | |
498 | + if (ret < 0) | |
499 | + av_log(avctx, AV_LOG_ERROR, "%s: reinit request %d failed, %s (%d)\n", __func__, req->request_fd, strerror(errno), errno); | |
500 | + | |
501 | + return -1; | |
502 | +} | |
503 | + | |
504 | +int ff_v4l2_request_decode_slice(AVCodecContext *avctx, AVFrame *frame, struct v4l2_ext_control *control, int count, int first_slice, int last_slice) | |
505 | +{ | |
506 | + V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)frame->data[0]; | |
507 | + | |
508 | + // fall back to queue each slice as a full frame | |
509 | + if ((req->output.capabilities & V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF) != V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF) | |
510 | + return v4l2_request_queue_decode(avctx, frame, control, count, 1, 1); | |
511 | + | |
512 | + return v4l2_request_queue_decode(avctx, frame, control, count, first_slice, last_slice); | |
513 | +} | |
514 | + | |
515 | +int ff_v4l2_request_decode_frame(AVCodecContext *avctx, AVFrame *frame, struct v4l2_ext_control *control, int count) | |
516 | +{ | |
517 | + return v4l2_request_queue_decode(avctx, frame, control, count, 1, 1); | |
518 | +} | |
519 | + | |
520 | +static int v4l2_request_try_format(AVCodecContext *avctx, enum v4l2_buf_type type, uint32_t pixelformat) | |
521 | +{ | |
522 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
523 | + struct v4l2_fmtdesc fmtdesc = { | |
524 | + .index = 0, | |
525 | + .type = type, | |
526 | + }; | |
527 | + | |
528 | + if (V4L2_TYPE_IS_OUTPUT(type)) { | |
529 | + struct v4l2_create_buffers buffers = { | |
530 | + .count = 0, | |
531 | + .memory = V4L2_MEMORY_MMAP, | |
532 | + .format.type = type, | |
533 | + }; | |
534 | + | |
535 | + if (ioctl(ctx->video_fd, VIDIOC_CREATE_BUFS, &buffers) < 0) { | |
536 | + av_log(avctx, AV_LOG_ERROR, "%s: create buffers failed for type %u, %s (%d)\n", __func__, type, strerror(errno), errno); | |
537 | + return -1; | |
538 | + } | |
539 | + | |
540 | + if ((buffers.capabilities & V4L2_BUF_CAP_SUPPORTS_REQUESTS) != V4L2_BUF_CAP_SUPPORTS_REQUESTS) { | |
541 | + av_log(avctx, AV_LOG_INFO, "%s: output buffer type do not support requests, capabilities %u\n", __func__, buffers.capabilities); | |
542 | + return -1; | |
543 | + } | |
544 | + } | |
545 | + | |
546 | + while (ioctl(ctx->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) { | |
547 | + if (fmtdesc.pixelformat == pixelformat) | |
548 | + return 0; | |
549 | + | |
550 | + fmtdesc.index++; | |
551 | + } | |
552 | + | |
553 | + av_log(avctx, AV_LOG_INFO, "%s: pixelformat %u not supported for type %u\n", __func__, pixelformat, type); | |
554 | + return -1; | |
555 | +} | |
556 | + | |
557 | +static int v4l2_request_set_format(AVCodecContext *avctx, enum v4l2_buf_type type, uint32_t pixelformat, uint32_t buffersize) | |
558 | +{ | |
559 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
560 | + struct v4l2_format format = { | |
561 | + .type = type, | |
562 | + }; | |
563 | + | |
564 | + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { | |
565 | + format.fmt.pix_mp.width = avctx->coded_width; | |
566 | + format.fmt.pix_mp.height = avctx->coded_height; | |
567 | + format.fmt.pix_mp.pixelformat = pixelformat; | |
568 | + format.fmt.pix_mp.plane_fmt[0].sizeimage = buffersize; | |
569 | + format.fmt.pix_mp.num_planes = 1; | |
570 | + } else { | |
571 | + format.fmt.pix.width = avctx->coded_width; | |
572 | + format.fmt.pix.height = avctx->coded_height; | |
573 | + format.fmt.pix.pixelformat = pixelformat; | |
574 | + format.fmt.pix.sizeimage = buffersize; | |
575 | + } | |
576 | + | |
577 | + return ioctl(ctx->video_fd, VIDIOC_S_FMT, &format); | |
578 | +} | |
579 | + | |
580 | +static int v4l2_request_select_capture_format(AVCodecContext *avctx) | |
581 | +{ | |
582 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
583 | + enum v4l2_buf_type type = ctx->format.type; | |
584 | + | |
585 | +#if 0 | |
586 | + struct v4l2_format format = { | |
587 | + .type = type, | |
588 | + }; | |
589 | + struct v4l2_fmtdesc fmtdesc = { | |
590 | + .index = 0, | |
591 | + .type = type, | |
592 | + }; | |
593 | + uint32_t pixelformat; | |
594 | + int i; | |
595 | + | |
596 | + if (ioctl(ctx->video_fd, VIDIOC_G_FMT, &format) < 0) { | |
597 | + av_log(avctx, AV_LOG_ERROR, "%s: get capture format failed, %s (%d)\n", __func__, strerror(errno), errno); | |
598 | + return -1; | |
599 | + } | |
600 | + | |
601 | + pixelformat = V4L2_TYPE_IS_MULTIPLANAR(type) ? format.fmt.pix_mp.pixelformat : format.fmt.pix.pixelformat; | |
602 | + | |
603 | + for (i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { | |
604 | + if (pixelformat == v4l2_request_capture_pixelformats[i]) | |
605 | + return v4l2_request_set_format(avctx, type, pixelformat, 0); | |
606 | + } | |
607 | + | |
608 | + while (ioctl(ctx->video_fd, VIDIOC_ENUM_FMT, &fmtdesc) >= 0) { | |
609 | + for (i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { | |
610 | + if (fmtdesc.pixelformat == v4l2_request_capture_pixelformats[i]) | |
611 | + return v4l2_request_set_format(avctx, type, fmtdesc.pixelformat, 0); | |
612 | + } | |
613 | + | |
614 | + fmtdesc.index++; | |
615 | + } | |
616 | +#else | |
617 | + for (int i = 0; i < FF_ARRAY_ELEMS(v4l2_request_capture_pixelformats); i++) { | |
618 | + uint32_t pixelformat = v4l2_request_capture_pixelformats[i]; | |
619 | + if (!v4l2_request_try_format(avctx, type, pixelformat)) | |
620 | + return v4l2_request_set_format(avctx, type, pixelformat, 0); | |
621 | + } | |
622 | +#endif | |
623 | + | |
624 | + return -1; | |
625 | +} | |
626 | + | |
627 | +static int v4l2_request_probe_video_device(struct udev_device *device, AVCodecContext *avctx, uint32_t pixelformat, uint32_t buffersize, struct v4l2_ext_control *control, int count) | |
628 | +{ | |
629 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
630 | + int ret = AVERROR(EINVAL); | |
631 | + struct v4l2_capability capability = {0}; | |
632 | + unsigned int capabilities = 0; | |
633 | + | |
634 | + const char *path = udev_device_get_devnode(device); | |
635 | + if (!path) { | |
636 | + av_log(avctx, AV_LOG_ERROR, "%s: get video device devnode failed\n", __func__); | |
637 | + ret = AVERROR(EINVAL); | |
638 | + goto fail; | |
639 | + } | |
640 | + | |
641 | + ctx->video_fd = open(path, O_RDWR | O_NONBLOCK, 0); | |
642 | + if (ctx->video_fd < 0) { | |
643 | + av_log(avctx, AV_LOG_ERROR, "%s: opening %s failed, %s (%d)\n", __func__, path, strerror(errno), errno); | |
644 | + ret = AVERROR(EINVAL); | |
645 | + goto fail; | |
646 | + } | |
647 | + | |
648 | + ret = ioctl(ctx->video_fd, VIDIOC_QUERYCAP, &capability); | |
649 | + if (ret < 0) { | |
650 | + av_log(avctx, AV_LOG_ERROR, "%s: get video capability failed, %s (%d)\n", __func__, strerror(errno), errno); | |
651 | + ret = AVERROR(EINVAL); | |
652 | + goto fail; | |
653 | + } | |
654 | + | |
655 | + if (capability.capabilities & V4L2_CAP_DEVICE_CAPS) | |
656 | + capabilities = capability.device_caps; | |
657 | + else | |
658 | + capabilities = capability.capabilities; | |
659 | + | |
660 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p ctx=%p path=%s capabilities=%u\n", __func__, avctx, ctx, path, capabilities); | |
661 | + | |
662 | + if ((capabilities & V4L2_CAP_STREAMING) != V4L2_CAP_STREAMING) { | |
663 | + av_log(avctx, AV_LOG_ERROR, "%s: missing required streaming capability\n", __func__); | |
664 | + ret = AVERROR(EINVAL); | |
665 | + goto fail; | |
666 | + } | |
667 | + | |
668 | + if ((capabilities & V4L2_CAP_VIDEO_M2M_MPLANE) == V4L2_CAP_VIDEO_M2M_MPLANE) { | |
669 | + ctx->output_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
670 | + ctx->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
671 | + } else if ((capabilities & V4L2_CAP_VIDEO_M2M) == V4L2_CAP_VIDEO_M2M) { | |
672 | + ctx->output_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | |
673 | + ctx->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
674 | + } else { | |
675 | + av_log(avctx, AV_LOG_ERROR, "%s: missing required mem2mem capability\n", __func__); | |
676 | + ret = AVERROR(EINVAL); | |
677 | + goto fail; | |
678 | + } | |
679 | + | |
680 | + ret = v4l2_request_try_format(avctx, ctx->output_type, pixelformat); | |
681 | + if (ret < 0) { | |
682 | + av_log(avctx, AV_LOG_WARNING, "%s: try output format failed\n", __func__); | |
683 | + ret = AVERROR(EINVAL); | |
684 | + goto fail; | |
685 | + } | |
686 | + | |
687 | + ret = v4l2_request_set_format(avctx, ctx->output_type, pixelformat, buffersize); | |
688 | + if (ret < 0) { | |
689 | + av_log(avctx, AV_LOG_ERROR, "%s: set output format failed, %s (%d)\n", __func__, strerror(errno), errno); | |
690 | + ret = AVERROR(EINVAL); | |
691 | + goto fail; | |
692 | + } | |
693 | + | |
694 | + ret = v4l2_request_set_controls(ctx, -1, control, count); | |
695 | + if (ret < 0) { | |
696 | + av_log(avctx, AV_LOG_ERROR, "%s: set controls failed, %s (%d)\n", __func__, strerror(errno), errno); | |
697 | + ret = AVERROR(EINVAL); | |
698 | + goto fail; | |
699 | + } | |
700 | + | |
701 | + ret = v4l2_request_select_capture_format(avctx); | |
702 | + if (ret < 0) { | |
703 | + av_log(avctx, AV_LOG_WARNING, "%s: select capture format failed\n", __func__); | |
704 | + ret = AVERROR(EINVAL); | |
705 | + goto fail; | |
706 | + } | |
707 | + | |
708 | + return 0; | |
709 | + | |
710 | +fail: | |
711 | + if (ctx->video_fd >= 0) { | |
712 | + close(ctx->video_fd); | |
713 | + ctx->video_fd = -1; | |
714 | + } | |
715 | + return ret; | |
716 | +} | |
717 | + | |
718 | +static int v4l2_request_init_context(AVCodecContext *avctx) | |
719 | +{ | |
720 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
721 | + int ret; | |
722 | + | |
723 | + ret = ioctl(ctx->video_fd, VIDIOC_G_FMT, &ctx->format); | |
724 | + if (ret < 0) { | |
725 | + av_log(avctx, AV_LOG_ERROR, "%s: get capture format failed, %s (%d)\n", __func__, strerror(errno), errno); | |
726 | + ret = AVERROR(EINVAL); | |
727 | + goto fail; | |
728 | + } | |
729 | + | |
730 | + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->format.type)) { | |
731 | + av_log(avctx, AV_LOG_DEBUG, "%s: pixelformat=%d width=%u height=%u bytesperline=%u sizeimage=%u num_planes=%u\n", __func__, ctx->format.fmt.pix_mp.pixelformat, ctx->format.fmt.pix_mp.width, ctx->format.fmt.pix_mp.height, ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline, ctx->format.fmt.pix_mp.plane_fmt[0].sizeimage, ctx->format.fmt.pix_mp.num_planes); | |
732 | + } else { | |
733 | + av_log(avctx, AV_LOG_DEBUG, "%s: pixelformat=%d width=%u height=%u bytesperline=%u sizeimage=%u\n", __func__, ctx->format.fmt.pix.pixelformat, ctx->format.fmt.pix.width, ctx->format.fmt.pix.height, ctx->format.fmt.pix.bytesperline, ctx->format.fmt.pix.sizeimage); | |
734 | + } | |
735 | + | |
736 | + ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_DRM); | |
737 | + if (ret < 0) | |
738 | + goto fail; | |
739 | + | |
740 | + ret = ioctl(ctx->video_fd, VIDIOC_STREAMON, &ctx->output_type); | |
741 | + if (ret < 0) { | |
742 | + av_log(avctx, AV_LOG_ERROR, "%s: output stream on failed, %s (%d)\n", __func__, strerror(errno), errno); | |
743 | + ret = AVERROR(EINVAL); | |
744 | + goto fail; | |
745 | + } | |
746 | + | |
747 | + ret = ioctl(ctx->video_fd, VIDIOC_STREAMON, &ctx->format.type); | |
748 | + if (ret < 0) { | |
749 | + av_log(avctx, AV_LOG_ERROR, "%s: capture stream on failed, %s (%d)\n", __func__, strerror(errno), errno); | |
750 | + ret = AVERROR(EINVAL); | |
751 | + goto fail; | |
752 | + } | |
753 | + | |
754 | + return 0; | |
755 | + | |
756 | +fail: | |
757 | + ff_v4l2_request_uninit(avctx); | |
758 | + return ret; | |
759 | +} | |
760 | + | |
761 | +static int v4l2_request_probe_media_device(struct udev_device *device, AVCodecContext *avctx, uint32_t pixelformat, uint32_t buffersize, struct v4l2_ext_control *control, int count) | |
762 | +{ | |
763 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
764 | + int ret; | |
765 | + struct media_device_info device_info = {0}; | |
766 | + struct media_v2_topology topology = {0}; | |
767 | + struct media_v2_interface *interfaces = NULL; | |
768 | + struct udev *udev = udev_device_get_udev(device); | |
769 | + struct udev_device *video_device; | |
770 | + dev_t devnum; | |
771 | + | |
772 | + const char *path = udev_device_get_devnode(device); | |
773 | + if (!path) { | |
774 | + av_log(avctx, AV_LOG_ERROR, "%s: get media device devnode failed\n", __func__); | |
775 | + ret = AVERROR(EINVAL); | |
776 | + goto fail; | |
777 | + } | |
778 | + | |
779 | + ctx->media_fd = open(path, O_RDWR, 0); | |
780 | + if (ctx->media_fd < 0) { | |
781 | + av_log(avctx, AV_LOG_ERROR, "%s: opening %s failed, %s (%d)\n", __func__, path, strerror(errno), errno); | |
782 | + ret = AVERROR(EINVAL); | |
783 | + goto fail; | |
784 | + } | |
785 | + | |
786 | + ret = ioctl(ctx->media_fd, MEDIA_IOC_DEVICE_INFO, &device_info); | |
787 | + if (ret < 0) { | |
788 | + av_log(avctx, AV_LOG_ERROR, "%s: get media device info failed, %s (%d)\n", __func__, strerror(errno), errno); | |
789 | + ret = AVERROR(EINVAL); | |
790 | + goto fail; | |
791 | + } | |
792 | + | |
793 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p ctx=%p path=%s driver=%s\n", __func__, avctx, ctx, path, device_info.driver); | |
794 | + | |
795 | + ret = ioctl(ctx->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology); | |
796 | + if (ret < 0) { | |
797 | + av_log(avctx, AV_LOG_ERROR, "%s: get media topology failed, %s (%d)\n", __func__, strerror(errno), errno); | |
798 | + ret = AVERROR(EINVAL); | |
799 | + goto fail; | |
800 | + } | |
801 | + | |
802 | + if (topology.num_interfaces <= 0) { | |
803 | + av_log(avctx, AV_LOG_ERROR, "%s: media device has no interfaces\n", __func__); | |
804 | + ret = AVERROR(EINVAL); | |
805 | + goto fail; | |
806 | + } | |
807 | + | |
808 | + interfaces = av_mallocz(topology.num_interfaces * sizeof(struct media_v2_interface)); | |
809 | + if (!interfaces) { | |
810 | + av_log(avctx, AV_LOG_ERROR, "%s: allocating media interface struct failed\n", __func__); | |
811 | + ret = AVERROR(ENOMEM); | |
812 | + goto fail; | |
813 | + } | |
814 | + | |
815 | + topology.ptr_interfaces = (__u64)(uintptr_t)interfaces; | |
816 | + ret = ioctl(ctx->media_fd, MEDIA_IOC_G_TOPOLOGY, &topology); | |
817 | + if (ret < 0) { | |
818 | + av_log(avctx, AV_LOG_ERROR, "%s: get media topology failed, %s (%d)\n", __func__, strerror(errno), errno); | |
819 | + ret = AVERROR(EINVAL); | |
820 | + goto fail; | |
821 | + } | |
822 | + | |
823 | + ret = AVERROR(EINVAL); | |
824 | + for (int i = 0; i < topology.num_interfaces; i++) { | |
825 | + if (interfaces[i].intf_type != MEDIA_INTF_T_V4L_VIDEO) | |
826 | + continue; | |
827 | + | |
828 | + devnum = makedev(interfaces[i].devnode.major, interfaces[i].devnode.minor); | |
829 | + video_device = udev_device_new_from_devnum(udev, 'c', devnum); | |
830 | + if (!video_device) { | |
831 | + av_log(avctx, AV_LOG_ERROR, "%s: video_device=%p\n", __func__, video_device); | |
832 | + continue; | |
833 | + } | |
834 | + | |
835 | + ret = v4l2_request_probe_video_device(video_device, avctx, pixelformat, buffersize, control, count); | |
836 | + udev_device_unref(video_device); | |
837 | + | |
838 | + if (!ret) | |
839 | + break; | |
840 | + } | |
841 | + | |
842 | + av_freep(&interfaces); | |
843 | + return ret; | |
844 | + | |
845 | +fail: | |
846 | + av_freep(&interfaces); | |
847 | + if (ctx->media_fd >= 0) { | |
848 | + close(ctx->media_fd); | |
849 | + ctx->media_fd = -1; | |
850 | + } | |
851 | + return ret; | |
852 | +} | |
853 | + | |
854 | +int ff_v4l2_request_init(AVCodecContext *avctx, uint32_t pixelformat, uint32_t buffersize, struct v4l2_ext_control *control, int count) | |
855 | +{ | |
856 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
857 | + int ret = AVERROR(EINVAL); | |
858 | + struct udev *udev; | |
859 | + struct udev_enumerate *enumerate; | |
860 | + struct udev_list_entry *devices; | |
861 | + struct udev_list_entry *entry; | |
862 | + struct udev_device *device; | |
863 | + | |
864 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p hw_device_ctx=%p hw_frames_ctx=%p\n", __func__, avctx, avctx->hw_device_ctx, avctx->hw_frames_ctx); | |
865 | + | |
866 | + ctx->media_fd = -1; | |
867 | + ctx->video_fd = -1; | |
868 | + ctx->timestamp = 0; | |
869 | + | |
870 | + udev = udev_new(); | |
871 | + if (!udev) { | |
872 | + av_log(avctx, AV_LOG_ERROR, "%s: allocating udev context failed\n", __func__); | |
873 | + ret = AVERROR(ENOMEM); | |
874 | + goto fail; | |
875 | + } | |
876 | + | |
877 | + enumerate = udev_enumerate_new(udev); | |
878 | + if (!enumerate) { | |
879 | + av_log(avctx, AV_LOG_ERROR, "%s: allocating udev enumerator failed\n", __func__); | |
880 | + ret = AVERROR(ENOMEM); | |
881 | + goto fail; | |
882 | + } | |
883 | + | |
884 | + udev_enumerate_add_match_subsystem(enumerate, "media"); | |
885 | + udev_enumerate_scan_devices(enumerate); | |
886 | + | |
887 | + devices = udev_enumerate_get_list_entry(enumerate); | |
888 | + udev_list_entry_foreach(entry, devices) { | |
889 | + const char *path = udev_list_entry_get_name(entry); | |
890 | + if (!path) | |
891 | + continue; | |
892 | + | |
893 | + device = udev_device_new_from_syspath(udev, path); | |
894 | + if (!device) | |
895 | + continue; | |
896 | + | |
897 | + ret = v4l2_request_probe_media_device(device, avctx, pixelformat, buffersize, control, count); | |
898 | + udev_device_unref(device); | |
899 | + | |
900 | + if (!ret) | |
901 | + break; | |
902 | + } | |
903 | + | |
904 | + udev_enumerate_unref(enumerate); | |
905 | + | |
906 | + if (!ret) | |
907 | + ret = v4l2_request_init_context(avctx); | |
908 | + | |
909 | +fail: | |
910 | + udev_unref(udev); | |
911 | + return ret; | |
912 | +} | |
913 | + | |
914 | +int ff_v4l2_request_uninit(AVCodecContext *avctx) | |
915 | +{ | |
916 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
917 | + int ret; | |
918 | + | |
919 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p ctx=%p\n", __func__, avctx, ctx); | |
920 | + | |
921 | + if (ctx->video_fd >= 0) { | |
922 | + ret = ioctl(ctx->video_fd, VIDIOC_STREAMOFF, &ctx->output_type); | |
923 | + if (ret < 0) | |
924 | + av_log(avctx, AV_LOG_ERROR, "%s: output stream off failed, %s (%d)\n", __func__, strerror(errno), errno); | |
925 | + | |
926 | + ret = ioctl(ctx->video_fd, VIDIOC_STREAMOFF, &ctx->format.type); | |
927 | + if (ret < 0) | |
928 | + av_log(avctx, AV_LOG_ERROR, "%s: capture stream off failed, %s (%d)\n", __func__, strerror(errno), errno); | |
929 | + } | |
930 | + | |
931 | + if (avctx->hw_frames_ctx) { | |
932 | + AVHWFramesContext *hwfc = (AVHWFramesContext*)avctx->hw_frames_ctx->data; | |
933 | + av_buffer_pool_flush(hwfc->pool); | |
934 | + } | |
935 | + | |
936 | + if (ctx->video_fd >= 0) | |
937 | + close(ctx->video_fd); | |
938 | + | |
939 | + if (ctx->media_fd >= 0) | |
940 | + close(ctx->media_fd); | |
941 | + | |
942 | + return 0; | |
943 | +} | |
944 | + | |
945 | +static int v4l2_request_buffer_alloc(AVCodecContext *avctx, V4L2RequestBuffer *buf, enum v4l2_buf_type type) | |
946 | +{ | |
947 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
948 | + int ret; | |
949 | + struct v4l2_plane planes[1] = {}; | |
950 | + struct v4l2_create_buffers buffers = { | |
951 | + .count = 1, | |
952 | + .memory = V4L2_MEMORY_MMAP, | |
953 | + .format.type = type, | |
954 | + }; | |
955 | + | |
956 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p buf=%p type=%u\n", __func__, avctx, buf, type); | |
957 | + | |
958 | + ret = ioctl(ctx->video_fd, VIDIOC_G_FMT, &buffers.format); | |
959 | + if (ret < 0) { | |
960 | + av_log(avctx, AV_LOG_ERROR, "%s: get format failed for type %u, %s (%d)\n", __func__, type, strerror(errno), errno); | |
961 | + return ret; | |
962 | + } | |
963 | + | |
964 | + if (V4L2_TYPE_IS_MULTIPLANAR(buffers.format.type)) { | |
965 | + av_log(avctx, AV_LOG_DEBUG, "%s: pixelformat=%d width=%u height=%u bytesperline=%u sizeimage=%u num_planes=%u\n", __func__, buffers.format.fmt.pix_mp.pixelformat, buffers.format.fmt.pix_mp.width, buffers.format.fmt.pix_mp.height, buffers.format.fmt.pix_mp.plane_fmt[0].bytesperline, buffers.format.fmt.pix_mp.plane_fmt[0].sizeimage, buffers.format.fmt.pix_mp.num_planes); | |
966 | + } else { | |
967 | + av_log(avctx, AV_LOG_DEBUG, "%s: pixelformat=%d width=%u height=%u bytesperline=%u sizeimage=%u\n", __func__, buffers.format.fmt.pix.pixelformat, buffers.format.fmt.pix.width, buffers.format.fmt.pix.height, buffers.format.fmt.pix.bytesperline, buffers.format.fmt.pix.sizeimage); | |
968 | + } | |
969 | + | |
970 | + ret = ioctl(ctx->video_fd, VIDIOC_CREATE_BUFS, &buffers); | |
971 | + if (ret < 0) { | |
972 | + av_log(avctx, AV_LOG_ERROR, "%s: create buffers failed for type %u, %s (%d)\n", __func__, type, strerror(errno), errno); | |
973 | + return ret; | |
974 | + } | |
975 | + | |
976 | + if (V4L2_TYPE_IS_MULTIPLANAR(type)) { | |
977 | + buf->width = buffers.format.fmt.pix_mp.width; | |
978 | + buf->height = buffers.format.fmt.pix_mp.height; | |
979 | + buf->size = buffers.format.fmt.pix_mp.plane_fmt[0].sizeimage; | |
980 | + buf->buffer.length = 1; | |
981 | + buf->buffer.m.planes = planes; | |
982 | + } else { | |
983 | + buf->width = buffers.format.fmt.pix.width; | |
984 | + buf->height = buffers.format.fmt.pix.height; | |
985 | + buf->size = buffers.format.fmt.pix.sizeimage; | |
986 | + } | |
987 | + | |
988 | + buf->index = buffers.index; | |
989 | + buf->capabilities = buffers.capabilities; | |
990 | + buf->used = 0; | |
991 | + | |
992 | + buf->buffer.type = type; | |
993 | + buf->buffer.memory = V4L2_MEMORY_MMAP; | |
994 | + buf->buffer.index = buf->index; | |
995 | + | |
996 | + ret = ioctl(ctx->video_fd, VIDIOC_QUERYBUF, &buf->buffer); | |
997 | + if (ret < 0) { | |
998 | + av_log(avctx, AV_LOG_ERROR, "%s: query buffer %d failed, %s (%d)\n", __func__, buf->index, strerror(errno), errno); | |
999 | + return ret; | |
1000 | + } | |
1001 | + | |
1002 | + if (V4L2_TYPE_IS_OUTPUT(type)) { | |
1003 | + void *addr = mmap(NULL, buf->size, PROT_READ | PROT_WRITE, MAP_SHARED, ctx->video_fd, V4L2_TYPE_IS_MULTIPLANAR(type) ? buf->buffer.m.planes[0].m.mem_offset : buf->buffer.m.offset); | |
1004 | + if (addr == MAP_FAILED) { | |
1005 | + av_log(avctx, AV_LOG_ERROR, "%s: mmap failed, %s (%d)\n", __func__, strerror(errno), errno); | |
1006 | + return -1; | |
1007 | + } | |
1008 | + | |
1009 | + buf->addr = (uint8_t*)addr; | |
1010 | + } else { | |
1011 | + struct v4l2_exportbuffer exportbuffer = { | |
1012 | + .type = type, | |
1013 | + .index = buf->index, | |
1014 | + .flags = O_RDONLY, | |
1015 | + }; | |
1016 | + | |
1017 | + ret = ioctl(ctx->video_fd, VIDIOC_EXPBUF, &exportbuffer); | |
1018 | + if (ret < 0) { | |
1019 | + av_log(avctx, AV_LOG_ERROR, "%s: export buffer %d failed, %s (%d)\n", __func__, buf->index, strerror(errno), errno); | |
1020 | + return ret; | |
1021 | + } | |
1022 | + | |
1023 | + buf->fd = exportbuffer.fd; | |
1024 | + } | |
1025 | + | |
1026 | + av_log(avctx, AV_LOG_DEBUG, "%s: buf=%p index=%d fd=%d addr=%p width=%u height=%u size=%u\n", __func__, buf, buf->index, buf->fd, buf->addr, buf->width, buf->height, buf->size); | |
1027 | + return 0; | |
1028 | +} | |
1029 | + | |
1030 | +static void v4l2_request_buffer_free(V4L2RequestBuffer *buf) | |
1031 | +{ | |
1032 | + av_log(NULL, AV_LOG_DEBUG, "%s: buf=%p index=%d fd=%d addr=%p width=%u height=%u size=%u\n", __func__, buf, buf->index, buf->fd, buf->addr, buf->width, buf->height, buf->size); | |
1033 | + | |
1034 | + if (buf->addr) | |
1035 | + munmap(buf->addr, buf->size); | |
1036 | + | |
1037 | + if (buf->fd >= 0) | |
1038 | + close(buf->fd); | |
1039 | +} | |
1040 | + | |
1041 | +static void v4l2_request_frame_free(void *opaque, uint8_t *data) | |
1042 | +{ | |
1043 | + AVCodecContext *avctx = opaque; | |
1044 | + V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)data; | |
1045 | + | |
1046 | + av_log(NULL, AV_LOG_DEBUG, "%s: avctx=%p data=%p request_fd=%d\n", __func__, avctx, data, req->request_fd); | |
1047 | + | |
1048 | + if (req->request_fd >= 0) | |
1049 | + close(req->request_fd); | |
1050 | + | |
1051 | + v4l2_request_buffer_free(&req->capture); | |
1052 | + v4l2_request_buffer_free(&req->output); | |
1053 | + | |
1054 | + av_free(data); | |
1055 | +} | |
1056 | + | |
1057 | +static AVBufferRef *v4l2_request_frame_alloc(void *opaque, int size) | |
1058 | +{ | |
1059 | + AVCodecContext *avctx = opaque; | |
1060 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
1061 | + V4L2RequestDescriptor *req; | |
1062 | + AVBufferRef *ref; | |
1063 | + uint8_t *data; | |
1064 | + int ret; | |
1065 | + | |
1066 | + data = av_mallocz(size); | |
1067 | + if (!data) | |
1068 | + return NULL; | |
1069 | + | |
1070 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p size=%d data=%p\n", __func__, avctx, size, data); | |
1071 | + | |
1072 | + ref = av_buffer_create(data, size, v4l2_request_frame_free, avctx, 0); | |
1073 | + if (!ref) { | |
1074 | + av_freep(&data); | |
1075 | + return NULL; | |
1076 | + } | |
1077 | + | |
1078 | + req = (V4L2RequestDescriptor*)data; | |
1079 | + req->request_fd = -1; | |
1080 | + req->output.fd = -1; | |
1081 | + req->capture.fd = -1; | |
1082 | + | |
1083 | + ret = v4l2_request_buffer_alloc(avctx, &req->output, ctx->output_type); | |
1084 | + if (ret < 0) { | |
1085 | + av_buffer_unref(&ref); | |
1086 | + return NULL; | |
1087 | + } | |
1088 | + | |
1089 | + ret = v4l2_request_buffer_alloc(avctx, &req->capture, ctx->format.type); | |
1090 | + if (ret < 0) { | |
1091 | + av_buffer_unref(&ref); | |
1092 | + return NULL; | |
1093 | + } | |
1094 | + | |
1095 | + ret = ioctl(ctx->media_fd, MEDIA_IOC_REQUEST_ALLOC, &req->request_fd); | |
1096 | + if (ret < 0) { | |
1097 | + av_log(avctx, AV_LOG_ERROR, "%s: request alloc failed, %s (%d)\n", __func__, strerror(errno), errno); | |
1098 | + av_buffer_unref(&ref); | |
1099 | + return NULL; | |
1100 | + } | |
1101 | + | |
1102 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p size=%d data=%p request_fd=%d\n", __func__, avctx, size, data, req->request_fd); | |
1103 | + return ref; | |
1104 | +} | |
1105 | + | |
1106 | +static void v4l2_request_pool_free(void *opaque) | |
1107 | +{ | |
1108 | + av_log(NULL, AV_LOG_DEBUG, "%s: opaque=%p\n", __func__, opaque); | |
1109 | +} | |
1110 | + | |
1111 | +static void v4l2_request_hwframe_ctx_free(AVHWFramesContext *hwfc) | |
1112 | +{ | |
1113 | + av_log(NULL, AV_LOG_DEBUG, "%s: hwfc=%p pool=%p\n", __func__, hwfc, hwfc->pool); | |
1114 | + | |
1115 | + av_buffer_pool_flush(hwfc->pool); | |
1116 | + av_buffer_pool_uninit(&hwfc->pool); | |
1117 | +} | |
1118 | + | |
1119 | +int ff_v4l2_request_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) | |
1120 | +{ | |
1121 | + V4L2RequestContext *ctx = avctx->internal->hwaccel_priv_data; | |
1122 | + AVHWFramesContext *hwfc = (AVHWFramesContext*)hw_frames_ctx->data; | |
1123 | + | |
1124 | + hwfc->format = AV_PIX_FMT_DRM_PRIME; | |
1125 | + hwfc->sw_format = AV_PIX_FMT_NV12; | |
1126 | + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->format.type)) { | |
1127 | + hwfc->width = ctx->format.fmt.pix_mp.width; | |
1128 | + hwfc->height = ctx->format.fmt.pix_mp.height; | |
1129 | + } else { | |
1130 | + hwfc->width = ctx->format.fmt.pix.width; | |
1131 | + hwfc->height = ctx->format.fmt.pix.height; | |
1132 | + } | |
1133 | + | |
1134 | + hwfc->pool = av_buffer_pool_init2(sizeof(V4L2RequestDescriptor), avctx, v4l2_request_frame_alloc, v4l2_request_pool_free); | |
1135 | + if (!hwfc->pool) | |
1136 | + return AVERROR(ENOMEM); | |
1137 | + | |
1138 | + hwfc->free = v4l2_request_hwframe_ctx_free; | |
1139 | + | |
1140 | + hwfc->initial_pool_size = 1; | |
1141 | + | |
1142 | + switch (avctx->codec_id) { | |
1143 | + case AV_CODEC_ID_VP9: | |
1144 | + hwfc->initial_pool_size += 8; | |
1145 | + break; | |
1146 | + case AV_CODEC_ID_VP8: | |
1147 | + hwfc->initial_pool_size += 3; | |
1148 | + break; | |
1149 | + default: | |
1150 | + hwfc->initial_pool_size += 2; | |
1151 | + } | |
1152 | + | |
1153 | + av_log(avctx, AV_LOG_DEBUG, "%s: avctx=%p ctx=%p hw_frames_ctx=%p hwfc=%p pool=%p width=%d height=%d initial_pool_size=%d\n", __func__, avctx, ctx, hw_frames_ctx, hwfc, hwfc->pool, hwfc->width, hwfc->height, hwfc->initial_pool_size); | |
1154 | + | |
1155 | + return 0; | |
1156 | +} | |
1157 | diff --git a/libavcodec/v4l2_request.h b/libavcodec/v4l2_request.h | |
1158 | new file mode 100644 | |
1159 | index 000000000000..58d2aa70af80 | |
1160 | --- /dev/null | |
1161 | +++ b/libavcodec/v4l2_request.h | |
1162 | @@ -0,0 +1,77 @@ | |
1163 | +/* | |
1164 | + * This file is part of FFmpeg. | |
1165 | + * | |
1166 | + * FFmpeg is free software; you can redistribute it and/or | |
1167 | + * modify it under the terms of the GNU Lesser General Public | |
1168 | + * License as published by the Free Software Foundation; either | |
1169 | + * version 2.1 of the License, or (at your option) any later version. | |
1170 | + * | |
1171 | + * FFmpeg is distributed in the hope that it will be useful, | |
1172 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1173 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
1174 | + * Lesser General Public License for more details. | |
1175 | + * | |
1176 | + * You should have received a copy of the GNU Lesser General Public | |
1177 | + * License along with FFmpeg; if not, write to the Free Software | |
1178 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
1179 | + */ | |
1180 | + | |
1181 | +#ifndef AVCODEC_V4L2_REQUEST_H | |
1182 | +#define AVCODEC_V4L2_REQUEST_H | |
1183 | + | |
1184 | +#include <linux/videodev2.h> | |
1185 | + | |
1186 | +#include "libavutil/hwcontext_drm.h" | |
1187 | + | |
1188 | +typedef struct V4L2RequestContext { | |
1189 | + int video_fd; | |
1190 | + int media_fd; | |
1191 | + enum v4l2_buf_type output_type; | |
1192 | + struct v4l2_format format; | |
1193 | + int timestamp; | |
1194 | +} V4L2RequestContext; | |
1195 | + | |
1196 | +typedef struct V4L2RequestBuffer { | |
1197 | + int index; | |
1198 | + int fd; | |
1199 | + uint8_t *addr; | |
1200 | + uint32_t width; | |
1201 | + uint32_t height; | |
1202 | + uint32_t size; | |
1203 | + uint32_t used; | |
1204 | + uint32_t capabilities; | |
1205 | + struct v4l2_buffer buffer; | |
1206 | +} V4L2RequestBuffer; | |
1207 | + | |
1208 | +typedef struct V4L2RequestDescriptor { | |
1209 | + AVDRMFrameDescriptor drm; | |
1210 | + int request_fd; | |
1211 | + V4L2RequestBuffer output; | |
1212 | + V4L2RequestBuffer capture; | |
1213 | +} V4L2RequestDescriptor; | |
1214 | + | |
1215 | +uint64_t ff_v4l2_request_get_capture_timestamp(AVFrame *frame); | |
1216 | + | |
1217 | +int ff_v4l2_request_reset_frame(AVCodecContext *avctx, AVFrame *frame); | |
1218 | + | |
1219 | +int ff_v4l2_request_append_output_buffer(AVCodecContext *avctx, AVFrame *frame, const uint8_t *data, uint32_t size); | |
1220 | + | |
1221 | +int ff_v4l2_request_set_controls(AVCodecContext *avctx, struct v4l2_ext_control *control, int count); | |
1222 | + | |
1223 | +int ff_v4l2_request_get_controls(AVCodecContext *avctx, struct v4l2_ext_control *control, int count); | |
1224 | + | |
1225 | +int ff_v4l2_request_query_control(AVCodecContext *avctx, struct v4l2_query_ext_ctrl *control); | |
1226 | + | |
1227 | +int ff_v4l2_request_query_control_default_value(AVCodecContext *avctx, uint32_t id); | |
1228 | + | |
1229 | +int ff_v4l2_request_decode_slice(AVCodecContext *avctx, AVFrame *frame, struct v4l2_ext_control *control, int count, int first_slice, int last_slice); | |
1230 | + | |
1231 | +int ff_v4l2_request_decode_frame(AVCodecContext *avctx, AVFrame *frame, struct v4l2_ext_control *control, int count); | |
1232 | + | |
1233 | +int ff_v4l2_request_init(AVCodecContext *avctx, uint32_t pixelformat, uint32_t buffersize, struct v4l2_ext_control *control, int count); | |
1234 | + | |
1235 | +int ff_v4l2_request_uninit(AVCodecContext *avctx); | |
1236 | + | |
1237 | +int ff_v4l2_request_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx); | |
1238 | + | |
1239 | +#endif /* AVCODEC_V4L2_REQUEST_H */ | |
1240 | From a0a5b816593e3911aeedd201baa8057b64a89a39 Mon Sep 17 00:00:00 2001 | |
1241 | From: Ezequiel Garcia <ezequiel@collabora.com> | |
1242 | Date: Wed, 20 Feb 2019 11:18:00 -0300 | |
1243 | Subject: [PATCH] h264dec: add idr_pic_id to slice context | |
1244 | ||
1245 | Used by V4L2 request API h264 hwaccel | |
1246 | ||
1247 | Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com> | |
1248 | Signed-off-by: Jonas Karlman <jonas@kwiboo.se> | |
1249 | --- | |
1250 | libavcodec/h264_slice.c | 2 +- | |
1251 | libavcodec/h264dec.h | 1 + | |
1252 | 2 files changed, 2 insertions(+), 1 deletion(-) | |
1253 | ||
1254 | diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c | |
1255 | index db8363e4cc98..a19635a23d44 100644 | |
1256 | --- a/libavcodec/h264_slice.c | |
1257 | +++ b/libavcodec/h264_slice.c | |
1258 | @@ -1818,7 +1818,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, | |
1259 | } | |
1260 | ||
1261 | if (nal->type == H264_NAL_IDR_SLICE) | |
1262 | - get_ue_golomb_long(&sl->gb); /* idr_pic_id */ | |
1263 | + sl->idr_pic_id = get_ue_golomb_long(&sl->gb); | |
1264 | ||
1265 | if (sps->poc_type == 0) { | |
1266 | sl->poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb); | |
1267 | diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h | |
1268 | index a419615124b2..316dc6a2c890 100644 | |
1269 | --- a/libavcodec/h264dec.h | |
1270 | +++ b/libavcodec/h264dec.h | |
1271 | @@ -335,6 +335,7 @@ typedef struct H264SliceContext { | |
1272 | int delta_poc[2]; | |
1273 | int curr_pic_num; | |
1274 | int max_pic_num; | |
1275 | + int idr_pic_id; | |
1276 | } H264SliceContext; | |
1277 | ||
1278 | /** | |
1279 | From 6349ae1e10d1b68c47c3b883b27567f9678c6e0c Mon Sep 17 00:00:00 2001 | |
1280 | From: Boris Brezillon <boris.brezillon@collabora.com> | |
1281 | Date: Wed, 22 May 2019 14:44:22 +0200 | |
1282 | Subject: [PATCH] h264dec: add ref_pic_marking and pic_order_cnt bit_size to | |
1283 | slice context | |
1284 | ||
1285 | Used by V4L2 request API h264 hwaccel | |
1286 | ||
1287 | Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> | |
1288 | Signed-off-by: Jonas Karlman <jonas@kwiboo.se> | |
1289 | --- | |
1290 | libavcodec/h264_slice.c | 6 +++++- | |
1291 | libavcodec/h264dec.h | 2 ++ | |
1292 | 2 files changed, 7 insertions(+), 1 deletion(-) | |
1293 | ||
1294 | diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c | |
1295 | index a19635a23d44..5a5ceb09352c 100644 | |
1296 | --- a/libavcodec/h264_slice.c | |
1297 | +++ b/libavcodec/h264_slice.c | |
1298 | @@ -1736,7 +1736,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, | |
1299 | unsigned int slice_type, tmp, i; | |
1300 | int field_pic_flag, bottom_field_flag; | |
1301 | int first_slice = sl == h->slice_ctx && !h->current_slice; | |
1302 | - int picture_structure; | |
1303 | + int picture_structure, pos; | |
1304 | ||
1305 | if (first_slice) | |
1306 | av_assert0(!h->setup_finished); | |
1307 | @@ -1820,6 +1820,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, | |
1308 | if (nal->type == H264_NAL_IDR_SLICE) | |
1309 | sl->idr_pic_id = get_ue_golomb_long(&sl->gb); | |
1310 | ||
1311 | + pos = sl->gb.index; | |
1312 | if (sps->poc_type == 0) { | |
1313 | sl->poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb); | |
1314 | ||
1315 | @@ -1833,6 +1834,7 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, | |
1316 | if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) | |
1317 | sl->delta_poc[1] = get_se_golomb(&sl->gb); | |
1318 | } | |
1319 | + sl->pic_order_cnt_bit_size = sl->gb.index - pos; | |
1320 | ||
1321 | sl->redundant_pic_count = 0; | |
1322 | if (pps->redundant_pic_cnt_present) | |
1323 | @@ -1872,9 +1874,11 @@ static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, | |
1324 | ||
1325 | sl->explicit_ref_marking = 0; | |
1326 | if (nal->ref_idc) { | |
1327 | + pos = sl->gb.index; | |
1328 | ret = ff_h264_decode_ref_pic_marking(sl, &sl->gb, nal, h->avctx); | |
1329 | if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) | |
1330 | return AVERROR_INVALIDDATA; | |
1331 | + sl->ref_pic_marking_bit_size = sl->gb.index - pos; | |
1332 | } | |
1333 | ||
1334 | if (sl->slice_type_nos != AV_PICTURE_TYPE_I && pps->cabac) { | |
1335 | diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h | |
1336 | index 316dc6a2c890..f2cabac468d0 100644 | |
1337 | --- a/libavcodec/h264dec.h | |
1338 | +++ b/libavcodec/h264dec.h | |
1339 | @@ -328,6 +328,7 @@ typedef struct H264SliceContext { | |
1340 | MMCO mmco[MAX_MMCO_COUNT]; | |
1341 | int nb_mmco; | |
1342 | int explicit_ref_marking; | |
1343 | + int ref_pic_marking_bit_size; | |
1344 | ||
1345 | int frame_num; | |
1346 | int poc_lsb; | |
1347 | @@ -336,6 +337,7 @@ typedef struct H264SliceContext { | |
1348 | int curr_pic_num; | |
1349 | int max_pic_num; | |
1350 | int idr_pic_id; | |
1351 | + int pic_order_cnt_bit_size; | |
1352 | } H264SliceContext; | |
1353 | ||
1354 | /** | |
1355 | From 650875c24687c35290b2393ef39f77074ca49813 Mon Sep 17 00:00:00 2001 | |
1356 | From: Jernej Skrabec <jernej.skrabec@siol.net> | |
1357 | Date: Sat, 15 Dec 2018 22:32:16 +0100 | |
1358 | Subject: [PATCH] Add V4L2 request API h264 hwaccel | |
1359 | ||
1360 | Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net> | |
1361 | Signed-off-by: Jonas Karlman <jonas@kwiboo.se> | |
1362 | --- | |
1363 | configure | 3 + | |
1364 | libavcodec/Makefile | 1 + | |
1365 | libavcodec/h264_slice.c | 4 + | |
1366 | libavcodec/h264dec.c | 3 + | |
1367 | libavcodec/hwaccels.h | 1 + | |
1368 | libavcodec/v4l2_request_h264.c | 456 +++++++++++++++++++++++++++++++++ | |
1369 | 6 files changed, 468 insertions(+) | |
1370 | create mode 100644 libavcodec/v4l2_request_h264.c | |
1371 | ||
1372 | diff --git a/configure b/configure | |
1373 | index 9f9909a23696..293d0447f683 100755 | |
1374 | --- a/configure | |
1375 | +++ b/configure | |
1376 | @@ -2925,6 +2925,8 @@ h264_dxva2_hwaccel_deps="dxva2" | |
1377 | h264_dxva2_hwaccel_select="h264_decoder" | |
1378 | h264_nvdec_hwaccel_deps="nvdec" | |
1379 | h264_nvdec_hwaccel_select="h264_decoder" | |
1380 | +h264_v4l2request_hwaccel_deps="v4l2_request" | |
1381 | +h264_v4l2request_hwaccel_select="h264_decoder" | |
1382 | h264_vaapi_hwaccel_deps="vaapi" | |
1383 | h264_vaapi_hwaccel_select="h264_decoder" | |
1384 | h264_vdpau_hwaccel_deps="vdpau" | |
1385 | @@ -6567,6 +6569,7 @@ if enabled v4l2_m2m; then | |
1386 | fi | |
1387 | ||
1388 | check_func_headers "linux/media.h linux/videodev2.h" v4l2_timeval_to_ns | |
1389 | +check_cc h264_v4l2_request linux/videodev2.h "int i = V4L2_PIX_FMT_H264_SLICE;" | |
1390 | ||
1391 | check_headers sys/videoio.h | |
1392 | test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete | |
1393 | diff --git a/libavcodec/Makefile b/libavcodec/Makefile | |
1394 | index d74220516826..4f6e7fc2515c 100644 | |
1395 | --- a/libavcodec/Makefile | |
1396 | +++ b/libavcodec/Makefile | |
1397 | @@ -903,6 +903,7 @@ OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o | |
1398 | OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o | |
1399 | OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o | |
60ce8543 | 1400 | OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec.o |
80105e83 JP |
1401 | +OBJS-$(CONFIG_H264_V4L2REQUEST_HWACCEL) += v4l2_request_h264.o |
1402 | OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o | |
1403 | OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o | |
1404 | OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o | |
1405 | diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c | |
1406 | index 5a5ceb09352c..4ed267317184 100644 | |
1407 | --- a/libavcodec/h264_slice.c | |
1408 | +++ b/libavcodec/h264_slice.c | |
1409 | @@ -759,6 +759,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) | |
1410 | #define HWACCEL_MAX (CONFIG_H264_DXVA2_HWACCEL + \ | |
1411 | (CONFIG_H264_D3D11VA_HWACCEL * 2) + \ | |
1412 | CONFIG_H264_NVDEC_HWACCEL + \ | |
1413 | + CONFIG_H264_V4L2REQUEST_HWACCEL + \ | |
1414 | CONFIG_H264_VAAPI_HWACCEL + \ | |
1415 | CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \ | |
1416 | CONFIG_H264_VDPAU_HWACCEL) | |
1417 | @@ -843,6 +844,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) | |
1418 | #endif | |
1419 | #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL | |
1420 | *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; | |
1421 | +#endif | |
1422 | +#if CONFIG_H264_V4L2REQUEST_HWACCEL | |
1423 | + *fmt++ = AV_PIX_FMT_DRM_PRIME; | |
1424 | #endif | |
1425 | if (h->avctx->codec->pix_fmts) | |
1426 | choices = h->avctx->codec->pix_fmts; | |
1427 | diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c | |
1428 | index 5eedeb3c275d..a504c89565c7 100644 | |
1429 | --- a/libavcodec/h264dec.c | |
1430 | +++ b/libavcodec/h264dec.c | |
1431 | @@ -1102,6 +1102,9 @@ AVCodec ff_h264_decoder = { | |
1432 | #endif | |
1433 | #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL | |
1434 | HWACCEL_VIDEOTOOLBOX(h264), | |
1435 | +#endif | |
1436 | +#if CONFIG_H264_V4L2REQUEST_HWACCEL | |
1437 | + HWACCEL_V4L2REQUEST(h264), | |
1438 | #endif | |
1439 | NULL | |
1440 | }, | |
1441 | diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h | |
1442 | index 6109c89bd63c..f758c34ddcf9 100644 | |
1443 | --- a/libavcodec/hwaccels.h | |
1444 | +++ b/libavcodec/hwaccels.h | |
1445 | @@ -27,6 +27,7 @@ extern const AVHWAccel ff_h264_d3d11va_hwaccel; | |
1446 | extern const AVHWAccel ff_h264_d3d11va2_hwaccel; | |
1447 | extern const AVHWAccel ff_h264_dxva2_hwaccel; | |
1448 | extern const AVHWAccel ff_h264_nvdec_hwaccel; | |
1449 | +extern const AVHWAccel ff_h264_v4l2request_hwaccel; | |
1450 | extern const AVHWAccel ff_h264_vaapi_hwaccel; | |
1451 | extern const AVHWAccel ff_h264_vdpau_hwaccel; | |
1452 | extern const AVHWAccel ff_h264_videotoolbox_hwaccel; | |
1453 | diff --git a/libavcodec/v4l2_request_h264.c b/libavcodec/v4l2_request_h264.c | |
1454 | new file mode 100644 | |
1455 | index 000000000000..88da8f0a2db0 | |
1456 | --- /dev/null | |
1457 | +++ b/libavcodec/v4l2_request_h264.c | |
1458 | @@ -0,0 +1,456 @@ | |
1459 | +/* | |
1460 | + * This file is part of FFmpeg. | |
1461 | + * | |
1462 | + * FFmpeg is free software; you can redistribute it and/or | |
1463 | + * modify it under the terms of the GNU Lesser General Public | |
1464 | + * License as published by the Free Software Foundation; either | |
1465 | + * version 2.1 of the License, or (at your option) any later version. | |
1466 | + * | |
1467 | + * FFmpeg is distributed in the hope that it will be useful, | |
1468 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1469 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
1470 | + * Lesser General Public License for more details. | |
1471 | + * | |
1472 | + * You should have received a copy of the GNU Lesser General Public | |
1473 | + * License along with FFmpeg; if not, write to the Free Software | |
1474 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
1475 | + */ | |
1476 | + | |
1477 | +#include "h264dec.h" | |
1478 | +#include "hwconfig.h" | |
1479 | +#include "v4l2_request.h" | |
1480 | + | |
1481 | +typedef struct V4L2RequestControlsH264 { | |
1482 | + struct v4l2_ctrl_h264_sps sps; | |
1483 | + struct v4l2_ctrl_h264_pps pps; | |
1484 | + struct v4l2_ctrl_h264_scaling_matrix scaling_matrix; | |
1485 | + struct v4l2_ctrl_h264_decode_params decode_params; | |
1486 | + struct v4l2_ctrl_h264_slice_params slice_params; | |
1487 | + struct v4l2_ctrl_h264_pred_weights pred_weights; | |
1488 | + int pred_weights_required; | |
1489 | + int first_slice; | |
1490 | + int num_slices; | |
1491 | +} V4L2RequestControlsH264; | |
1492 | + | |
1493 | +typedef struct V4L2RequestContextH264 { | |
1494 | + V4L2RequestContext base; | |
1495 | + int decode_mode; | |
1496 | + int start_code; | |
1497 | +} V4L2RequestContextH264; | |
1498 | + | |
1499 | +static uint8_t nalu_slice_start_code[] = { 0x00, 0x00, 0x01 }; | |
1500 | + | |
1501 | +static void fill_weight_factors(struct v4l2_h264_weight_factors *factors, int list, const H264SliceContext *sl) | |
1502 | +{ | |
1503 | + for (int i = 0; i < sl->ref_count[list]; i++) { | |
1504 | + if (sl->pwt.luma_weight_flag[list]) { | |
1505 | + factors->luma_weight[i] = sl->pwt.luma_weight[i][list][0]; | |
1506 | + factors->luma_offset[i] = sl->pwt.luma_weight[i][list][1]; | |
1507 | + } else { | |
1508 | + factors->luma_weight[i] = 1 << sl->pwt.luma_log2_weight_denom; | |
1509 | + factors->luma_offset[i] = 0; | |
1510 | + } | |
1511 | + for (int j = 0; j < 2; j++) { | |
1512 | + if (sl->pwt.chroma_weight_flag[list]) { | |
1513 | + factors->chroma_weight[i][j] = sl->pwt.chroma_weight[i][list][j][0]; | |
1514 | + factors->chroma_offset[i][j] = sl->pwt.chroma_weight[i][list][j][1]; | |
1515 | + } else { | |
1516 | + factors->chroma_weight[i][j] = 1 << sl->pwt.chroma_log2_weight_denom; | |
1517 | + factors->chroma_offset[i][j] = 0; | |
1518 | + } | |
1519 | + } | |
1520 | + } | |
1521 | +} | |
1522 | + | |
1523 | +static void fill_dpb_entry(struct v4l2_h264_dpb_entry *entry, const H264Picture *pic) | |
1524 | +{ | |
1525 | + entry->reference_ts = ff_v4l2_request_get_capture_timestamp(pic->f); | |
1526 | + entry->pic_num = pic->pic_id; | |
1527 | + entry->frame_num = pic->frame_num; | |
1528 | + entry->fields = pic->reference & V4L2_H264_FRAME_REF; | |
1529 | + entry->flags = V4L2_H264_DPB_ENTRY_FLAG_VALID; | |
1530 | + if (entry->fields) | |
1531 | + entry->flags |= V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; | |
1532 | + if (pic->long_ref) | |
1533 | + entry->flags |= V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM; | |
1534 | + if (pic->field_picture) | |
1535 | + entry->flags |= V4L2_H264_DPB_ENTRY_FLAG_FIELD; | |
1536 | + if (pic->field_poc[0] != INT_MAX) | |
1537 | + entry->top_field_order_cnt = pic->field_poc[0]; | |
1538 | + if (pic->field_poc[1] != INT_MAX) | |
1539 | + entry->bottom_field_order_cnt = pic->field_poc[1]; | |
1540 | +} | |
1541 | + | |
1542 | +static void fill_dpb(struct v4l2_ctrl_h264_decode_params *decode, const H264Context *h) | |
1543 | +{ | |
1544 | + int entries = 0; | |
1545 | + | |
1546 | + for (int i = 0; i < h->short_ref_count; i++) { | |
1547 | + const H264Picture *pic = h->short_ref[i]; | |
1548 | + if (pic && (pic->field_poc[0] != INT_MAX || pic->field_poc[1] != INT_MAX)) | |
1549 | + fill_dpb_entry(&decode->dpb[entries++], pic); | |
1550 | + } | |
1551 | + | |
1552 | + if (!h->long_ref_count) | |
1553 | + return; | |
1554 | + | |
1555 | + for (int i = 0; i < FF_ARRAY_ELEMS(h->long_ref); i++) { | |
1556 | + const H264Picture *pic = h->long_ref[i]; | |
1557 | + if (pic && (pic->field_poc[0] != INT_MAX || pic->field_poc[1] != INT_MAX)) | |
1558 | + fill_dpb_entry(&decode->dpb[entries++], pic); | |
1559 | + } | |
1560 | +} | |
1561 | + | |
1562 | +static void fill_ref_list(struct v4l2_h264_reference *reference, struct v4l2_ctrl_h264_decode_params *decode, const H264Ref *ref) | |
1563 | +{ | |
1564 | + uint64_t timestamp; | |
1565 | + | |
1566 | + if (!ref->parent) | |
1567 | + return; | |
1568 | + | |
1569 | + timestamp = ff_v4l2_request_get_capture_timestamp(ref->parent->f); | |
1570 | + | |
1571 | + for (uint8_t i = 0; i < FF_ARRAY_ELEMS(decode->dpb); i++) { | |
1572 | + struct v4l2_h264_dpb_entry *entry = &decode->dpb[i]; | |
1573 | + if ((entry->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID) && | |
1574 | + entry->reference_ts == timestamp) { | |
1575 | + reference->fields = ref->reference & V4L2_H264_FRAME_REF; | |
1576 | + reference->index = i; | |
1577 | + return; | |
1578 | + } | |
1579 | + } | |
1580 | +} | |
1581 | + | |
1582 | +static void fill_sps(struct v4l2_ctrl_h264_sps *ctrl, const H264Context *h) | |
1583 | +{ | |
1584 | + const SPS *sps = h->ps.sps; | |
1585 | + | |
1586 | + *ctrl = (struct v4l2_ctrl_h264_sps) { | |
1587 | + .profile_idc = sps->profile_idc, | |
1588 | + .constraint_set_flags = sps->constraint_set_flags, | |
1589 | + .level_idc = sps->level_idc, | |
1590 | + .seq_parameter_set_id = sps->sps_id, | |
1591 | + .chroma_format_idc = sps->chroma_format_idc, | |
1592 | + .bit_depth_luma_minus8 = sps->bit_depth_luma - 8, | |
1593 | + .bit_depth_chroma_minus8 = sps->bit_depth_chroma - 8, | |
1594 | + .log2_max_frame_num_minus4 = sps->log2_max_frame_num - 4, | |
1595 | + .pic_order_cnt_type = sps->poc_type, | |
1596 | + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_poc_lsb - 4, | |
1597 | + .max_num_ref_frames = sps->ref_frame_count, | |
1598 | + .num_ref_frames_in_pic_order_cnt_cycle = sps->poc_cycle_length, | |
1599 | + .offset_for_non_ref_pic = sps->offset_for_non_ref_pic, | |
1600 | + .offset_for_top_to_bottom_field = sps->offset_for_top_to_bottom_field, | |
1601 | + .pic_width_in_mbs_minus1 = h->mb_width - 1, | |
1602 | + .pic_height_in_map_units_minus1 = sps->frame_mbs_only_flag ? h->mb_height - 1 : h->mb_height / 2 - 1, | |
1603 | + }; | |
1604 | + | |
1605 | + if (sps->poc_cycle_length > 0 && sps->poc_cycle_length <= 255) | |
1606 | + memcpy(ctrl->offset_for_ref_frame, sps->offset_for_ref_frame, sps->poc_cycle_length * sizeof(ctrl->offset_for_ref_frame[0])); | |
1607 | + | |
1608 | + if (sps->residual_color_transform_flag) | |
1609 | + ctrl->flags |= V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE; | |
1610 | + if (sps->transform_bypass) | |
1611 | + ctrl->flags |= V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS; | |
1612 | + if (sps->delta_pic_order_always_zero_flag) | |
1613 | + ctrl->flags |= V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO; | |
1614 | + if (sps->gaps_in_frame_num_allowed_flag) | |
1615 | + ctrl->flags |= V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED; | |
1616 | + if (sps->frame_mbs_only_flag) | |
1617 | + ctrl->flags |= V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY; | |
1618 | + if (sps->mb_aff) | |
1619 | + ctrl->flags |= V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD; | |
1620 | + if (sps->direct_8x8_inference_flag) | |
1621 | + ctrl->flags |= V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE; | |
1622 | +} | |
1623 | + | |
1624 | +static void fill_pps(struct v4l2_ctrl_h264_pps *ctrl, const H264Context *h) | |
1625 | +{ | |
1626 | + const SPS *sps = h->ps.sps; | |
1627 | + const PPS *pps = h->ps.pps; | |
1628 | + const H264SliceContext *sl = &h->slice_ctx[0]; | |
1629 | + int qp_bd_offset = 6 * (sps->bit_depth_luma - 8); | |
1630 | + | |
1631 | + *ctrl = (struct v4l2_ctrl_h264_pps) { | |
1632 | + .pic_parameter_set_id = sl->pps_id, | |
1633 | + .seq_parameter_set_id = pps->sps_id, | |
1634 | + .num_slice_groups_minus1 = pps->slice_group_count - 1, | |
1635 | + .num_ref_idx_l0_default_active_minus1 = pps->ref_count[0] - 1, | |
1636 | + .num_ref_idx_l1_default_active_minus1 = pps->ref_count[1] - 1, | |
1637 | + .weighted_bipred_idc = pps->weighted_bipred_idc, | |
1638 | + .pic_init_qp_minus26 = pps->init_qp - 26 - qp_bd_offset, | |
1639 | + .pic_init_qs_minus26 = pps->init_qs - 26 - qp_bd_offset, | |
1640 | + .chroma_qp_index_offset = pps->chroma_qp_index_offset[0], | |
1641 | + .second_chroma_qp_index_offset = pps->chroma_qp_index_offset[1], | |
1642 | + }; | |
1643 | + | |
1644 | + if (pps->cabac) | |
1645 | + ctrl->flags |= V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE; | |
1646 | + if (pps->pic_order_present) | |
1647 | + ctrl->flags |= V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT; | |
1648 | + if (pps->weighted_pred) | |
1649 | + ctrl->flags |= V4L2_H264_PPS_FLAG_WEIGHTED_PRED; | |
1650 | + if (pps->deblocking_filter_parameters_present) | |
1651 | + ctrl->flags |= V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT; | |
1652 | + if (pps->constrained_intra_pred) | |
1653 | + ctrl->flags |= V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED; | |
1654 | + if (pps->redundant_pic_cnt_present) | |
1655 | + ctrl->flags |= V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT; | |
1656 | + if (pps->transform_8x8_mode) | |
1657 | + ctrl->flags |= V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE; | |
1658 | + | |
1659 | + /* FFmpeg always provide a scaling matrix */ | |
1660 | + ctrl->flags |= V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT; | |
1661 | +} | |
1662 | + | |
1663 | +static int v4l2_request_h264_start_frame(AVCodecContext *avctx, | |
1664 | + av_unused const uint8_t *buffer, | |
1665 | + av_unused uint32_t size) | |
1666 | +{ | |
1667 | + const H264Context *h = avctx->priv_data; | |
1668 | + const PPS *pps = h->ps.pps; | |
1669 | + const SPS *sps = h->ps.sps; | |
1670 | + const H264SliceContext *sl = &h->slice_ctx[0]; | |
1671 | + V4L2RequestControlsH264 *controls = h->cur_pic_ptr->hwaccel_picture_private; | |
1672 | + | |
1673 | + fill_sps(&controls->sps, h); | |
1674 | + fill_pps(&controls->pps, h); | |
1675 | + | |
1676 | + memcpy(controls->scaling_matrix.scaling_list_4x4, pps->scaling_matrix4, sizeof(controls->scaling_matrix.scaling_list_4x4)); | |
1677 | + memcpy(controls->scaling_matrix.scaling_list_8x8[0], pps->scaling_matrix8[0], sizeof(controls->scaling_matrix.scaling_list_8x8[0])); | |
1678 | + memcpy(controls->scaling_matrix.scaling_list_8x8[1], pps->scaling_matrix8[3], sizeof(controls->scaling_matrix.scaling_list_8x8[1])); | |
1679 | + | |
1680 | + if (sps->chroma_format_idc == 3) { | |
1681 | + memcpy(controls->scaling_matrix.scaling_list_8x8[2], pps->scaling_matrix8[1], sizeof(controls->scaling_matrix.scaling_list_8x8[2])); | |
1682 | + memcpy(controls->scaling_matrix.scaling_list_8x8[3], pps->scaling_matrix8[4], sizeof(controls->scaling_matrix.scaling_list_8x8[3])); | |
1683 | + memcpy(controls->scaling_matrix.scaling_list_8x8[4], pps->scaling_matrix8[2], sizeof(controls->scaling_matrix.scaling_list_8x8[4])); | |
1684 | + memcpy(controls->scaling_matrix.scaling_list_8x8[5], pps->scaling_matrix8[5], sizeof(controls->scaling_matrix.scaling_list_8x8[5])); | |
1685 | + } | |
1686 | + | |
1687 | + controls->decode_params = (struct v4l2_ctrl_h264_decode_params) { | |
1688 | + .nal_ref_idc = h->nal_ref_idc, | |
1689 | + .frame_num = h->poc.frame_num, | |
1690 | + .top_field_order_cnt = h->cur_pic_ptr->field_poc[0] != INT_MAX ? h->cur_pic_ptr->field_poc[0] : 0, | |
1691 | + .bottom_field_order_cnt = h->cur_pic_ptr->field_poc[1] != INT_MAX ? h->cur_pic_ptr->field_poc[1] : 0, | |
1692 | + .idr_pic_id = sl->idr_pic_id, | |
1693 | + .pic_order_cnt_lsb = sl->poc_lsb, | |
1694 | + .delta_pic_order_cnt_bottom = sl->delta_poc_bottom, | |
1695 | + .delta_pic_order_cnt0 = sl->delta_poc[0], | |
1696 | + .delta_pic_order_cnt1 = sl->delta_poc[1], | |
1697 | + /* Size in bits of dec_ref_pic_marking() syntax element. */ | |
1698 | + .dec_ref_pic_marking_bit_size = sl->ref_pic_marking_bit_size, | |
1699 | + /* Size in bits of pic order count syntax. */ | |
1700 | + .pic_order_cnt_bit_size = sl->pic_order_cnt_bit_size, | |
1701 | + .slice_group_change_cycle = 0, /* slice group not supported by FFmpeg */ | |
1702 | + }; | |
1703 | + | |
1704 | + if (h->picture_idr) | |
1705 | + controls->decode_params.flags |= V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC; | |
1706 | + if (FIELD_PICTURE(h)) | |
1707 | + controls->decode_params.flags |= V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC; | |
1708 | + if (h->picture_structure == PICT_BOTTOM_FIELD) | |
1709 | + controls->decode_params.flags |= V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD; | |
1710 | + | |
1711 | + fill_dpb(&controls->decode_params, h); | |
1712 | + | |
1713 | + controls->first_slice = !FIELD_PICTURE(h) || h->first_field; | |
1714 | + controls->num_slices = 0; | |
1715 | + | |
1716 | + return ff_v4l2_request_reset_frame(avctx, h->cur_pic_ptr->f); | |
1717 | +} | |
1718 | + | |
1719 | +static int v4l2_request_h264_queue_decode(AVCodecContext *avctx, int last_slice) | |
1720 | +{ | |
1721 | + const H264Context *h = avctx->priv_data; | |
1722 | + V4L2RequestControlsH264 *controls = h->cur_pic_ptr->hwaccel_picture_private; | |
1723 | + V4L2RequestContextH264 *ctx = avctx->internal->hwaccel_priv_data; | |
1724 | + | |
1725 | + struct v4l2_ext_control control[] = { | |
1726 | + { | |
1727 | + .id = V4L2_CID_STATELESS_H264_SPS, | |
1728 | + .ptr = &controls->sps, | |
1729 | + .size = sizeof(controls->sps), | |
1730 | + }, | |
1731 | + { | |
1732 | + .id = V4L2_CID_STATELESS_H264_PPS, | |
1733 | + .ptr = &controls->pps, | |
1734 | + .size = sizeof(controls->pps), | |
1735 | + }, | |
1736 | + { | |
1737 | + .id = V4L2_CID_STATELESS_H264_SCALING_MATRIX, | |
1738 | + .ptr = &controls->scaling_matrix, | |
1739 | + .size = sizeof(controls->scaling_matrix), | |
1740 | + }, | |
1741 | + { | |
1742 | + .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, | |
1743 | + .ptr = &controls->decode_params, | |
1744 | + .size = sizeof(controls->decode_params), | |
1745 | + }, | |
1746 | + { | |
1747 | + .id = V4L2_CID_STATELESS_H264_SLICE_PARAMS, | |
1748 | + .ptr = &controls->slice_params, | |
1749 | + .size = sizeof(controls->slice_params), | |
1750 | + }, | |
1751 | + { | |
1752 | + .id = V4L2_CID_STATELESS_H264_PRED_WEIGHTS, | |
1753 | + .ptr = &controls->pred_weights, | |
1754 | + .size = sizeof(controls->pred_weights), | |
1755 | + }, | |
1756 | + }; | |
1757 | + | |
1758 | + if (ctx->decode_mode == V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED) { | |
1759 | + int count = FF_ARRAY_ELEMS(control) - (controls->pred_weights_required ? 0 : 1); | |
1760 | + return ff_v4l2_request_decode_slice(avctx, h->cur_pic_ptr->f, control, count, controls->first_slice, last_slice); | |
1761 | + } | |
1762 | + | |
1763 | + return ff_v4l2_request_decode_frame(avctx, h->cur_pic_ptr->f, control, FF_ARRAY_ELEMS(control) - 2); | |
1764 | +} | |
1765 | + | |
1766 | +static int v4l2_request_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) | |
1767 | +{ | |
1768 | + const H264Context *h = avctx->priv_data; | |
1769 | + const PPS *pps = h->ps.pps; | |
1770 | + const H264SliceContext *sl = &h->slice_ctx[0]; | |
1771 | + V4L2RequestControlsH264 *controls = h->cur_pic_ptr->hwaccel_picture_private; | |
1772 | + V4L2RequestContextH264 *ctx = avctx->internal->hwaccel_priv_data; | |
1773 | + int i, ret, count; | |
1774 | + | |
1775 | + if (ctx->decode_mode == V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED && controls->num_slices) { | |
1776 | + ret = v4l2_request_h264_queue_decode(avctx, 0); | |
1777 | + if (ret) | |
1778 | + return ret; | |
1779 | + | |
1780 | + ff_v4l2_request_reset_frame(avctx, h->cur_pic_ptr->f); | |
1781 | + controls->first_slice = 0; | |
1782 | + } | |
1783 | + | |
1784 | + if (ctx->start_code == V4L2_STATELESS_H264_START_CODE_ANNEX_B) { | |
1785 | + ret = ff_v4l2_request_append_output_buffer(avctx, h->cur_pic_ptr->f, nalu_slice_start_code, 3); | |
1786 | + if (ret) | |
1787 | + return ret; | |
1788 | + } | |
1789 | + | |
1790 | + ret = ff_v4l2_request_append_output_buffer(avctx, h->cur_pic_ptr->f, buffer, size); | |
1791 | + if (ret) | |
1792 | + return ret; | |
1793 | + | |
1794 | + if (ctx->decode_mode != V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED) | |
1795 | + return 0; | |
1796 | + | |
1797 | + controls->slice_params = (struct v4l2_ctrl_h264_slice_params) { | |
1798 | + /* Offset in bits to slice_data() from the beginning of this slice. */ | |
1799 | + .header_bit_size = get_bits_count(&sl->gb), | |
1800 | + | |
1801 | + .first_mb_in_slice = sl->first_mb_addr, | |
1802 | + | |
1803 | + .slice_type = ff_h264_get_slice_type(sl), | |
1804 | + .colour_plane_id = 0, /* separate colour plane not supported by FFmpeg */ | |
1805 | + .redundant_pic_cnt = sl->redundant_pic_count, | |
1806 | + .cabac_init_idc = sl->cabac_init_idc, | |
1807 | + .slice_qp_delta = sl->qscale - pps->init_qp, | |
1808 | + .slice_qs_delta = 0, /* not implemented by FFmpeg */ | |
1809 | + .disable_deblocking_filter_idc = sl->deblocking_filter < 2 ? !sl->deblocking_filter : sl->deblocking_filter, | |
1810 | + .slice_alpha_c0_offset_div2 = sl->slice_alpha_c0_offset / 2, | |
1811 | + .slice_beta_offset_div2 = sl->slice_beta_offset / 2, | |
1812 | + .num_ref_idx_l0_active_minus1 = sl->list_count > 0 ? sl->ref_count[0] - 1 : 0, | |
1813 | + .num_ref_idx_l1_active_minus1 = sl->list_count > 1 ? sl->ref_count[1] - 1 : 0, | |
1814 | + }; | |
1815 | + | |
1816 | + if (sl->slice_type == AV_PICTURE_TYPE_B && sl->direct_spatial_mv_pred) | |
1817 | + controls->slice_params.flags |= V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED; | |
1818 | + /* V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH: not implemented by FFmpeg */ | |
1819 | + | |
1820 | + controls->pred_weights_required = V4L2_H264_CTRL_PRED_WEIGHTS_REQUIRED(&controls->pps, &controls->slice_params); | |
1821 | + if (controls->pred_weights_required) { | |
1822 | + controls->pred_weights.chroma_log2_weight_denom = sl->pwt.chroma_log2_weight_denom; | |
1823 | + controls->pred_weights.luma_log2_weight_denom = sl->pwt.luma_log2_weight_denom; | |
1824 | + } | |
1825 | + | |
1826 | + count = sl->list_count > 0 ? sl->ref_count[0] : 0; | |
1827 | + for (i = 0; i < count; i++) | |
1828 | + fill_ref_list(&controls->slice_params.ref_pic_list0[i], &controls->decode_params, &sl->ref_list[0][i]); | |
1829 | + if (count && controls->pred_weights_required) | |
1830 | + fill_weight_factors(&controls->pred_weights.weight_factors[0], 0, sl); | |
1831 | + | |
1832 | + count = sl->list_count > 1 ? sl->ref_count[1] : 0; | |
1833 | + for (i = 0; i < count; i++) | |
1834 | + fill_ref_list(&controls->slice_params.ref_pic_list1[i], &controls->decode_params, &sl->ref_list[1][i]); | |
1835 | + if (count && controls->pred_weights_required) | |
1836 | + fill_weight_factors(&controls->pred_weights.weight_factors[1], 1, sl); | |
1837 | + | |
1838 | + controls->num_slices++; | |
1839 | + return 0; | |
1840 | +} | |
1841 | + | |
1842 | +static int v4l2_request_h264_end_frame(AVCodecContext *avctx) | |
1843 | +{ | |
1844 | + const H264Context *h = avctx->priv_data; | |
1845 | + return v4l2_request_h264_queue_decode(avctx, !FIELD_PICTURE(h) || !h->first_field); | |
1846 | +} | |
1847 | + | |
1848 | +static int v4l2_request_h264_set_controls(AVCodecContext *avctx) | |
1849 | +{ | |
1850 | + V4L2RequestContextH264 *ctx = avctx->internal->hwaccel_priv_data; | |
1851 | + | |
1852 | + struct v4l2_ext_control control[] = { | |
1853 | + { .id = V4L2_CID_STATELESS_H264_DECODE_MODE, }, | |
1854 | + { .id = V4L2_CID_STATELESS_H264_START_CODE, }, | |
1855 | + }; | |
1856 | + | |
1857 | + ctx->decode_mode = ff_v4l2_request_query_control_default_value(avctx, V4L2_CID_STATELESS_H264_DECODE_MODE); | |
1858 | + if (ctx->decode_mode != V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED && | |
1859 | + ctx->decode_mode != V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED) { | |
1860 | + av_log(avctx, AV_LOG_ERROR, "%s: unsupported decode mode, %d\n", __func__, ctx->decode_mode); | |
1861 | + return AVERROR(EINVAL); | |
1862 | + } | |
1863 | + | |
1864 | + ctx->start_code = ff_v4l2_request_query_control_default_value(avctx, V4L2_CID_STATELESS_H264_START_CODE); | |
1865 | + if (ctx->start_code != V4L2_STATELESS_H264_START_CODE_NONE && | |
1866 | + ctx->start_code != V4L2_STATELESS_H264_START_CODE_ANNEX_B) { | |
1867 | + av_log(avctx, AV_LOG_ERROR, "%s: unsupported start code, %d\n", __func__, ctx->start_code); | |
1868 | + return AVERROR(EINVAL); | |
1869 | + } | |
1870 | + | |
1871 | + control[0].value = ctx->decode_mode; | |
1872 | + control[1].value = ctx->start_code; | |
1873 | + | |
1874 | + return ff_v4l2_request_set_controls(avctx, control, FF_ARRAY_ELEMS(control)); | |
1875 | +} | |
1876 | + | |
1877 | +static int v4l2_request_h264_init(AVCodecContext *avctx) | |
1878 | +{ | |
1879 | + const H264Context *h = avctx->priv_data; | |
1880 | + struct v4l2_ctrl_h264_sps sps; | |
1881 | + int ret; | |
1882 | + | |
1883 | + struct v4l2_ext_control control[] = { | |
1884 | + { | |
1885 | + .id = V4L2_CID_STATELESS_H264_SPS, | |
1886 | + .ptr = &sps, | |
1887 | + .size = sizeof(sps), | |
1888 | + }, | |
1889 | + }; | |
1890 | + | |
1891 | + fill_sps(&sps, h); | |
1892 | + | |
1893 | + ret = ff_v4l2_request_init(avctx, V4L2_PIX_FMT_H264_SLICE, 4 * 1024 * 1024, control, FF_ARRAY_ELEMS(control)); | |
1894 | + if (ret) | |
1895 | + return ret; | |
1896 | + | |
1897 | + return v4l2_request_h264_set_controls(avctx); | |
1898 | +} | |
1899 | + | |
1900 | +const AVHWAccel ff_h264_v4l2request_hwaccel = { | |
1901 | + .name = "h264_v4l2request", | |
1902 | + .type = AVMEDIA_TYPE_VIDEO, | |
1903 | + .id = AV_CODEC_ID_H264, | |
1904 | + .pix_fmt = AV_PIX_FMT_DRM_PRIME, | |
1905 | + .start_frame = v4l2_request_h264_start_frame, | |
1906 | + .decode_slice = v4l2_request_h264_decode_slice, | |
1907 | + .end_frame = v4l2_request_h264_end_frame, | |
1908 | + .frame_priv_data_size = sizeof(V4L2RequestControlsH264), | |
1909 | + .init = v4l2_request_h264_init, | |
1910 | + .uninit = ff_v4l2_request_uninit, | |
1911 | + .priv_data_size = sizeof(V4L2RequestContextH264), | |
1912 | + .frame_params = ff_v4l2_request_frame_params, | |
1913 | + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, | |
1914 | +}; | |
1915 | From f9f4a89058a6fac25712cc385eab72f70e9ac4c8 Mon Sep 17 00:00:00 2001 | |
1916 | From: Jonas Karlman <jonas@kwiboo.se> | |
1917 | Date: Mon, 29 Apr 2019 22:08:59 +0000 | |
1918 | Subject: [PATCH] HACK: hwcontext_drm: do not require drm device | |
1919 | ||
1920 | Signed-off-by: Jonas Karlman <jonas@kwiboo.se> | |
1921 | --- | |
1922 | libavutil/hwcontext_drm.c | 5 +++++ | |
1923 | 1 file changed, 5 insertions(+) | |
1924 | ||
1925 | diff --git a/libavutil/hwcontext_drm.c b/libavutil/hwcontext_drm.c | |
1926 | index 32cbde82ebfa..aa4794c5e665 100644 | |
1927 | --- a/libavutil/hwcontext_drm.c | |
1928 | +++ b/libavutil/hwcontext_drm.c | |
1929 | @@ -43,6 +43,11 @@ static int drm_device_create(AVHWDeviceContext *hwdev, const char *device, | |
1930 | AVDRMDeviceContext *hwctx = hwdev->hwctx; | |
1931 | drmVersionPtr version; | |
1932 | ||
1933 | + if (device == NULL) { | |
1934 | + hwctx->fd = -1; | |
1935 | + return 0; | |
1936 | + } | |
1937 | + | |
1938 | hwctx->fd = open(device, O_RDWR); | |
1939 | if (hwctx->fd < 0) | |
1940 | return AVERROR(errno); | |
1941 | From fa7165e391287bf970569e36b0b19bff947b084f Mon Sep 17 00:00:00 2001 | |
1942 | From: Jonas Karlman <jonas@kwiboo.se> | |
1943 | Date: Mon, 27 Jul 2020 23:15:45 +0000 | |
1944 | Subject: [PATCH] HACK: define drm NV15 and NV20 format | |
1945 | ||
1946 | --- | |
1947 | libavcodec/v4l2_request.c | 8 ++++++++ | |
1948 | 1 file changed, 8 insertions(+) | |
1949 | ||
1950 | diff --git a/libavcodec/v4l2_request.c b/libavcodec/v4l2_request.c | |
1951 | index 0b294feff2eb..a8f0ee79eeef 100644 | |
1952 | --- a/libavcodec/v4l2_request.c | |
1953 | +++ b/libavcodec/v4l2_request.c | |
1954 | @@ -30,6 +30,14 @@ | |
1955 | #include "internal.h" | |
1956 | #include "v4l2_request.h" | |
1957 | ||
1958 | +#ifndef DRM_FORMAT_NV15 | |
1959 | +#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') | |
1960 | +#endif | |
1961 | + | |
1962 | +#ifndef DRM_FORMAT_NV20 | |
1963 | +#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') | |
1964 | +#endif | |
1965 | + | |
1966 | uint64_t ff_v4l2_request_get_capture_timestamp(AVFrame *frame) | |
1967 | { | |
1968 | V4L2RequestDescriptor *req = (V4L2RequestDescriptor*)frame->data[0]; |