]> git.pld-linux.org Git - packages/ffmpeg.git/blob - v4l2-drmprime.patch
drmprime zero-copy output patch from libreelec
[packages/ffmpeg.git] / v4l2-drmprime.patch
1 From 40a990827399c05ad3ce3f8242321bd8a67aa0bd Mon Sep 17 00:00:00 2001
2 From: Lukas Rusak <lorusak@gmail.com>
3 Date: Tue, 24 Apr 2018 23:00:23 -0700
4 Subject: [PATCH 1/9] libavcodec: v4l2m2m: output AVDRMFrameDescriptor
5
6 This allows for a zero-copy output by exporting the v4l2 buffer then wrapping that buffer
7 in the AVDRMFrameDescriptor like it is done in rkmpp.
8
9 This 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
15 This was developed in conjunction with Kodi to allow handling the zero-copy buffer rendering.
16 A simply utility for testing is also available here: https://github.com/BayLibre/ffmpeg-drm
17
18 todo:
19  - allow selecting pixel format output from decoder
20  - allow configuring amount of output and capture buffers
21
22 V2:
23  - allow selecting AV_PIX_FMT_DRM_PRIME
24
25 V3:
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
31 V4:
32  - rebased on 4.2.2
33
34 V5:
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
44 diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
45 index 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  
262 diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
263 index 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;
284 diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
285 index 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)
347 diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
348 index 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 {
361 diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
362 index 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
424 From 9a2a361c2c84c8da54cd3a74b0d0bb966df8fe69 Mon Sep 17 00:00:00 2001
425 From: Lukas Rusak <lorusak@gmail.com>
426 Date: Thu, 16 Aug 2018 21:09:40 -0700
427 Subject: [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
434 diff --git a/configure b/configure
435 index 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"
446 diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
447 index 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
460 From 7b0fa2d859c12a8a129c884d16673ca731336c06 Mon Sep 17 00:00:00 2001
461 From: Lukas Rusak <lorusak@gmail.com>
462 Date: Thu, 16 Aug 2018 21:10:13 -0700
463 Subject: [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
470 diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
471 index 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
488 From e1857456c8f24e40d5c898886f2f51014e59ee9d Mon Sep 17 00:00:00 2001
489 From: Lukas Rusak <lorusak@gmail.com>
490 Date: Thu, 16 Aug 2018 21:10:53 -0700
491 Subject: [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
498 diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
499 index 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
532 From c8fc3ea1b5777546f7ec72a54b053a2d4fa9fd59 Mon Sep 17 00:00:00 2001
533 From: Lukas Rusak <lorusak@gmail.com>
534 Date: Thu, 16 Aug 2018 21:11:38 -0700
535 Subject: [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
541 diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
542 index 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
572 From 13f02e940f083f19dbe8b9ac8fc7df45700dd36e Mon Sep 17 00:00:00 2001
573 From: Lukas Rusak <lorusak@gmail.com>
574 Date: Mon, 24 Sep 2018 13:39:31 -0700
575 Subject: [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
584 diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
585 index 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;
624 diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h
625 index 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  /**
637 diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
638 index 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;
650 diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
651 index 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
680 From 34be198b8039c9df434792f19f0985e45419407e Mon Sep 17 00:00:00 2001
681 From: Lukas Rusak <lorusak@gmail.com>
682 Date: Mon, 4 May 2020 13:01:29 -0700
683 Subject: [PATCH 7/9] libavcodec: v4l2m2m: allow lower minimum buffer values
684
685 There is no reason to enforce a high minimum. In the context
686 of streaming only a few output buffers and capture buffers
687 are even needed for continuous playback. This also helps
688 alleviate 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
694 diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
695 index 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];
707 diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
708 index 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
721 From 2956fd1881d28abf6bf77bd9a57866c4ba81d199 Mon Sep 17 00:00:00 2001
722 From: Lukas Rusak <lorusak@gmail.com>
723 Date: Wed, 6 May 2020 11:12:58 -0700
724 Subject: [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
733 diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
734 index 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){
760 diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
761 index 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  /**
780 diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
781 index 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
793 From 2bb6d0cb244590f0c70dd111ed978cd87fa3bee1 Mon Sep 17 00:00:00 2001
794 From: Lukas Rusak <lorusak@gmail.com>
795 Date: Mon, 24 Sep 2018 13:39:56 -0700
796 Subject: [PATCH 9/9] libavcodec: v4l2m2m: implement flush
797
798 ---
799  libavcodec/v4l2_m2m_dec.c | 36 ++++++++++++++++++++++++++++++++++++
800  1 file changed, 36 insertions(+)
801
802 diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
803 index 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.32672 seconds and 3 git commands to generate.