[FFmpeg-devel] [PATCH 16/25] avcodec/v4l2_m2m_dec: add support for AV_PIX_FMT_DRM_PRIME

Mark Thompson sw at jkqxz.net
Fri Sep 13 03:01:20 EEST 2019


On 03/09/2019 02:02, Aman Gupta wrote:
> From: Aman Gupta <aman at tmm1.net>
> 
> Based on patchset submitted to ffmpeg-devel by Lukas Rusak <lorusak at gmail.com>
> 
> Signed-off-by: Aman Gupta <aman at tmm1.net>
> ---
>  libavcodec/v4l2_m2m_dec.c | 85 ++++++++++++++++++++++++++++++++++++---
>  1 file changed, 80 insertions(+), 5 deletions(-)
> 
> diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> index a3744208f3..6b73d2ffd9 100644
> --- a/libavcodec/v4l2_m2m_dec.c
> +++ b/libavcodec/v4l2_m2m_dec.c
> @@ -23,11 +23,16 @@
>  
>  #include <linux/videodev2.h>
>  #include <sys/ioctl.h>
> +
> +#include "libavutil/hwcontext.h"
> +#include "libavutil/hwcontext_drm.h"
>  #include "libavutil/pixfmt.h"
>  #include "libavutil/pixdesc.h"
>  #include "libavutil/opt.h"
>  #include "libavcodec/avcodec.h"
>  #include "libavcodec/decode.h"
> +#include "libavcodec/hwaccel.h"
> +#include "libavcodec/internal.h"
>  
>  #include "v4l2_context.h"
>  #include "v4l2_m2m.h"
> @@ -39,7 +44,7 @@ static int v4l2_try_start(AVCodecContext *avctx)
>      V4L2Context *const capture = &s->capture;
>      V4L2Context *const output = &s->output;
>      struct v4l2_selection selection;
> -    int ret;
> +    int ret, pix_fmt;
>  
>      /* 1. start the output process */
>      if (!output->streamon) {
> @@ -62,8 +67,13 @@ static int v4l2_try_start(AVCodecContext *avctx)
>      }
>  
>      /* 2.1 update the AVCodecContext */
> -    avctx->pix_fmt = ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
> +    pix_fmt = ff_v4l2_format_v4l2_to_avfmt(capture->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
> +    if (avctx->pix_fmt != AV_PIX_FMT_DRM_PRIME)
> +        avctx->pix_fmt = pix_fmt;
> +    else
> +        avctx->sw_pix_fmt = pix_fmt;
>      capture->av_pix_fmt = avctx->pix_fmt;
> +    capture->sw_pix_fmt = avctx->sw_pix_fmt;
>  
>      /* 3. set the crop parameters */
>      selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> @@ -189,15 +199,42 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx)
>      output->av_codec_id = avctx->codec_id;
>      output->av_pix_fmt  = AV_PIX_FMT_NONE;
>  
> +    /* negotiate drm vs software pixel formats */
> +    avctx->pix_fmt = ff_get_format(avctx, avctx->codec->pix_fmts);

The codec array allows choice between NV12 and YUV420P, but probably only one of those is actually supported?  You need to make this array with the actually-supported format.

Do all V4L2 M2M devices necessarily support VIDIOC_EXPBUF?

> +    switch (avctx->pix_fmt) {
> +    case AV_PIX_FMT_DRM_PRIME:
> +        avctx->sw_pix_fmt = AV_PIX_FMT_NV12;

The previous patch strongly suggests that this is not always true.

> +        break;
> +
> +    case AV_PIX_FMT_NONE:
> +        return 0;

I think this should be an error code - zero indicates success.

> +        break;
> +
> +    default:
> +        break;
> +    }
> +
>      capture->av_codec_id = AV_CODEC_ID_RAWVIDEO;
>      capture->av_pix_fmt = avctx->pix_fmt;
> +    capture->sw_pix_fmt = avctx->sw_pix_fmt;
> +
> +    if (avctx->hw_device_ctx) {
> +        s->device_ref = av_buffer_ref(avctx->hw_device_ctx);
> +    } else {
> +        s->device_ref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_DRM);
> +        if (!s->device_ref)
> +            return AVERROR(ENOMEM);
> +
> +        ret = av_hwdevice_ctx_init(s->device_ref);
> +        if (ret < 0) {
> +            av_buffer_unref(&s->device_ref);
> +            return ret;
> +        }
> +    }
>  
>      ret = ff_v4l2_m2m_codec_init(priv);
>      if (ret) {
>          av_log(avctx, AV_LOG_ERROR, "can't configure decoder\n");
> -        s->self_ref = NULL;
> -        av_buffer_unref(&priv->context_ref);
> -
>          return ret;
>      }
>      s->avctx = avctx;
> @@ -210,6 +247,25 @@ static av_cold int v4l2_decode_close(AVCodecContext *avctx)
>      return ff_v4l2_m2m_codec_end(avctx->priv_data);
>  }
>  
> +static void v4l2_flush(AVCodecContext *avctx)
> +{
> +    V4L2m2mPriv *priv = avctx->priv_data;
> +    V4L2m2mContext* s = priv->context;
> +    int ret;
> +
> +    /* wait for pending buffer references */
> +    if (atomic_load(&s->refcount))
> +        while(sem_wait(&s->refsync) == -1 && errno == EINTR);
> +
> +    ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
> +    if (ret)
> +        av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
> +
> +    ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
> +    if (ret)
> +        av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
> +}
> +
>  #define OFFSET(x) offsetof(V4L2m2mPriv, x)
>  #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
>  
> @@ -220,6 +276,19 @@ static const AVOption options[] = {
>      { NULL},
>  };
>  
> +static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = {
> +    &(const AVCodecHWConfigInternal) {
> +        .public = {
> +            .pix_fmt     = AV_PIX_FMT_DRM_PRIME,
> +            .methods     = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX |
> +                           AV_CODEC_HW_CONFIG_METHOD_INTERNAL,
> +            .device_type = AV_HWDEVICE_TYPE_DRM

The external device doesn't do anything here - this should just be METHOD_INTERNAL and not offer a device type.

(The device is always guessed inside the code, I suppose with the assumption that no system will ever have two decoders.  Possibly some sort of V4L2 device would make sense for proper selection, though I'm not sure how that would work.)

> +        },
> +        .hwaccel = NULL,
> +    },
> +    NULL
> +};
> +
>  #define M2MDEC_CLASS(NAME) \
>      static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \
>          .class_name = #NAME "_v4l2m2m_decoder", \
> @@ -240,7 +309,13 @@ static const AVOption options[] = {
>          .init           = v4l2_decode_init, \
>          .receive_frame  = v4l2_receive_frame, \
>          .close          = v4l2_decode_close, \
> +        .flush          = v4l2_flush, \
> +        .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \
> +                                                         AV_PIX_FMT_NV12, \
> +                                                         AV_PIX_FMT_YUV420P, \
> +                                                         AV_PIX_FMT_NONE}, \

As above, this is likely to be wrong.  It's probably better to leave this empty like other decoders which don't have a fixed format.

>          .bsfs           = bsf_name, \
> +        .hw_configs     = v4l2_m2m_hw_configs, \
>          .capabilities   = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \
>          .caps_internal  = FF_CODEC_CAP_SETS_PKT_DTS, \
>          .wrapper_name   = "v4l2m2m", \
> 

- Mark


More information about the ffmpeg-devel mailing list