[FFmpeg-devel] [PATCH 3/3] avcodec: Implement mpeg4 nvdec hwaccel

Philip Langdale philipl at overt.org
Mon Nov 20 02:09:01 EET 2017


On Sun, 19 Nov 2017 11:52:28 -0800
Philip Langdale <philipl at overt.org> wrote:

> This was predictably nightmarish, given how ridiculous mpeg4 is.
> I had to stare at the cuvid parser output for a long time to work
> out what each field was supposed to be, and even then, I still don't
> fully understand some of them, particularly:
> 
> vop_coded: I think this means whether the vop has a picture shape,
>            and therefore a picture type. I have no samples where
>            this is not the case.
> divx_flags: There's obviously no documentation on what the possible
>             flags are. I simply observed that this is '0' for a
>             normal bitstream and '5' for packed b-frames.
> gmc_enabled: This seems to map to mc_sel being non-zero, but I also
>              have no samples where that is true.
> 
> Also note that as with the vdpau hwaccel, the decoder needs to
> consume the entire frame and not the slice.
> 
> Signed-off-by: Philip Langdale <philipl at overt.org>
> ---
>  Changelog                |   2 +-
>  configure                |   2 +
>  libavcodec/Makefile      |   1 +
>  libavcodec/allcodecs.c   |   1 +
>  libavcodec/h263dec.c     |   3 ++
>  libavcodec/nvdec.c       |   1 +
>  libavcodec/nvdec_mpeg4.c | 121
> +++++++++++++++++++++++++++++++++++++++++++++++
> libavcodec/version.h     |   2 +- 8 files changed, 131 insertions(+),
> 2 deletions(-) create mode 100644 libavcodec/nvdec_mpeg4.c
> 
> diff --git a/Changelog b/Changelog
> index 5a9d183aed..74ed35cfe6 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -13,7 +13,7 @@ version <next>:
>  - PCE support for extended channel layouts in the AAC encoder
>  - native aptX encoder and decoder
>  - Raw aptX muxer and demuxer
> -- NVIDIA NVDEC-accelerated H.264, HEVC, MPEG-1/2, VC1 and VP9
> hwaccel decoding +- NVIDIA NVDEC-accelerated H.264, HEVC, MPEG-1/2/4,
> VC1 and VP9 hwaccel decoding
>  - Intel QSV-accelerated overlay filter
>  - mcompand audio filter
>  - acontrast audio filter
> diff --git a/configure b/configure
> index 35713805fa..36ccf767dd 100755
> --- a/configure
> +++ b/configure
> @@ -2731,6 +2731,8 @@ mpeg2_xvmc_hwaccel_select="mpeg2video_decoder"
>  mpeg4_cuvid_hwaccel_select="mpeg4_cuvid_decoder"
>  mpeg4_mediacodec_hwaccel_deps="mediacodec"
>  mpeg4_mmal_hwaccel_deps="mmal"
> +mpeg4_nvdec_hwaccel_deps="nvdec"
> +mpeg4_nvdec_hwaccel_select="mpeg4_decoder"
>  mpeg4_vaapi_hwaccel_deps="vaapi"
>  mpeg4_vaapi_hwaccel_select="mpeg4_decoder"
>  mpeg4_vdpau_hwaccel_deps="vdpau"
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 0573454c7b..2af957ab72 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -861,6 +861,7 @@ OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL)        +=
> vaapi_mpeg2.o OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL)        +=
> vdpau_mpeg12.o OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) +=
> videotoolbox.o OBJS-$(CONFIG_MPEG2_XVMC_HWACCEL)         +=
> mpegvideo_xvmc.o +OBJS-$(CONFIG_MPEG4_NVDEC_HWACCEL)        +=
> nvdec_mpeg4.o OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL)        +=
> vaapi_mpeg4.o OBJS-$(CONFIG_MPEG4_VDPAU_HWACCEL)        +=
> vdpau_mpeg4.o OBJS-$(CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL) +=
> videotoolbox.o diff --git a/libavcodec/allcodecs.c
> b/libavcodec/allcodecs.c index e9df7049de..85c38c83aa 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -106,6 +106,7 @@ static void register_all(void)
>      REGISTER_HWACCEL(MPEG4_CUVID,       mpeg4_cuvid);
>      REGISTER_HWACCEL(MPEG4_MEDIACODEC,  mpeg4_mediacodec);
>      REGISTER_HWACCEL(MPEG4_MMAL,        mpeg4_mmal);
> +    REGISTER_HWACCEL(MPEG4_NVDEC,       mpeg4_nvdec);
>      REGISTER_HWACCEL(MPEG4_VAAPI,       mpeg4_vaapi);
>      REGISTER_HWACCEL(MPEG4_VDPAU,       mpeg4_vdpau);
>      REGISTER_HWACCEL(MPEG4_VIDEOTOOLBOX, mpeg4_videotoolbox);
> diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
> index c7cf4bc0c2..b222de793b 100644
> --- a/libavcodec/h263dec.c
> +++ b/libavcodec/h263dec.c
> @@ -714,6 +714,9 @@ const enum AVPixelFormat
> ff_h263_hwaccel_pixfmt_list_420[] = { #if CONFIG_H263_VAAPI_HWACCEL
> || CONFIG_MPEG4_VAAPI_HWACCEL AV_PIX_FMT_VAAPI,
>  #endif
> +#if CONFIG_MPEG4_NVDEC_HWACCEL
> +    AV_PIX_FMT_CUDA,
> +#endif
>  #if CONFIG_MPEG4_VDPAU_HWACCEL
>      AV_PIX_FMT_VDPAU,
>  #endif
> diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c
> index d5cf1058cb..efcd47a7f7 100644
> --- a/libavcodec/nvdec.c
> +++ b/libavcodec/nvdec.c
> @@ -56,6 +56,7 @@ static int map_avcodec_id(enum AVCodecID id)
>      case AV_CODEC_ID_HEVC:       return cudaVideoCodec_HEVC;
>      case AV_CODEC_ID_MPEG1VIDEO: return cudaVideoCodec_MPEG1;
>      case AV_CODEC_ID_MPEG2VIDEO: return cudaVideoCodec_MPEG2;
> +    case AV_CODEC_ID_MPEG4:      return cudaVideoCodec_MPEG4;
>      case AV_CODEC_ID_VC1:        return cudaVideoCodec_VC1;
>      case AV_CODEC_ID_VP9:        return cudaVideoCodec_VP9;
>      case AV_CODEC_ID_WMV3:       return cudaVideoCodec_VC1;
> diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c
> new file mode 100644
> index 0000000000..be81bd958b
> --- /dev/null
> +++ b/libavcodec/nvdec_mpeg4.c
> @@ -0,0 +1,121 @@
> +/*
> + * MPEG-4 Part 2 HW decode acceleration through NVDEC
> + *
> + * Copyright (c) 2017 Philip Langdale
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> + */
> +
> +#include "avcodec.h"
> +#include "mpeg4video.h"
> +#include "nvdec.h"
> +#include "decode.h"
> +
> +static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const
> uint8_t *buffer, uint32_t size) +{
> +    Mpeg4DecContext *m = avctx->priv_data;
> +    MpegEncContext *s = &m->m;
> +
> +    NVDECContext      *ctx = avctx->internal->hwaccel_priv_data;
> +    CUVIDPICPARAMS     *pp = &ctx->pic_params;
> +    CUVIDPICPARAMS     *picparams = &ctx->pic_params;

Duplicate. Will remove.

> +    CUVIDMPEG4PICPARAMS *ppc = &pp->CodecSpecific.mpeg4;
> +    FrameDecodeData *fdd;
> +    NVDECFrame *cf;
> +    AVFrame *cur_frame = s->current_picture.f;
> +
> +    int ret, i;
> +
> +    ret = ff_nvdec_start_frame(avctx, cur_frame);
> +    if (ret < 0)
> +        return ret;
> +
> +    fdd = (FrameDecodeData*)cur_frame->private_ref->data;
> +    cf  = (NVDECFrame*)fdd->hwaccel_priv;
> +
> +    *pp = (CUVIDPICPARAMS) {
> +        .PicWidthInMbs     = (cur_frame->width  + 15) / 16,
> +        .FrameHeightInMbs  = (cur_frame->height + 15) / 16,
> +        .CurrPicIdx        = cf->idx,
> +
> +        .intra_pic_flag    = s->pict_type == AV_PICTURE_TYPE_I,
> +        .ref_pic_flag      = s->pict_type == AV_PICTURE_TYPE_I ||
> +                             s->pict_type == AV_PICTURE_TYPE_P ||
> +                             s->pict_type == AV_PICTURE_TYPE_S,
> +
> +        .CodecSpecific.mpeg4 = {
> +            .ForwardRefIdx                =
> ff_nvdec_get_ref_idx(s->last_picture.f),
> +            .BackwardRefIdx               =
> ff_nvdec_get_ref_idx(s->next_picture.f), +
> +            .video_object_layer_width     = s->width,
> +            .video_object_layer_height    = s->height,
> +            .vop_time_increment_bitcount  = m->time_increment_bits,
> +            .top_field_first              = s->top_field_first,
> +            .resync_marker_disable        = !m->resync_marker,
> +            .quant_type                   = s->mpeg_quant,
> +            .quarter_sample               = s->quarter_sample,
> +            .short_video_header           = avctx->codec->id ==
> AV_CODEC_ID_H263,
> +            .divx_flags                   = s->divx_packed ? 5 : 0,
> +
> +            .vop_coding_type              = s->pict_type -
> AV_PICTURE_TYPE_I,
> +            .vop_coded                    = m->shape != RECT_SHAPE,

Logic is reversed from what I intended, but playback works either way so
who knows. Should be m->shape == RECT_SHAPE.

> +            .vop_rounding_type            = s->no_rounding,
> +            .alternate_vertical_scan_flag = s->alternate_scan,
> +            .interlaced                   = !s->progressive_sequence,
> +            .vop_fcode_forward            = s->f_code,
> +            .vop_fcode_backward           = s->b_code,
> +            .trd                          = { s->pp_time,
> s->pp_field_time >> 1 },
> +            .trb                          = { s->pb_time,
> s->pb_field_time >> 1 }, +
> +            .gmc_enabled                  = s->mcsel != 0,
> +        }
> +    };
> +
> +    for (i = 0; i < 64; ++i) {
> +        ppc->QuantMatrixIntra[i] = s->intra_matrix[i];
> +        ppc->QuantMatrixInter[i] = s->inter_matrix[i];
> +    }
> +
> +    // We need to pass the full frame buffer and not just the slice
> +    return ff_nvdec_simple_decode_slice(avctx, buffer, size);
> +}
> +
> +static int nvdec_mpeg4_decode_slice(AVCodecContext *avctx, const
> uint8_t *buffer, uint32_t size) +{
> +    return 0;
> +}
> +
> +static int nvdec_mpeg4_frame_params(AVCodecContext *avctx,
> +                                  AVBufferRef *hw_frames_ctx)
> +{
> +    // Each frame can at most have one P and one B reference
> +    return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2);
> +}
> +
> +AVHWAccel ff_mpeg4_nvdec_hwaccel = {
> +    .name                 = "mpeg4_nvdec",
> +    .type                 = AVMEDIA_TYPE_VIDEO,
> +    .id                   = AV_CODEC_ID_MPEG4,
> +    .pix_fmt              = AV_PIX_FMT_CUDA,
> +    .start_frame          = nvdec_mpeg4_start_frame,
> +    .end_frame            = ff_nvdec_simple_end_frame,
> +    .decode_slice         = nvdec_mpeg4_decode_slice,
> +    .frame_params         = nvdec_mpeg4_frame_params,
> +    .init                 = ff_nvdec_decode_init,
> +    .uninit               = ff_nvdec_decode_uninit,
> +    .priv_data_size       = sizeof(NVDECContext),
> +};
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index ff54670ea9..c8550bca9a 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -29,7 +29,7 @@
>  
>  #define LIBAVCODEC_VERSION_MAJOR  58
>  #define LIBAVCODEC_VERSION_MINOR   3
> -#define LIBAVCODEC_VERSION_MICRO 104
> +#define LIBAVCODEC_VERSION_MICRO 105
>  
>  #define LIBAVCODEC_VERSION_INT
> AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \




--phil


More information about the ffmpeg-devel mailing list