diff mbox

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

Message ID 20171119195228.25719-4-philipl@overt.org
State New
Headers show

Commit Message

Philip Langdale Nov. 19, 2017, 7:52 p.m. UTC
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@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

Comments

Carl Eugen Hoyos Nov. 19, 2017, 10:35 p.m. UTC | #1
2017-11-19 20:52 GMT+01:00 Philip Langdale <philipl@overt.org>:

> gmc_enabled: This seems to map to mc_sel being non-zero, but I also
>              have no samples where that is true.

Iirc, global motion compensation is not supported by hardware decoders.

Carl Eugen
Philip Langdale Nov. 19, 2017, 11:45 p.m. UTC | #2
On Sun, 19 Nov 2017 23:35:24 +0100
Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:

> 2017-11-19 20:52 GMT+01:00 Philip Langdale <philipl@overt.org>:
> 
> > gmc_enabled: This seems to map to mc_sel being non-zero, but I also
> >              have no samples where that is true.  
> 
> Iirc, global motion compensation is not supported by hardware
> decoders.
> 

It's obviously hard to tell when you have no samples and no
documentation, but it would be weird if this flag existed only for the
hardware to give up if gmc was used. Still, it's all academic given the
complete lack of real world usage of gmc.

--phil
Philip Langdale Nov. 20, 2017, 12:09 a.m. UTC | #3
On Sun, 19 Nov 2017 11:52:28 -0800
Philip Langdale <philipl@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@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
Carl Eugen Hoyos Nov. 20, 2017, 12:13 a.m. UTC | #4
2017-11-19 23:35 GMT+01:00 Carl Eugen Hoyos <ceffmpeg@gmail.com>:
> 2017-11-19 20:52 GMT+01:00 Philip Langdale <philipl@overt.org>:
>
>> gmc_enabled: This seems to map to mc_sel being non-zero, but I also
>>              have no samples where that is true.
>
> Iirc, global motion compensation is not supported by hardware decoders.

Or maybe it only works if there is no more than one warppoint.

Carl Eugen
Timo Rothenpieler Nov. 20, 2017, 9:59 a.m. UTC | #5
> Duplicate. Will remove.

Can't really tell if the parameters are in any way correct, but I guess 
time will tell if some sample comes up that breaks it.

lgtm with that duplicate removed
Philip Langdale Nov. 20, 2017, 3:25 p.m. UTC | #6
On Mon, 20 Nov 2017 10:59:52 +0100
Timo Rothenpieler <timo@rothenpieler.org> wrote:

> > Duplicate. Will remove.  
> 
> Can't really tell if the parameters are in any way correct, but I
> guess time will tell if some sample comes up that breaks it.
> 
> lgtm with that duplicate removed
> 

Thanks. I've pushed all three. I learned a bit more about a couple of
the mpeg4 flags and made small updates in the pushed version.

--phil
Michael Niedermayer Nov. 20, 2017, 9:53 p.m. UTC | #7
On Sun, Nov 19, 2017 at 11:52:28AM -0800, Philip Langdale 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.

issues/388/Matrix.Reloaded.Trailer-640x346-XviD-1.0beta2-HE_AAC_subtitled.mkv
seems to use gmc, didnt check how compex or trivial its use is

[...]
Philip Langdale Nov. 21, 2017, 4:10 a.m. UTC | #8
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Mon, 20 Nov 2017 22:53:00 +0100
Michael Niedermayer <michael@niedermayer.cc> wrote:

> On Sun, Nov 19, 2017 at 11:52:28AM -0800, Philip Langdale 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.  

> 

> issues/388/Matrix.Reloaded.Trailer-640x346-XviD-1.0beta2-HE_AAC_subtitled.mkv

> seems to use gmc, didnt check how compex or trivial its use is

> 

> [...]


I think it's as complex as you can get, and the nvidia decoder cannot
handle it properly. With vdpau, cuvid and now nvdec, there are a lot of
visual glitches. Interestingly, the resutls with nvdec are better than
cuvid, so not using the nvidia parser somehow makes things less worse.

I'd love to try a single warp point sample but can't find or generate
one.

- --phil
-----BEGIN PGP SIGNATURE-----

iEYEARECAAYFAloTpz0ACgkQ+NaxlGp1aC5ZgQCaA4FpVgJq6YKS6TkbHxiLque7
6pIAn1kL80I16yvLVZAFSw27Opcw0/tn
=UqY9
-----END PGP SIGNATURE-----
diff mbox

Patch

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;
+    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,
+            .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, \