]> git.pld-linux.org Git - packages/ffmpeg.git/blame - v4l2-drmprime.patch
drmprime zero-copy output patch from libreelec
[packages/ffmpeg.git] / v4l2-drmprime.patch
CommitLineData
6838be8a
JP
1From 40a990827399c05ad3ce3f8242321bd8a67aa0bd Mon Sep 17 00:00:00 2001
2From: Lukas Rusak <lorusak@gmail.com>
3Date: Tue, 24 Apr 2018 23:00:23 -0700
4Subject: [PATCH 1/9] libavcodec: v4l2m2m: output AVDRMFrameDescriptor
5
6This allows for a zero-copy output by exporting the v4l2 buffer then wrapping that buffer
7in the AVDRMFrameDescriptor like it is done in rkmpp.
8
9This has been in use for quite some time with great success on many platforms including:
10 - Amlogic S905
11 - Raspberry Pi
12 - i.MX6
13 - Dragonboard 410c
14
15This was developed in conjunction with Kodi to allow handling the zero-copy buffer rendering.
16A simply utility for testing is also available here: https://github.com/BayLibre/ffmpeg-drm
17
18todo:
19 - allow selecting pixel format output from decoder
20 - allow configuring amount of output and capture buffers
21
22V2:
23 - allow selecting AV_PIX_FMT_DRM_PRIME
24
25V3:
26 - use get_format to select AV_PIX_FMT_DRM_PRIME
27 - use hw_configs
28 - add handling of AV_PIX_FMT_YUV420P format (for raspberry pi)
29 - add handling of AV_PIX_FMT_YUYV422 format (for i.MX6 coda decoder)
30
31V4:
32 - rebased on 4.2.2
33
34V5:
35 - rebased on 4.3
36---
37 libavcodec/v4l2_buffers.c | 155 ++++++++++++++++++++++++++++++++++++--
38 libavcodec/v4l2_buffers.h | 4 +
39 libavcodec/v4l2_context.c | 40 +++++++++-
40 libavcodec/v4l2_m2m.h | 3 +
41 libavcodec/v4l2_m2m_dec.c | 23 ++++++
42 5 files changed, 213 insertions(+), 12 deletions(-)
43
44diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
45index 4b2679eb38..cbd3e5680d 100644
46--- a/libavcodec/v4l2_buffers.c
47+++ b/libavcodec/v4l2_buffers.c
48@@ -21,6 +21,7 @@
49 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
50 */
51
52+#include <drm/drm_fourcc.h>
53 #include <linux/videodev2.h>
54 #include <sys/ioctl.h>
55 #include <sys/mman.h>
56@@ -30,6 +31,7 @@
57 #include "libavcodec/avcodec.h"
58 #include "libavcodec/internal.h"
59 #include "libavutil/pixdesc.h"
60+#include "libavutil/hwcontext.h"
61 #include "v4l2_context.h"
62 #include "v4l2_buffers.h"
63 #include "v4l2_m2m.h"
64@@ -210,7 +212,79 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf)
65 return AVCOL_TRC_UNSPECIFIED;
66 }
67
68-static void v4l2_free_buffer(void *opaque, uint8_t *unused)
69+static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf)
70+{
71+ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame;
72+ AVDRMLayerDescriptor *layer;
73+
74+ /* fill the DRM frame descriptor */
75+ drm_desc->nb_objects = avbuf->num_planes;
76+ drm_desc->nb_layers = 1;
77+
78+ layer = &drm_desc->layers[0];
79+ layer->nb_planes = avbuf->num_planes;
80+
81+ for (int i = 0; i < avbuf->num_planes; i++) {
82+ layer->planes[i].object_index = i;
83+ layer->planes[i].offset = 0;
84+ layer->planes[i].pitch = avbuf->plane_info[i].bytesperline;
85+ }
86+
87+ switch (avbuf->context->av_pix_fmt) {
88+ case AV_PIX_FMT_YUYV422:
89+
90+ layer->format = DRM_FORMAT_YUYV;
91+ layer->nb_planes = 1;
92+
93+ break;
94+
95+ case AV_PIX_FMT_NV12:
96+ case AV_PIX_FMT_NV21:
97+
98+ layer->format = avbuf->context->av_pix_fmt == AV_PIX_FMT_NV12 ?
99+ DRM_FORMAT_NV12 : DRM_FORMAT_NV21;
100+
101+ if (avbuf->num_planes > 1)
102+ break;
103+
104+ layer->nb_planes = 2;
105+
106+ layer->planes[1].object_index = 0;
107+ layer->planes[1].offset = avbuf->plane_info[0].bytesperline *
108+ avbuf->context->format.fmt.pix.height;
109+ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline;
110+ break;
111+
112+ case AV_PIX_FMT_YUV420P:
113+
114+ layer->format = DRM_FORMAT_YUV420;
115+
116+ if (avbuf->num_planes > 1)
117+ break;
118+
119+ layer->nb_planes = 3;
120+
121+ layer->planes[1].object_index = 0;
122+ layer->planes[1].offset = avbuf->plane_info[0].bytesperline *
123+ avbuf->context->format.fmt.pix.height;
124+ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline >> 1;
125+
126+ layer->planes[2].object_index = 0;
127+ layer->planes[2].offset = layer->planes[1].offset +
128+ ((avbuf->plane_info[0].bytesperline *
129+ avbuf->context->format.fmt.pix.height) >> 2);
130+ layer->planes[2].pitch = avbuf->plane_info[0].bytesperline >> 1;
131+ break;
132+
133+ default:
134+ drm_desc->nb_layers = 0;
135+ break;
136+ }
137+
138+ return (uint8_t *) drm_desc;
139+}
140+
141+static void v4l2_free_buffer(void *opaque, uint8_t *data)
142 {
143 V4L2Buffer* avbuf = opaque;
144 V4L2m2mContext *s = buf_to_m2mctx(avbuf);
145@@ -234,6 +308,36 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused)
146 }
147 }
148
149+static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
150+{
151+ struct v4l2_exportbuffer expbuf;
152+ int i, ret;
153+
154+ for (i = 0; i < avbuf->num_planes; i++) {
155+ memset(&expbuf, 0, sizeof(expbuf));
156+
157+ expbuf.index = avbuf->buf.index;
158+ expbuf.type = avbuf->buf.type;
159+ expbuf.plane = i;
160+
161+ ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_EXPBUF, &expbuf);
162+ if (ret < 0)
163+ return AVERROR(errno);
164+
165+ if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type)) {
166+ /* drm frame */
167+ avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length;
168+ avbuf->drm_frame.objects[i].fd = expbuf.fd;
169+ } else {
170+ /* drm frame */
171+ avbuf->drm_frame.objects[0].size = avbuf->buf.length;
172+ avbuf->drm_frame.objects[0].fd = expbuf.fd;
173+ }
174+ }
175+
176+ return 0;
177+}
178+
179 static int v4l2_buf_increase_ref(V4L2Buffer *in)
180 {
181 V4L2m2mContext *s = buf_to_m2mctx(in);
182@@ -254,6 +358,24 @@ static int v4l2_buf_increase_ref(V4L2Buffer *in)
183 return 0;
184 }
185
186+static int v4l2_buf_to_bufref_drm(V4L2Buffer *in, AVBufferRef **buf)
187+{
188+ int ret;
189+
190+ *buf = av_buffer_create((uint8_t *) &in->drm_frame,
191+ sizeof(in->drm_frame),
192+ v4l2_free_buffer,
193+ in, AV_BUFFER_FLAG_READONLY);
194+ if (!*buf)
195+ return AVERROR(ENOMEM);
196+
197+ ret = v4l2_buf_increase_ref(in);
198+ if (ret)
199+ av_buffer_unref(buf);
200+
201+ return ret;
202+}
203+
204 static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf)
205 {
206 int ret;
207@@ -303,13 +425,24 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
208
209 frame->format = avbuf->context->av_pix_fmt;
210
211- for (i = 0; i < avbuf->num_planes; i++) {
212- ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]);
213+ if (buf_to_m2mctx(avbuf)->output_drm) {
214+ /* 1. get references to the actual data */
215+ ret = v4l2_buf_to_bufref_drm(avbuf, &frame->buf[0]);
216 if (ret)
217 return ret;
218
219- frame->linesize[i] = avbuf->plane_info[i].bytesperline;
220- frame->data[i] = frame->buf[i]->data;
221+ frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf);
222+ frame->format = AV_PIX_FMT_DRM_PRIME;
223+ } else {
224+ /* 1. get references to the actual data */
225+ for (i = 0; i < avbuf->num_planes; i++) {
226+ ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]);
227+ if (ret)
228+ return ret;
229+
230+ frame->linesize[i] = avbuf->plane_info[i].bytesperline;
231+ frame->data[i] = frame->buf[i]->data;
232+ }
233 }
234
235 /* fixup special cases */
236@@ -543,9 +676,6 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
237
238 avbuf->status = V4L2BUF_AVAILABLE;
239
240- if (V4L2_TYPE_IS_OUTPUT(ctx->type))
241- return 0;
242-
243 if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
244 avbuf->buf.m.planes = avbuf->planes;
245 avbuf->buf.length = avbuf->num_planes;
246@@ -555,6 +685,15 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
247 avbuf->buf.length = avbuf->planes[0].length;
248 }
249
250+ if (V4L2_TYPE_IS_OUTPUT(ctx->type))
251+ return 0;
252+
253+ if (buf_to_m2mctx(avbuf)->output_drm) {
254+ ret = v4l2_buffer_export_drm(avbuf);
255+ if (ret)
256+ return ret;
257+ }
258+
259 return ff_v4l2_buffer_enqueue(avbuf);
260 }
261
262diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
263index 8dbc7fc104..037e667997 100644
264--- a/libavcodec/v4l2_buffers.h
265+++ b/libavcodec/v4l2_buffers.h
266@@ -27,6 +27,7 @@
267 #include <stdatomic.h>
268 #include <linux/videodev2.h>
269
270+#include "libavutil/hwcontext_drm.h"
271 #include "avcodec.h"
272
273 enum V4L2Buffer_status {
274@@ -42,6 +43,9 @@ typedef struct V4L2Buffer {
275 /* each buffer needs to have a reference to its context */
276 struct V4L2Context *context;
277
278+ /* DRM descriptor */
279+ AVDRMFrameDescriptor drm_frame;
280+
281 /* This object is refcounted per-plane, so we need to keep track
282 * of how many context-refs we are holding. */
283 AVBufferRef *context_ref;
284diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
285index ff1ea8e57b..e9e8c27a54 100644
286--- a/libavcodec/v4l2_context.c
287+++ b/libavcodec/v4l2_context.c
288@@ -455,22 +455,54 @@ static int v4l2_release_buffers(V4L2Context* ctx)
289 struct v4l2_requestbuffers req = {
290 .memory = V4L2_MEMORY_MMAP,
291 .type = ctx->type,
292- .count = 0, /* 0 -> unmaps buffers from the driver */
293+ .count = 0, /* 0 -> unmap all buffers from the driver */
294 };
295- int i, j;
296+ int ret, i, j;
297
298 for (i = 0; i < ctx->num_buffers; i++) {
299 V4L2Buffer *buffer = &ctx->buffers[i];
300
301 for (j = 0; j < buffer->num_planes; j++) {
302 struct V4L2Plane_info *p = &buffer->plane_info[j];
303+
304+ if (V4L2_TYPE_IS_OUTPUT(ctx->type)) {
305+ /* output buffers are not EXPORTED */
306+ goto unmap;
307+ }
308+
309+ if (ctx_to_m2mctx(ctx)->output_drm) {
310+ /* use the DRM frame to close */
311+ if (buffer->drm_frame.objects[j].fd >= 0) {
312+ if (close(buffer->drm_frame.objects[j].fd) < 0) {
313+ av_log(logger(ctx), AV_LOG_ERROR, "%s close drm fd "
314+ "[buffer=%2d, plane=%d, fd=%2d] - %s \n",
315+ ctx->name, i, j, buffer->drm_frame.objects[j].fd,
316+ av_err2str(AVERROR(errno)));
317+ }
318+ }
319+ }
320+unmap:
321 if (p->mm_addr && p->length)
322 if (munmap(p->mm_addr, p->length) < 0)
323- av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno)));
324+ av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n",
325+ ctx->name, av_err2str(AVERROR(errno)));
326 }
327 }
328
329- return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req);
330+ ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req);
331+ if (ret < 0) {
332+ av_log(logger(ctx), AV_LOG_ERROR, "release all %s buffers (%s)\n",
333+ ctx->name, av_err2str(AVERROR(errno)));
334+
335+ if (ctx_to_m2mctx(ctx)->output_drm)
336+ av_log(logger(ctx), AV_LOG_ERROR,
337+ "Make sure the DRM client releases all FB/GEM objects before closing the codec (ie):\n"
338+ "for all buffers: \n"
339+ " 1. drmModeRmFB(..)\n"
340+ " 2. drmIoctl(.., DRM_IOCTL_GEM_CLOSE,... )\n");
341+ }
342+
343+ return ret;
344 }
345
346 static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt)
347diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
348index b67b216331..0fbd19a013 100644
349--- a/libavcodec/v4l2_m2m.h
350+++ b/libavcodec/v4l2_m2m.h
351@@ -66,6 +66,9 @@ typedef struct V4L2m2mContext {
352
353 /* reference back to V4L2m2mPriv */
354 void *priv;
355+
356+ /* generate DRM frames */
357+ int output_drm;
358 } V4L2m2mContext;
359
360 typedef struct V4L2m2mPriv {
361diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
362index ab07c0a24a..6bc7442702 100644
363--- a/libavcodec/v4l2_m2m_dec.c
364+++ b/libavcodec/v4l2_m2m_dec.c
365@@ -23,6 +23,9 @@
366
367 #include <linux/videodev2.h>
368 #include <sys/ioctl.h>
369+
370+#include "libavutil/hwcontext.h"
371+#include "libavutil/hwcontext_drm.h"
372 #include "libavutil/pixfmt.h"
373 #include "libavutil/pixdesc.h"
374 #include "libavutil/opt.h"
375@@ -30,6 +33,9 @@
376 #include "libavcodec/decode.h"
377 #include "libavcodec/internal.h"
378
379+#include "libavcodec/hwaccels.h"
380+#include "libavcodec/internal.h"
381+
382 #include "v4l2_context.h"
383 #include "v4l2_m2m.h"
384 #include "v4l2_fmt.h"
385@@ -201,6 +207,15 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
386 capture->av_codec_id = AV_CODEC_ID_RAWVIDEO;
387 capture->av_pix_fmt = avctx->pix_fmt;
388
389+ /* the client requests the codec to generate DRM frames:
390+ * - data[0] will therefore point to the returned AVDRMFrameDescriptor
391+ * check the ff_v4l2_buffer_to_avframe conversion function.
392+ * - the DRM frame format is passed in the DRM frame descriptor layer.
393+ * check the v4l2_get_drm_frame function.
394+ */
395+ if (ff_get_format(avctx, avctx->codec->pix_fmts) == AV_PIX_FMT_DRM_PRIME)
396+ s->output_drm = 1;
397+
398 s->avctx = avctx;
399 ret = ff_v4l2_m2m_codec_init(priv);
400 if (ret) {
401@@ -226,6 +241,11 @@ static const AVOption options[] = {
402 { NULL},
403 };
404
405+static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
406+ HW_CONFIG_INTERNAL(DRM_PRIME),
407+ NULL
408+};
409+
410 #define M2MDEC_CLASS(NAME) \
411 static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \
412 .class_name = #NAME "_v4l2m2m_decoder", \
413@@ -249,6 +269,9 @@ static const AVOption options[] = {
414 .bsfs = bsf_name, \
415 .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
416 .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, \
417+ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
418+ AV_PIX_FMT_NONE}, \
419+ .hw_configs = v4l2_m2m_hw_configs, \
420 .wrapper_name = "v4l2m2m", \
421 }
422
423
424From 9a2a361c2c84c8da54cd3a74b0d0bb966df8fe69 Mon Sep 17 00:00:00 2001
425From: Lukas Rusak <lorusak@gmail.com>
426Date: Thu, 16 Aug 2018 21:09:40 -0700
427Subject: [PATCH 2/9] libavcodec: v4l2m2m: depends on libdrm
428
429---
430 configure | 1 +
431 libavcodec/v4l2_buffers.c | 2 +-
432 2 files changed, 2 insertions(+), 1 deletion(-)
433
434diff --git a/configure b/configure
435index d7a3f507e8..d203f6f7da 100755
436--- a/configure
437+++ b/configure
438@@ -3437,6 +3437,7 @@ sndio_indev_deps="sndio"
439 sndio_outdev_deps="sndio"
440 v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h"
441 v4l2_indev_suggest="libv4l2"
442+v4l2_outdev_deps="libdrm"
443 v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h"
444 v4l2_outdev_suggest="libv4l2"
445 vfwcap_indev_deps="vfw32 vfwcap_defines"
446diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
447index cbd3e5680d..bebe2c1796 100644
448--- a/libavcodec/v4l2_buffers.c
449+++ b/libavcodec/v4l2_buffers.c
450@@ -21,7 +21,7 @@
451 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
452 */
453
454-#include <drm/drm_fourcc.h>
455+#include <drm_fourcc.h>
456 #include <linux/videodev2.h>
457 #include <sys/ioctl.h>
458 #include <sys/mman.h>
459
460From 7b0fa2d859c12a8a129c884d16673ca731336c06 Mon Sep 17 00:00:00 2001
461From: Lukas Rusak <lorusak@gmail.com>
462Date: Thu, 16 Aug 2018 21:10:13 -0700
463Subject: [PATCH 3/9] libavcodec: v4l2m2m: set format_modifier to
464 DRM_FORMAT_MOD_LINEAR
465
466---
467 libavcodec/v4l2_buffers.c | 2 ++
468 1 file changed, 2 insertions(+)
469
470diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
471index bebe2c1796..12037d5d66 100644
472--- a/libavcodec/v4l2_buffers.c
473+++ b/libavcodec/v4l2_buffers.c
474@@ -328,10 +328,12 @@ static int v4l2_buffer_export_drm(V4L2Buffer* avbuf)
475 /* drm frame */
476 avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length;
477 avbuf->drm_frame.objects[i].fd = expbuf.fd;
478+ avbuf->drm_frame.objects[i].format_modifier = DRM_FORMAT_MOD_LINEAR;
479 } else {
480 /* drm frame */
481 avbuf->drm_frame.objects[0].size = avbuf->buf.length;
482 avbuf->drm_frame.objects[0].fd = expbuf.fd;
483+ avbuf->drm_frame.objects[0].format_modifier = DRM_FORMAT_MOD_LINEAR;
484 }
485 }
486
487
488From e1857456c8f24e40d5c898886f2f51014e59ee9d Mon Sep 17 00:00:00 2001
489From: Lukas Rusak <lorusak@gmail.com>
490Date: Thu, 16 Aug 2018 21:10:53 -0700
491Subject: [PATCH 4/9] libavcodec: v4l2m2m: only mmap the buffer when it is
492 output type and drm prime is used
493
494---
495 libavcodec/v4l2_buffers.c | 20 ++++++++++++++------
496 1 file changed, 14 insertions(+), 6 deletions(-)
497
498diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
499index 12037d5d66..1adf518ab9 100644
500--- a/libavcodec/v4l2_buffers.c
501+++ b/libavcodec/v4l2_buffers.c
502@@ -662,14 +662,22 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
503
504 if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
505 avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length;
506- avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length,
507- PROT_READ | PROT_WRITE, MAP_SHARED,
508- buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset);
509+
510+ if ((V4L2_TYPE_IS_OUTPUT(ctx->type) && buf_to_m2mctx(avbuf)->output_drm) ||
511+ !buf_to_m2mctx(avbuf)->output_drm) {
512+ avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length,
513+ PROT_READ | PROT_WRITE, MAP_SHARED,
514+ buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset);
515+ }
516 } else {
517 avbuf->plane_info[i].length = avbuf->buf.length;
518- avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length,
519- PROT_READ | PROT_WRITE, MAP_SHARED,
520- buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset);
521+
522+ if ((V4L2_TYPE_IS_OUTPUT(ctx->type) && buf_to_m2mctx(avbuf)->output_drm) ||
523+ !buf_to_m2mctx(avbuf)->output_drm) {
524+ avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length,
525+ PROT_READ | PROT_WRITE, MAP_SHARED,
526+ buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset);
527+ }
528 }
529
530 if (avbuf->plane_info[i].mm_addr == MAP_FAILED)
531
532From c8fc3ea1b5777546f7ec72a54b053a2d4fa9fd59 Mon Sep 17 00:00:00 2001
533From: Lukas Rusak <lorusak@gmail.com>
534Date: Thu, 16 Aug 2018 21:11:38 -0700
535Subject: [PATCH 5/9] libavcodec: v4l2m2m: allow using software pixel formats
536
537---
538 libavcodec/v4l2_m2m_dec.c | 11 ++++++++++-
539 1 file changed, 10 insertions(+), 1 deletion(-)
540
541diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
542index 6bc7442702..4b9baf833c 100644
543--- a/libavcodec/v4l2_m2m_dec.c
544+++ b/libavcodec/v4l2_m2m_dec.c
545@@ -213,8 +213,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
546 * - the DRM frame format is passed in the DRM frame descriptor layer.
547 * check the v4l2_get_drm_frame function.
548 */
549- if (ff_get_format(avctx, avctx->codec->pix_fmts) == AV_PIX_FMT_DRM_PRIME)
550+ switch (ff_get_format(avctx, avctx->codec->pix_fmts)) {
551+ case AV_PIX_FMT_DRM_PRIME:
552 s->output_drm = 1;
553+ break;
554+ case AV_PIX_FMT_NONE:
555+ return 0;
556+ break;
557+ default:
558+ break;
559+ }
560
561 s->avctx = avctx;
562 ret = ff_v4l2_m2m_codec_init(priv);
563@@ -270,6 +278,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
564 .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
565 .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, \
566 .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
567+ AV_PIX_FMT_NV12, \
568 AV_PIX_FMT_NONE}, \
569 .hw_configs = v4l2_m2m_hw_configs, \
570 .wrapper_name = "v4l2m2m", \
571
572From 13f02e940f083f19dbe8b9ac8fc7df45700dd36e Mon Sep 17 00:00:00 2001
573From: Lukas Rusak <lorusak@gmail.com>
574Date: Mon, 24 Sep 2018 13:39:31 -0700
575Subject: [PATCH 6/9] libavcodec: v4l2m2m: implement hwcontext
576
577---
578 libavcodec/v4l2_buffers.c | 22 ++++++++++++++++++++++
579 libavcodec/v4l2_context.h | 2 ++
580 libavcodec/v4l2_m2m.h | 2 ++
581 libavcodec/v4l2_m2m_dec.c | 11 +++++++++++
582 4 files changed, 37 insertions(+)
583
584diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
585index 1adf518ab9..6e2a544394 100644
586--- a/libavcodec/v4l2_buffers.c
587+++ b/libavcodec/v4l2_buffers.c
588@@ -435,6 +435,7 @@ static int v4l2_buffer_buf_to_swframe(AVFrame *frame, V4L2Buffer *avbuf)
589
590 frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf);
591 frame->format = AV_PIX_FMT_DRM_PRIME;
592+ frame->hw_frames_ctx = av_buffer_ref(avbuf->context->frames_ref);
593 } else {
594 /* 1. get references to the actual data */
595 for (i = 0; i < avbuf->num_planes; i++) {
596@@ -635,6 +636,27 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index)
597 avbuf->buf.type = ctx->type;
598 avbuf->buf.index = index;
599
600+ if (buf_to_m2mctx(avbuf)->output_drm) {
601+ AVHWFramesContext *hwframes;
602+
603+ av_buffer_unref(&ctx->frames_ref);
604+
605+ ctx->frames_ref = av_hwframe_ctx_alloc(buf_to_m2mctx(avbuf)->device_ref);
606+ if (!ctx->frames_ref) {
607+ ret = AVERROR(ENOMEM);
608+ return ret;
609+ }
610+
611+ hwframes = (AVHWFramesContext*)ctx->frames_ref->data;
612+ hwframes->format = AV_PIX_FMT_DRM_PRIME;
613+ hwframes->sw_format = ctx->av_pix_fmt;
614+ hwframes->width = ctx->width;
615+ hwframes->height = ctx->height;
616+ ret = av_hwframe_ctx_init(ctx->frames_ref);
617+ if (ret < 0)
618+ return ret;
619+ }
620+
621 if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) {
622 avbuf->buf.length = VIDEO_MAX_PLANES;
623 avbuf->buf.m.planes = avbuf->planes;
624diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h
625index 22a9532444..e804e94131 100644
626--- a/libavcodec/v4l2_context.h
627+++ b/libavcodec/v4l2_context.h
628@@ -92,6 +92,8 @@ typedef struct V4L2Context {
629 */
630 int done;
631
632+ AVBufferRef *frames_ref;
633+
634 } V4L2Context;
635
636 /**
637diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
638index 0fbd19a013..adf5997bb5 100644
639--- a/libavcodec/v4l2_m2m.h
640+++ b/libavcodec/v4l2_m2m.h
641@@ -67,6 +67,8 @@ typedef struct V4L2m2mContext {
642 /* reference back to V4L2m2mPriv */
643 void *priv;
644
645+ AVBufferRef *device_ref;
646+
647 /* generate DRM frames */
648 int output_drm;
649 } V4L2m2mContext;
650diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
651index 4b9baf833c..6c23693137 100644
652--- a/libavcodec/v4l2_m2m_dec.c
653+++ b/libavcodec/v4l2_m2m_dec.c
654@@ -35,6 +35,7 @@
655
656 #include "libavcodec/hwaccels.h"
657 #include "libavcodec/internal.h"
658+#include "libavcodec/hwconfig.h"
659
660 #include "v4l2_context.h"
661 #include "v4l2_m2m.h"
662@@ -224,6 +225,16 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
663 break;
664 }
665
666+ s->device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM);
667+ if (!s->device_ref) {
668+ ret = AVERROR(ENOMEM);
669+ return ret;
670+ }
671+
672+ ret = av_hwdevice_ctx_init(s->device_ref);
673+ if (ret < 0)
674+ return ret;
675+
676 s->avctx = avctx;
677 ret = ff_v4l2_m2m_codec_init(priv);
678 if (ret) {
679
680From 34be198b8039c9df434792f19f0985e45419407e Mon Sep 17 00:00:00 2001
681From: Lukas Rusak <lorusak@gmail.com>
682Date: Mon, 4 May 2020 13:01:29 -0700
683Subject: [PATCH 7/9] libavcodec: v4l2m2m: allow lower minimum buffer values
684
685There is no reason to enforce a high minimum. In the context
686of streaming only a few output buffers and capture buffers
687are even needed for continuous playback. This also helps
688alleviate memory pressure when decoding 4K media.
689---
690 libavcodec/v4l2_m2m.h | 2 +-
691 libavcodec/v4l2_m2m_dec.c | 2 +-
692 2 files changed, 2 insertions(+), 2 deletions(-)
693
694diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
695index adf5997bb5..1082b9dad2 100644
696--- a/libavcodec/v4l2_m2m.h
697+++ b/libavcodec/v4l2_m2m.h
698@@ -38,7 +38,7 @@
699
700 #define V4L_M2M_DEFAULT_OPTS \
701 { "num_output_buffers", "Number of buffers in the output context",\
702- OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 6, INT_MAX, FLAGS }
703+ OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 2, INT_MAX, FLAGS }
704
705 typedef struct V4L2m2mContext {
706 char devname[PATH_MAX];
707diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
708index 6c23693137..e323c37052 100644
709--- a/libavcodec/v4l2_m2m_dec.c
710+++ b/libavcodec/v4l2_m2m_dec.c
711@@ -256,7 +256,7 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
712 static const AVOption options[] = {
713 V4L_M2M_DEFAULT_OPTS,
714 { "num_capture_buffers", "Number of buffers in the capture context",
715- OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 20, INT_MAX, FLAGS },
716+ OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 2, INT_MAX, FLAGS },
717 { NULL},
718 };
719
720
721From 2956fd1881d28abf6bf77bd9a57866c4ba81d199 Mon Sep 17 00:00:00 2001
722From: Lukas Rusak <lorusak@gmail.com>
723Date: Wed, 6 May 2020 11:12:58 -0700
724Subject: [PATCH 8/9] libavcodec: v4l2m2m: add option to specify pixel format
725 used by the decoder
726
727---
728 libavcodec/v4l2_context.c | 9 +++++++++
729 libavcodec/v4l2_m2m.h | 2 ++
730 libavcodec/v4l2_m2m_dec.c | 1 +
731 3 files changed, 12 insertions(+)
732
733diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
734index e9e8c27a54..a97b70e836 100644
735--- a/libavcodec/v4l2_context.c
736+++ b/libavcodec/v4l2_context.c
737@@ -531,6 +531,8 @@ static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfm
738
739 static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
740 {
741+ V4L2m2mContext* s = ctx_to_m2mctx(ctx);
742+ V4L2m2mPriv *priv = s->avctx->priv_data;
743 enum AVPixelFormat pixfmt = ctx->av_pix_fmt;
744 struct v4l2_fmtdesc fdesc;
745 int ret;
746@@ -549,6 +551,13 @@ static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p)
747 if (ret)
748 return AVERROR(EINVAL);
749
750+ if (priv->pix_fmt != AV_PIX_FMT_NONE) {
751+ if (fdesc.pixelformat != ff_v4l2_format_avfmt_to_v4l2(priv->pix_fmt)) {
752+ fdesc.index++;
753+ continue;
754+ }
755+ }
756+
757 pixfmt = ff_v4l2_format_v4l2_to_avfmt(fdesc.pixelformat, AV_CODEC_ID_RAWVIDEO);
758 ret = v4l2_try_raw_format(ctx, pixfmt);
759 if (ret){
760diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
761index 1082b9dad2..943a8923c4 100644
762--- a/libavcodec/v4l2_m2m.h
763+++ b/libavcodec/v4l2_m2m.h
764@@ -30,6 +30,7 @@
765 #include <linux/videodev2.h>
766
767 #include "libavcodec/avcodec.h"
768+#include "libavutil/pixfmt.h"
769 #include "v4l2_context.h"
770
771 #define container_of(ptr, type, member) ({ \
772@@ -81,6 +82,7 @@ typedef struct V4L2m2mPriv {
773
774 int num_output_buffers;
775 int num_capture_buffers;
776+ enum AVPixelFormat pix_fmt;
777 } V4L2m2mPriv;
778
779 /**
780diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
781index e323c37052..363e998142 100644
782--- a/libavcodec/v4l2_m2m_dec.c
783+++ b/libavcodec/v4l2_m2m_dec.c
784@@ -257,6 +257,7 @@ static const AVOption options[] = {
785 V4L_M2M_DEFAULT_OPTS,
786 { "num_capture_buffers", "Number of buffers in the capture context",
787 OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 2, INT_MAX, FLAGS },
788+ { "pixel_format", "Pixel format to be used by the decoder", OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, AV_PIX_FMT_NONE, AV_PIX_FMT_NB, FLAGS },
789 { NULL},
790 };
791
792
793From 2bb6d0cb244590f0c70dd111ed978cd87fa3bee1 Mon Sep 17 00:00:00 2001
794From: Lukas Rusak <lorusak@gmail.com>
795Date: Mon, 24 Sep 2018 13:39:56 -0700
796Subject: [PATCH 9/9] libavcodec: v4l2m2m: implement flush
797
798---
799 libavcodec/v4l2_m2m_dec.c | 36 ++++++++++++++++++++++++++++++++++++
800 1 file changed, 36 insertions(+)
801
802diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
803index 363e998142..52ec67cb59 100644
804--- a/libavcodec/v4l2_m2m_dec.c
805+++ b/libavcodec/v4l2_m2m_dec.c
806@@ -250,6 +250,41 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
807 return ff_v4l2_m2m_codec_end(avctx->priv_data);
808 }
809
810+static void v4l2_decode_flush(AVCodecContext *avctx)
811+{
812+ V4L2m2mPriv *priv = avctx->priv_data;
813+ V4L2m2mContext* s = priv->context;
814+ V4L2Context* output = &s->output;
815+ V4L2Context* capture = &s->capture;
816+ int ret, i;
817+
818+ ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMOFF);
819+ if (ret < 0)
820+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s error: %d\n", output->name, ret);
821+
822+ ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON);
823+ if (ret < 0)
824+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON %s error: %d\n", output->name, ret);
825+
826+ for (i = 0; i < output->num_buffers; i++) {
827+ if (output->buffers[i].status == V4L2BUF_IN_DRIVER)
828+ output->buffers[i].status = V4L2BUF_AVAILABLE;
829+ }
830+
831+ struct v4l2_decoder_cmd cmd = {
832+ .cmd = V4L2_DEC_CMD_START,
833+ .flags = 0,
834+ };
835+
836+ ret = ioctl(s->fd, VIDIOC_DECODER_CMD, &cmd);
837+ if (ret < 0)
838+ av_log(avctx, AV_LOG_ERROR, "VIDIOC_DECODER_CMD start error: %d\n", errno);
839+
840+ s->draining = 0;
841+ output->done = 0;
842+ capture->done = 0;
843+}
844+
845 #define OFFSET(x) offsetof(V4L2m2mPriv, x)
846 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
847
848@@ -286,6 +321,7 @@ static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
849 .init = v4l2_decode_init, \
850 .receive_frame = v4l2_receive_frame, \
851 .close = v4l2_decode_close, \
852+ .flush = v4l2_decode_flush, \
853 .bsfs = bsf_name, \
854 .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
855 .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_CLEANUP, \
This page took 0.174662 seconds and 4 git commands to generate.