[FFmpeg-devel] Add support for RockChip Media Process Platform

Submitted by LongChair . on June 13, 2017, 6:21 a.m.

Details

Message ID CY4PR1701MB1782719C8F6270E56214B03BB4C20@CY4PR1701MB1782.namprd17.prod.outlook.com
State Superseded
Headers show

Commit Message

LongChair . June 13, 2017, 6:21 a.m.
From: LongChair <LongChair@hotmail.com>


This adds hardware decoding for h264 / HEVC / VP8 using MPP Rockchip API.
Will return frames holding a av_drmprime struct in buf[3} that allows drm / dmabuf usage.
Was tested on RK3288 (TinkerBoard) and RK3328.

Additions from patch v1
 - Change AV_PIX_FMT_RKMPP to AV_PIX_FMT_DRMPRIME as any decoder able to output drmprime structures could use that pixel format.
---
 Changelog              |   1 +
 configure              |  12 ++
 libavcodec/Makefile    |   5 +
 libavcodec/allcodecs.c |   6 +
 libavcodec/drmprime.h  |  17 ++
 libavcodec/rkmppdec.c  | 523 +++++++++++++++++++++++++++++++++++++++++++++++++
 libavutil/pixdesc.c    |   4 +
 libavutil/pixfmt.h     |   5 +
 8 files changed, 573 insertions(+)
 create mode 100644 libavcodec/drmprime.h
 create mode 100644 libavcodec/rkmppdec.c

-- 
2.7.4

Comments

Mark Thompson June 13, 2017, 10:17 a.m.
On 13/06/17 07:21, LongChair . wrote:
> From: LongChair <LongChair@hotmail.com>
> 
> This adds hardware decoding for h264 / HEVC / VP8 using MPP Rockchip API.
> Will return frames holding a av_drmprime struct in buf[3} that allows drm / dmabuf usage.
> Was tested on RK3288 (TinkerBoard) and RK3328.
> 
> Additions from patch v1
>  - Change AV_PIX_FMT_RKMPP to AV_PIX_FMT_DRMPRIME as any decoder able to output drmprime structures could use that pixel format.
> ---
>  Changelog              |   1 +
>  configure              |  12 ++
>  libavcodec/Makefile    |   5 +
>  libavcodec/allcodecs.c |   6 +
>  libavcodec/drmprime.h  |  17 ++
>  libavcodec/rkmppdec.c  | 523 +++++++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/pixdesc.c    |   4 +
>  libavutil/pixfmt.h     |   5 +
>  8 files changed, 573 insertions(+)
>  create mode 100644 libavcodec/drmprime.h
>  create mode 100644 libavcodec/rkmppdec.c
> 
> diff --git a/Changelog b/Changelog
> index 3533bdc..498e433 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -52,6 +52,7 @@ version 3.3:
>  - Removed asyncts filter (use af_aresample instead)
>  - Intel QSV-accelerated VP8 video decoding
>  - VAAPI-accelerated deinterlacing
> +- Addition of Rockchip MPP harware decoding
>  
>  
>  version 3.2:
> diff --git a/configure b/configure
> index 4ec8f21..883fc84 100755
> --- a/configure
> +++ b/configure
> @@ -304,6 +304,7 @@ External library support:
>    --disable-nvenc          disable Nvidia video encoding code [autodetect]
>    --enable-omx             enable OpenMAX IL code [no]
>    --enable-omx-rpi         enable OpenMAX IL code for Raspberry Pi [no]
> +  --enable-rkmpp           enable Rockchip Media Process Platform code [no]
>    --disable-vaapi          disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
>    --disable-vda            disable Apple Video Decode Acceleration code [autodetect]
>    --disable-vdpau          disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
> @@ -1607,6 +1608,7 @@ HWACCEL_LIBRARY_LIST="
>      libmfx
>      mmal
>      omx
> +    rkmpp
>  "
>  
>  DOCUMENT_LIST="
> @@ -2616,6 +2618,7 @@ h264_dxva2_hwaccel_select="h264_decoder"
>  h264_mediacodec_hwaccel_deps="mediacodec"
>  h264_mmal_hwaccel_deps="mmal"
>  h264_qsv_hwaccel_deps="libmfx"
> +h264_rkmpp_hwaccel_deps="rkmpp"
>  h264_vaapi_hwaccel_deps="vaapi"
>  h264_vaapi_hwaccel_select="h264_decoder"
>  h264_vda_hwaccel_deps="vda"
> @@ -2634,6 +2637,7 @@ hevc_mediacodec_hwaccel_deps="mediacodec"
>  hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC"
>  hevc_dxva2_hwaccel_select="hevc_decoder"
>  hevc_qsv_hwaccel_deps="libmfx"
> +hevc_rkmpp_hwaccel_deps="rkmpp"
>  hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC"
>  hevc_vaapi_hwaccel_select="hevc_decoder"
>  hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC"
> @@ -2696,6 +2700,7 @@ vp9_cuvid_hwaccel_deps="cuda cuvid"
>  vp9_cuvid_hwaccel_select="vp9_cuvid_decoder"
>  vp8_mediacodec_hwaccel_deps="mediacodec"
>  vp8_qsv_hwaccel_deps="libmfx"
> +vp8_rkmpp_hwaccel_deps="rkmpp"
>  vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9"
>  vp9_d3d11va_hwaccel_select="vp9_decoder"
>  vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9"

Why do these hwaccels exist?  They don't appear to do anything, since you only have hardware surface output anyway.

> ...
> diff --git a/libavcodec/drmprime.h b/libavcodec/drmprime.h
> new file mode 100644
> index 0000000..44816db
> --- /dev/null
> +++ b/libavcodec/drmprime.h
> @@ -0,0 +1,17 @@
> +#ifndef AVCODEC_DRMPRIME_H
> +#define AVCODEC_DRMPRIME_H
> +
> +#include <stdint.h>
> +
> +#define AV_DRMPRIME_NUM_PLANES  4   // maximum number of planes
> +
> +typedef struct av_drmprime {
> +
> +    int strides[AV_DRMPRIME_NUM_PLANES];    // stride in byte of the according plane
> +    int offsets[AV_DRMPRIME_NUM_PLANES];    // offset from start in byte of the according plane
> +    int fds[AV_DRMPRIME_NUM_PLANES];        // file descriptor for the plane, (0) if unused.
> +    uint32_t format;                        // FOURC_CC drm format for the image
> +
> +} av_drmprime;
> +
> +#endif // AVCODEC_DRMPRIME_H

I'm not sure that a structure like this should be baked into the API/ABI now as a generic thing.  Are you confident that it is sufficient to represent any picture in a DRM object which might be used in future?  (Including things like tiling modes, field splitting, other craziness that GPU makers dream up?)

Can you explain the cases you are using this in?  Are you intending to make other components with input / output in this format?

With just this decoder in isolation, it would seem preferable to me to make a structure specific to the API for now (or use the existing one - is MppFrame sufficient?).  If later there are multiple implementations and need for a common structure like this then it will be clearer what the requirements are.  Compare VAAPI and QSV (possibly also CUDA, CUVID, VDPAU?) - they can expose DRM objects, but don't currently in the ffmpeg API because any consumers which want them in that form generally prefer the wrapping object including the relevant metadata anyway.

Also, zero is a valid file descriptor.

Thanks,

- Mark
wm4 June 13, 2017, 11:02 a.m.
On Tue, 13 Jun 2017 11:17:35 +0100
Mark Thompson <sw@jkqxz.net> wrote:

> > +vp8_rkmpp_hwaccel_deps="rkmpp"
> >  vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9"
> >  vp9_d3d11va_hwaccel_select="vp9_decoder"
> >  vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9"  
> 
> Why do these hwaccels exist?  They don't appear to do anything, since you only have hardware surface output anyway.

Well I guess you might have a point - as long as get_format isn't
actually involved, they're technically not needed. And we've apparently
always had hw decoders which can output both sw and hw surfaces, so
this never came up (probably).


I still think there's no harm in adding them.

> > ...
> > diff --git a/libavcodec/drmprime.h b/libavcodec/drmprime.h
> > new file mode 100644
> > index 0000000..44816db
> > --- /dev/null
> > +++ b/libavcodec/drmprime.h
> > @@ -0,0 +1,17 @@
> > +#ifndef AVCODEC_DRMPRIME_H
> > +#define AVCODEC_DRMPRIME_H
> > +
> > +#include <stdint.h>
> > +
> > +#define AV_DRMPRIME_NUM_PLANES  4   // maximum number of planes
> > +
> > +typedef struct av_drmprime {
> > +
> > +    int strides[AV_DRMPRIME_NUM_PLANES];    // stride in byte of the according plane
> > +    int offsets[AV_DRMPRIME_NUM_PLANES];    // offset from start in byte of the according plane
> > +    int fds[AV_DRMPRIME_NUM_PLANES];        // file descriptor for the plane, (0) if unused.
> > +    uint32_t format;                        // FOURC_CC drm format for the image
> > +
> > +} av_drmprime;
> > +
> > +#endif // AVCODEC_DRMPRIME_H  
> 
> I'm not sure that a structure like this should be baked into the API/ABI now as a generic thing.  Are you confident that it is sufficient to represent any picture in a DRM object which might be used in future?  (Including things like tiling modes, field splitting, other craziness that GPU makers dream up?)

This includes the DRM FourCC, which should take most craziness into
account. The RockChip decoder itself does something pretty crazy (10
bit _packed_ _planar_ format, wtf?), and it sort of fits in.

I had similar concerns, and I think I basically requested that all
standard eglCreateImageKHR() parameters for this to be included in this
struct (which was done).

It's true though that drivers could invent additional craziness as
additional EGL attributes, or by adding new DRM API calls.

It boils down to how the DRM kernel API handles these things, which I
don't know. (Not like kernel devs would write docs - they'd possibly be
forced to create something consistent!)

Longchair replied with the EGL mapping as use case, but you can also
map it as DRM framebuffer, which appears to happen around here:

https://github.com/LongChair/mpv/blob/rockchip/video/out/opengl/hwdec_drmprime_drm.c#L102

> Can you explain the cases you are using this in?  Are you intending to make other components with input / output in this format?
> 
> With just this decoder in isolation, it would seem preferable to me to make a structure specific to the API for now (or use the existing one - is MppFrame sufficient?).  If later there are multiple implementations and need for a common structure like this then it will be clearer what the requirements are.  Compare VAAPI and QSV (possibly also CUDA, CUVID, VDPAU?) - they can expose DRM objects, but don't currently in the ffmpeg API because any consumers which want them in that form generally prefer the wrapping object including the relevant metadata anyway.

So output those as MppFrames, and then map them as DRM frames? We'd
have the same issues. Also, the API would be harder to use. The
assumption is that native MppFrames are pretty useless anyway, other
than for using them with the MPP decode API.

> Also, zero is a valid file descriptor.

Technically yes, not sure if we care about that case.
Steven Liu July 4, 2017, 2:59 a.m.
2017-06-13 19:02 GMT+08:00 wm4 <nfxjfg@googlemail.com>:
> On Tue, 13 Jun 2017 11:17:35 +0100
> Mark Thompson <sw@jkqxz.net> wrote:
>
>> > +vp8_rkmpp_hwaccel_deps="rkmpp"
>> >  vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9"
>> >  vp9_d3d11va_hwaccel_select="vp9_decoder"
>> >  vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9"
>>
>> Why do these hwaccels exist?  They don't appear to do anything, since you only have hardware surface output anyway.
>
> Well I guess you might have a point - as long as get_format isn't
> actually involved, they're technically not needed. And we've apparently
> always had hw decoders which can output both sw and hw surfaces, so
> this never came up (probably).
>
>
> I still think there's no harm in adding them.
>
>> > ...
>> > diff --git a/libavcodec/drmprime.h b/libavcodec/drmprime.h
>> > new file mode 100644
>> > index 0000000..44816db
>> > --- /dev/null
>> > +++ b/libavcodec/drmprime.h
>> > @@ -0,0 +1,17 @@
>> > +#ifndef AVCODEC_DRMPRIME_H
>> > +#define AVCODEC_DRMPRIME_H
>> > +
>> > +#include <stdint.h>
>> > +
>> > +#define AV_DRMPRIME_NUM_PLANES  4   // maximum number of planes
>> > +
>> > +typedef struct av_drmprime {
>> > +
>> > +    int strides[AV_DRMPRIME_NUM_PLANES];    // stride in byte of the according plane
>> > +    int offsets[AV_DRMPRIME_NUM_PLANES];    // offset from start in byte of the according plane
>> > +    int fds[AV_DRMPRIME_NUM_PLANES];        // file descriptor for the plane, (0) if unused.
>> > +    uint32_t format;                        // FOURC_CC drm format for the image
>> > +
>> > +} av_drmprime;
>> > +
>> > +#endif // AVCODEC_DRMPRIME_H
>>
>> I'm not sure that a structure like this should be baked into the API/ABI now as a generic thing.  Are you confident that it is sufficient to represent any picture in a DRM object which might be used in future?  (Including things like tiling modes, field splitting, other craziness that GPU makers dream up?)
>
> This includes the DRM FourCC, which should take most craziness into
> account. The RockChip decoder itself does something pretty crazy (10
> bit _packed_ _planar_ format, wtf?), and it sort of fits in.
>
> I had similar concerns, and I think I basically requested that all
> standard eglCreateImageKHR() parameters for this to be included in this
> struct (which was done).
>
> It's true though that drivers could invent additional craziness as
> additional EGL attributes, or by adding new DRM API calls.
>
> It boils down to how the DRM kernel API handles these things, which I
> don't know. (Not like kernel devs would write docs - they'd possibly be
> forced to create something consistent!)
>
> Longchair replied with the EGL mapping as use case, but you can also
> map it as DRM framebuffer, which appears to happen around here:
>
> https://github.com/LongChair/mpv/blob/rockchip/video/out/opengl/hwdec_drmprime_drm.c#L102
>
>> Can you explain the cases you are using this in?  Are you intending to make other components with input / output in this format?
>>
>> With just this decoder in isolation, it would seem preferable to me to make a structure specific to the API for now (or use the existing one - is MppFrame sufficient?).  If later there are multiple implementations and need for a common structure like this then it will be clearer what the requirements are.  Compare VAAPI and QSV (possibly also CUDA, CUVID, VDPAU?) - they can expose DRM objects, but don't currently in the ffmpeg API because any consumers which want them in that form generally prefer the wrapping object including the relevant metadata anyway.
>
> So output those as MppFrames, and then map them as DRM frames? We'd
> have the same issues. Also, the API would be harder to use. The
> assumption is that native MppFrames are pretty useless anyway, other
> than for using them with the MPP decode API.
>
>> Also, zero is a valid file descriptor.
>
> Technically yes, not sure if we care about that case.
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Hello? What about this support? This is a very interesting function :D
wm4 July 4, 2017, 8:27 a.m.
On Tue, 4 Jul 2017 10:59:17 +0800
Steven Liu <lingjiujianke@gmail.com> wrote:

> Hello? What about this support? This is a very interesting function :D

Currently it's discussed what the DRM hwframes API should look like.

Patch hide | download patch | download mbox

diff --git a/Changelog b/Changelog
index 3533bdc..498e433 100644
--- a/Changelog
+++ b/Changelog
@@ -52,6 +52,7 @@  version 3.3:
 - Removed asyncts filter (use af_aresample instead)
 - Intel QSV-accelerated VP8 video decoding
 - VAAPI-accelerated deinterlacing
+- Addition of Rockchip MPP harware decoding
 
 
 version 3.2:
diff --git a/configure b/configure
index 4ec8f21..883fc84 100755
--- a/configure
+++ b/configure
@@ -304,6 +304,7 @@  External library support:
   --disable-nvenc          disable Nvidia video encoding code [autodetect]
   --enable-omx             enable OpenMAX IL code [no]
   --enable-omx-rpi         enable OpenMAX IL code for Raspberry Pi [no]
+  --enable-rkmpp           enable Rockchip Media Process Platform code [no]
   --disable-vaapi          disable Video Acceleration API (mainly Unix/Intel) code [autodetect]
   --disable-vda            disable Apple Video Decode Acceleration code [autodetect]
   --disable-vdpau          disable Nvidia Video Decode and Presentation API for Unix code [autodetect]
@@ -1607,6 +1608,7 @@  HWACCEL_LIBRARY_LIST="
     libmfx
     mmal
     omx
+    rkmpp
 "
 
 DOCUMENT_LIST="
@@ -2616,6 +2618,7 @@  h264_dxva2_hwaccel_select="h264_decoder"
 h264_mediacodec_hwaccel_deps="mediacodec"
 h264_mmal_hwaccel_deps="mmal"
 h264_qsv_hwaccel_deps="libmfx"
+h264_rkmpp_hwaccel_deps="rkmpp"
 h264_vaapi_hwaccel_deps="vaapi"
 h264_vaapi_hwaccel_select="h264_decoder"
 h264_vda_hwaccel_deps="vda"
@@ -2634,6 +2637,7 @@  hevc_mediacodec_hwaccel_deps="mediacodec"
 hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC"
 hevc_dxva2_hwaccel_select="hevc_decoder"
 hevc_qsv_hwaccel_deps="libmfx"
+hevc_rkmpp_hwaccel_deps="rkmpp"
 hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC"
 hevc_vaapi_hwaccel_select="hevc_decoder"
 hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC"
@@ -2696,6 +2700,7 @@  vp9_cuvid_hwaccel_deps="cuda cuvid"
 vp9_cuvid_hwaccel_select="vp9_cuvid_decoder"
 vp8_mediacodec_hwaccel_deps="mediacodec"
 vp8_qsv_hwaccel_deps="libmfx"
+vp8_rkmpp_hwaccel_deps="rkmpp"
 vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9"
 vp9_d3d11va_hwaccel_select="vp9_decoder"
 vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9"
@@ -2736,6 +2741,8 @@  h264_qsv_decoder_deps="libmfx"
 h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec h264_qsv_hwaccel"
 h264_qsv_encoder_deps="libmfx"
 h264_qsv_encoder_select="qsvenc"
+h264_rkmpp_decoder_deps="rkmpp"
+h264_rkmpp_decoder_select="h264_mp4toannexb_bsf rkmpp h264_rkmpp_hwaccel"
 h264_vaapi_encoder_deps="VAEncPictureParameterBufferH264"
 h264_vaapi_encoder_select="vaapi_encode golomb"
 h264_vda_decoder_deps="vda"
@@ -2751,6 +2758,8 @@  hevc_qsv_decoder_deps="libmfx"
 hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec hevc_qsv_hwaccel"
 hevc_qsv_encoder_deps="libmfx"
 hevc_qsv_encoder_select="hevcparse qsvenc"
+hevc_rkmpp_decoder_deps="rkmpp"
+hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf rkmpp hevc_rkmpp_hwaccel"
 hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC"
 hevc_vaapi_encoder_select="vaapi_encode golomb"
 mjpeg_cuvid_decoder_deps="cuda cuvid"
@@ -2789,6 +2798,8 @@  vp8_cuvid_decoder_deps="cuda cuvid"
 vp8_mediacodec_decoder_deps="mediacodec"
 vp8_qsv_decoder_deps="libmfx"
 vp8_qsv_decoder_select="qsvdec vp8_qsv_hwaccel vp8_parser"
+vp8_rkmpp_decoder_deps="rkmpp"
+vp8_rkmpp_decoder_select="rkmpp vp8_rkmpp_hwaccel"
 vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8"
 vp8_vaapi_encoder_select="vaapi_encode"
 vp9_cuvid_decoder_deps="cuda cuvid"
@@ -5917,6 +5928,7 @@  enabled mmal              && { check_lib mmal interface/mmal/mmal.h mmal_port_co
                                  check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } ||
                                die "ERROR: mmal not found" &&
                                check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; }
+enabled rkmpp             && { check_lib rkmpp rockchip/rk_mpi.h mpp_create "-lrockchip_mpp" || die "ERROR : Rockchip MPP was not found."; }
 enabled netcdf            && require_pkg_config netcdf netcdf.h nc_inq_libvers
 enabled openal            && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do
                                check_lib openal 'AL/al.h' alGetError "${al_extralibs}" && break; done } ||
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 0818950..0b1ebd0 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -6,6 +6,7 @@  HEADERS = avcodec.h                                                     \
           avfft.h                                                       \
           d3d11va.h                                                     \
           dirac.h                                                       \
+          drmprime.h                                                    \
           dv_profile.h                                                  \
           dxva2.h                                                       \
           jni.h                                                         \
@@ -19,6 +20,7 @@  HEADERS = avcodec.h                                                     \
           vorbis_parser.h                                               \
           xvmc.h                                                        \
 
+
 OBJS = allcodecs.o                                                      \
        audioconvert.o                                                   \
        avdct.o                                                          \
@@ -334,6 +336,7 @@  OBJS-$(CONFIG_H264_VDA_DECODER)        += vda_h264_dec.o
 OBJS-$(CONFIG_H264_OMX_ENCODER)        += omx.o
 OBJS-$(CONFIG_H264_QSV_DECODER)        += qsvdec_h2645.o
 OBJS-$(CONFIG_H264_QSV_ENCODER)        += qsvenc_h264.o
+OBJS-$(CONFIG_H264_RKMPP_DECODER)      += rkmppdec.o
 OBJS-$(CONFIG_H264_VAAPI_ENCODER)      += vaapi_encode_h264.o vaapi_encode_h26x.o
 OBJS-$(CONFIG_H264_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o
 OBJS-$(CONFIG_HAP_DECODER)             += hapdec.o hap.o
@@ -348,6 +351,7 @@  OBJS-$(CONFIG_NVENC_HEVC_ENCODER)      += nvenc_hevc.o
 OBJS-$(CONFIG_HEVC_QSV_DECODER)        += qsvdec_h2645.o
 OBJS-$(CONFIG_HEVC_QSV_ENCODER)        += qsvenc_hevc.o hevc_ps_enc.o       \
                                           hevc_data.o
+OBJS-$(CONFIG_HEVC_RKMPP_DECODER)      += rkmppdec.o
 OBJS-$(CONFIG_HEVC_VAAPI_ENCODER)      += vaapi_encode_h265.o vaapi_encode_h26x.o
 OBJS-$(CONFIG_HNM4_VIDEO_DECODER)      += hnm4video.o
 OBJS-$(CONFIG_HQ_HQA_DECODER)          += hq_hqa.o hq_hqadata.o hq_hqadsp.o \
@@ -618,6 +622,7 @@  OBJS-$(CONFIG_VP8_DECODER)             += vp8.o vp56rac.o
 OBJS-$(CONFIG_VP8_CUVID_DECODER)       += cuvid.o
 OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER)  += mediacodecdec.o
 OBJS-$(CONFIG_VP8_QSV_DECODER)         += qsvdec_other.o
+OBJS-$(CONFIG_VP8_RKMPP_DECODER)       += rkmppdec.o
 OBJS-$(CONFIG_VP8_VAAPI_ENCODER)       += vaapi_encode_vp8.o
 OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9recon.o \
                                           vp9block.o vp9prob.o vp9mvs.o vp56rac.o \
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 89fadcd..95d90fb 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -70,6 +70,7 @@  static void register_all(void)
     REGISTER_HWACCEL(H264_MEDIACODEC,   h264_mediacodec);
     REGISTER_HWACCEL(H264_MMAL,         h264_mmal);
     REGISTER_HWACCEL(H264_QSV,          h264_qsv);
+    REGISTER_HWACCEL(H264_RKMPP,        h264_rkmpp);
     REGISTER_HWACCEL(H264_VAAPI,        h264_vaapi);
     REGISTER_HWACCEL(H264_VDA,          h264_vda);
     REGISTER_HWACCEL(H264_VDA_OLD,      h264_vda_old);
@@ -80,6 +81,7 @@  static void register_all(void)
     REGISTER_HWACCEL(HEVC_DXVA2,        hevc_dxva2);
     REGISTER_HWACCEL(HEVC_MEDIACODEC,   hevc_mediacodec);
     REGISTER_HWACCEL(HEVC_QSV,          hevc_qsv);
+    REGISTER_HWACCEL(HEVC_RKMPP,        hevc_rkmpp);
     REGISTER_HWACCEL(HEVC_VAAPI,        hevc_vaapi);
     REGISTER_HWACCEL(HEVC_VDPAU,        hevc_vdpau);
     REGISTER_HWACCEL(MJPEG_CUVID,       mjpeg_cuvid);
@@ -112,6 +114,7 @@  static void register_all(void)
     REGISTER_HWACCEL(VP8_CUVID,         vp8_cuvid);
     REGISTER_HWACCEL(VP8_MEDIACODEC,    vp8_mediacodec);
     REGISTER_HWACCEL(VP8_QSV,           vp8_qsv);
+    REGISTER_HWACCEL(VP8_RKMPP,         vp8_rkmpp);
     REGISTER_HWACCEL(VP9_CUVID,         vp9_cuvid);
     REGISTER_HWACCEL(VP9_D3D11VA,       vp9_d3d11va);
     REGISTER_HWACCEL(VP9_DXVA2,         vp9_dxva2);
@@ -204,6 +207,7 @@  static void register_all(void)
     REGISTER_DECODER(H264_MEDIACODEC,   h264_mediacodec);
     REGISTER_DECODER(H264_MMAL,         h264_mmal);
     REGISTER_DECODER(H264_QSV,          h264_qsv);
+    REGISTER_DECODER(H264_RKMPP,        h264_rkmpp);
     REGISTER_DECODER(H264_VDA,          h264_vda);
 #if FF_API_VDPAU
     REGISTER_DECODER(H264_VDPAU,        h264_vdpau);
@@ -211,6 +215,7 @@  static void register_all(void)
     REGISTER_ENCDEC (HAP,               hap);
     REGISTER_DECODER(HEVC,              hevc);
     REGISTER_DECODER(HEVC_QSV,          hevc_qsv);
+    REGISTER_DECODER(HEVC_RKMPP,        hevc_rkmpp);
     REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
     REGISTER_DECODER(HQ_HQA,            hq_hqa);
     REGISTER_DECODER(HQX,               hqx);
@@ -363,6 +368,7 @@  static void register_all(void)
     REGISTER_DECODER(VP6F,              vp6f);
     REGISTER_DECODER(VP7,               vp7);
     REGISTER_DECODER(VP8,               vp8);
+    REGISTER_DECODER(VP8_RKMPP,         vp8_rkmpp);
     REGISTER_DECODER(VP9,               vp9);
     REGISTER_DECODER(VQA,               vqa);
     REGISTER_DECODER(BITPACKED,         bitpacked);
diff --git a/libavcodec/drmprime.h b/libavcodec/drmprime.h
new file mode 100644
index 0000000..44816db
--- /dev/null
+++ b/libavcodec/drmprime.h
@@ -0,0 +1,17 @@ 
+#ifndef AVCODEC_DRMPRIME_H
+#define AVCODEC_DRMPRIME_H
+
+#include <stdint.h>
+
+#define AV_DRMPRIME_NUM_PLANES  4   // maximum number of planes
+
+typedef struct av_drmprime {
+
+    int strides[AV_DRMPRIME_NUM_PLANES];    // stride in byte of the according plane
+    int offsets[AV_DRMPRIME_NUM_PLANES];    // offset from start in byte of the according plane
+    int fds[AV_DRMPRIME_NUM_PLANES];        // file descriptor for the plane, (0) if unused.
+    uint32_t format;                        // FOURC_CC drm format for the image
+
+} av_drmprime;
+
+#endif // AVCODEC_DRMPRIME_H
diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c
new file mode 100644
index 0000000..5073b84
--- /dev/null
+++ b/libavcodec/rkmppdec.c
@@ -0,0 +1,523 @@ 
+/*
+ * RockChip MPP Video Decoder
+ * Copyright (c) 2017 Lionel CHAZALLON
+ *
+ * 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 <drm/drm_fourcc.h>
+#include <pthread.h>
+#include <rockchip/mpp_buffer.h>
+#include <rockchip/rk_mpi.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "avcodec.h"
+#include "decode.h"
+#include "drmprime.h"
+#include "internal.h"
+#include "libavutil/buffer.h"
+#include "libavutil/common.h"
+#include "libavutil/frame.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+
+#define RECEIVE_FRAME_TIMEOUT   100
+#define FRAMEGROUP_MAX_FRAMES   16
+
+typedef struct {
+    MppCtx ctx;
+    MppApi *mpi;
+    MppBufferGroup frame_group;
+
+    char first_frame;
+    char first_packet;
+    char eos_reached;
+} RKMPPDecoder;
+
+typedef struct {
+    AVClass *av_class;
+    AVBufferRef *decoder_ref;
+} RKMPPDecodeContext;
+
+typedef struct {
+    MppFrame frame;
+    AVBufferRef *decoder_ref;
+} RKMPPFrameContext;
+
+static MppCodingType ffrkmpp_get_codingtype(AVCodecContext *avctx)
+{
+    switch (avctx->codec_id) {
+    case AV_CODEC_ID_H264:  return MPP_VIDEO_CodingAVC;
+    case AV_CODEC_ID_HEVC:  return MPP_VIDEO_CodingHEVC;
+    case AV_CODEC_ID_VP8:   return MPP_VIDEO_CodingVP8;
+    default:                return MPP_VIDEO_CodingUnused;
+    }
+}
+
+static int ffrkmpp_get_frameformat(MppFrameFormat mppformat)
+{
+    switch (mppformat) {
+    case MPP_FMT_YUV420SP:          return DRM_FORMAT_NV12;
+#ifdef DRM_FORMAT_NV12_10
+    case MPP_FMT_YUV420SP_10BIT:    return DRM_FORMAT_NV12_10;
+#endif
+    default:                        return 0;
+    }
+}
+
+static int ffrkmpp_write_data(AVCodecContext *avctx, uint8_t *buffer, int size, int64_t pts)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+    MPP_RET ret = MPP_NOK;
+    MppPacket packet;
+
+    // create the MPP packet
+    ret = mpp_packet_init(&packet, buffer, size);
+    if (ret != MPP_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to init MPP packet (code = %d)\n", ret);
+        return AVERROR_UNKNOWN;
+    }
+
+    mpp_packet_set_pts(packet, pts);
+
+    if (!buffer)
+        mpp_packet_set_eos(packet);
+
+    ret = decoder->mpi->decode_put_packet(decoder->ctx, packet);
+    if (ret != MPP_OK) {
+        if (ret == MPP_ERR_BUFFER_FULL) {
+            av_log(avctx, AV_LOG_DEBUG, "Buffer full writing %d bytes to decoder\n", size);
+            ret = AVERROR(EAGAIN);
+        } else
+            ret = AVERROR_UNKNOWN;
+    }
+    else
+        av_log(avctx, AV_LOG_DEBUG, "Wrote %d bytes to decoder\n", size);
+
+    mpp_packet_deinit(&packet);
+
+    return ret;
+}
+
+static int ffrkmpp_close_decoder(AVCodecContext *avctx)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    av_buffer_unref(&rk_context->decoder_ref);
+    return 0;
+}
+
+static void ffrkmpp_release_decoder(void *opaque, uint8_t *data)
+{
+    RKMPPDecoder *decoder = (RKMPPDecoder *)data;
+
+    decoder->mpi->reset(decoder->ctx);
+    mpp_destroy(decoder->ctx);
+    decoder->ctx = NULL;
+
+    if (decoder->frame_group) {
+        mpp_buffer_group_put(decoder->frame_group);
+        decoder->frame_group = NULL;
+    }
+
+    av_free(decoder);
+}
+
+static int ffrkmpp_init_decoder(AVCodecContext *avctx)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    RKMPPDecoder *decoder = NULL;
+    MppCodingType codectype = MPP_VIDEO_CodingUnused;
+    MPP_RET ret = MPP_NOK;
+    RK_S64 paramS64;
+    RK_S32 paramS32;
+
+    if ((ret = ff_get_format(avctx, avctx->codec->pix_fmts)) < 0)
+        return ret;
+
+    avctx->pix_fmt = ret;
+
+    // create a decoder and a ref to it
+    decoder = av_mallocz(sizeof(RKMPPDecoder));
+    if (!decoder) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    rk_context->decoder_ref = av_buffer_create((uint8_t *)decoder, sizeof(*decoder), ffrkmpp_release_decoder,
+                                               NULL, AV_BUFFER_FLAG_READONLY);
+    if (!rk_context->decoder_ref) {
+        av_free(decoder);
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    av_log(avctx, AV_LOG_DEBUG, "Initializing RKMPP decoder.\n");
+
+    codectype = ffrkmpp_get_codingtype(avctx);
+    if (codectype == MPP_VIDEO_CodingUnused) {
+        av_log(avctx, AV_LOG_ERROR, "Unknown codec type (%d).\n", avctx->codec_id);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    // Create the MPP context
+    ret = mpp_create(&decoder->ctx, &decoder->mpi);
+    if (ret != MPP_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to create MPP context (code = %d).\n", ret);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    // initialize mpp
+    ret = mpp_init(decoder->ctx, MPP_CTX_DEC, codectype);
+    if (ret != MPP_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to initialize MPP context (code = %d).\n", ret);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    // make decode calls blocking with a timeout
+    paramS32 = MPP_POLL_BLOCK;
+    ret = decoder->mpi->control(decoder->ctx, MPP_SET_OUTPUT_BLOCK, &paramS32);
+    if (ret != MPP_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to set blocking mode on MPI (code = %d).\n", ret);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    paramS64 = RECEIVE_FRAME_TIMEOUT;
+    ret = decoder->mpi->control(decoder->ctx, MPP_SET_OUTPUT_BLOCK_TIMEOUT, &paramS64);
+    if (ret != MPP_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to set block timeout on MPI (code = %d).\n", ret);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    ret = mpp_buffer_group_get_internal(&decoder->frame_group, MPP_BUFFER_TYPE_ION);
+    if (ret) {
+       av_log(avctx, AV_LOG_ERROR, "Failed to retrieve buffer group (code = %d)\n", ret);
+       ret = AVERROR_UNKNOWN;
+       goto fail;
+    }
+
+    ret = decoder->mpi->control(decoder->ctx, MPP_DEC_SET_EXT_BUF_GROUP, decoder->frame_group);
+    if (ret) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to assign buffer group (code = %d)\n", ret);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    ret = mpp_buffer_group_limit_config(decoder->frame_group, 0, FRAMEGROUP_MAX_FRAMES);
+    if (ret) {
+        av_log(avctx, AV_LOG_ERROR, "Failed to set buffer group limit (code = %d)\n", ret);
+        ret = AVERROR_UNKNOWN;
+        goto fail;
+    }
+
+    decoder->first_packet = 1;
+
+    av_log(avctx, AV_LOG_DEBUG, "RKMPP decoder initialized successfully.\n");
+    return 0;
+
+fail:
+    av_log(avctx, AV_LOG_ERROR, "Failed to initialize RKMPP decoder.\n");
+    ffrkmpp_close_decoder(avctx);
+    return ret;
+}
+
+static int ffrkmpp_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+    MPP_RET ret = MPP_NOK;
+
+    // handle EOF
+    if (!avpkt->size) {
+        av_log(avctx, AV_LOG_DEBUG, "End of stream.\n");
+        decoder->eos_reached = 1;
+        ret = ffrkmpp_write_data(avctx, NULL, 0, 0);
+        if (ret)
+            av_log(avctx, AV_LOG_ERROR, "Failed to send EOS to decoder (code = %d)\n", ret);
+        return ret;
+    }
+
+    // on first packet, send extradata
+    if (decoder->first_packet) {
+        if (avctx->extradata_size) {
+            ret = ffrkmpp_write_data(avctx, avctx->extradata,
+                                            avctx->extradata_size,
+                                            avpkt->pts);
+            if (ret) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to write extradata to decoder (code = %d)\n", ret);
+                return ret;
+            }
+        }
+        decoder->first_packet = 0;
+    }
+
+    // now send packet
+    ret = ffrkmpp_write_data(avctx, avpkt->data, avpkt->size, avpkt->pts);
+    if (ret)
+        av_log(avctx, AV_LOG_ERROR, "Failed to write data to decoder (code = %d)\n", ret);
+
+    return ret;
+}
+
+static void ffrkmpp_release_frame(void *opaque, uint8_t *data)
+{
+    av_drmprime *primedata = (av_drmprime *)data;
+    AVBufferRef *framecontextref = (AVBufferRef *)opaque;
+    RKMPPFrameContext *framecontext = (RKMPPFrameContext *)framecontextref->data;
+
+    mpp_frame_deinit(&framecontext->frame);
+    av_buffer_unref(&framecontext->decoder_ref);
+    av_buffer_unref(&framecontextref);
+
+    av_free(primedata);
+}
+
+static int ffrkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+    RKMPPFrameContext *framecontext = NULL;
+    AVBufferRef *framecontextref = NULL;
+    MPP_RET ret = MPP_NOK;
+    MppFrame mppframe = NULL;
+    MppBuffer buffer = NULL;
+    av_drmprime *primedata = NULL;
+    int retrycount = 0;
+
+    // on start of decoding, MPP can return -1, which is supposed to be expected
+    // this is due to some internal MPP init which is not completed, that will
+    // only happen in the first few frames queries, but should not be interpreted
+    // as an error, Therefore we need to retry a couple times when we get -1
+    // in order to let it time to complete it's init, then we sleep a bit between retries.
+retry_get_frame:
+    ret = decoder->mpi->decode_get_frame(decoder->ctx, &mppframe);
+    if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) {
+        if (retrycount < 5) {
+            av_log(avctx, AV_LOG_DEBUG, "Failed to get a frame, retrying (code = %d, retrycount = %d)\n", ret, retrycount);
+            usleep(10000);
+            retrycount++;
+            goto retry_get_frame;
+        } else {
+            av_log(avctx, AV_LOG_ERROR, "Failed to get a frame from MPP (code = %d)\n", ret);
+            goto fail;
+        }
+    }
+
+    if (mppframe) {
+        // Check wether we have a special frame or not
+        if (mpp_frame_get_info_change(mppframe)) {
+            av_log(avctx, AV_LOG_INFO, "Decoder noticed an info change (%dx%d), format=%d\n",
+                                        (int)mpp_frame_get_width(mppframe), (int)mpp_frame_get_height(mppframe),
+                                        (int)mpp_frame_get_fmt(mppframe));
+
+            avctx->width = mpp_frame_get_width(mppframe);
+            avctx->height = mpp_frame_get_height(mppframe);
+
+            decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
+            decoder->first_frame = 1;
+
+            // here decoder is fully initialized, we need to feed it again with data
+            ret = AVERROR(EAGAIN);
+            goto fail;
+        } else if (mpp_frame_get_eos(mppframe)) {
+            av_log(avctx, AV_LOG_DEBUG, "Received a EOS frame.\n");
+            decoder->eos_reached = 1;
+            ret = AVERROR_EOF;
+            goto fail;
+        } else if (mpp_frame_get_discard(mppframe) || mpp_frame_get_errinfo(mppframe)) {
+            av_log(avctx, AV_LOG_DEBUG, "Received a discard/errinfo frame.\n");
+            ret = AVERROR(EAGAIN);
+            goto fail;
+        }
+
+        // here we should have a valid frame
+        av_log(avctx, AV_LOG_DEBUG, "Received a frame.\n");
+
+        // setup general frame fields
+        frame->format   = AV_PIX_FMT_DRMPRIME;
+        frame->width    = mpp_frame_get_width(mppframe);
+        frame->height   = mpp_frame_get_height(mppframe);
+        frame->pts      = mpp_frame_get_pts(mppframe);
+
+        // now setup the frame buffer info
+        buffer = mpp_frame_get_buffer(mppframe);
+        if (buffer) {
+            primedata = av_mallocz(sizeof(av_drmprime));
+            if (!primedata) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            primedata->strides[0]   = mpp_frame_get_hor_stride(mppframe);
+            primedata->strides[1]   = primedata->strides[0];
+            primedata->offsets[0]   = 0;
+            primedata->offsets[1]   = primedata->strides[0] * mpp_frame_get_ver_stride(mppframe);
+            primedata->fds[0]       = mpp_buffer_get_fd(buffer);
+            primedata->fds[1]       = primedata->fds[0];
+            primedata->format       = ffrkmpp_get_frameformat(mpp_frame_get_fmt(mppframe));
+
+            // we also allocate a struct in buf[0] that will allow to hold additionnal information
+            // for releasing properly MPP frames and decoder
+            framecontextref = av_buffer_allocz(sizeof(*framecontext));
+            if (!framecontextref) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            // MPP decoder needs to be closed only when all frames have been released.
+            framecontext = (RKMPPFrameContext *)framecontextref->data;
+            framecontext->decoder_ref = av_buffer_ref(rk_context->decoder_ref);
+            framecontext->frame = mppframe;
+
+            frame->data[3]  = (uint8_t *)primedata;
+            frame->buf[0]   = av_buffer_create((uint8_t *)primedata, sizeof(*primedata), ffrkmpp_release_frame,
+                                               framecontextref, AV_BUFFER_FLAG_READONLY);
+
+            if (!frame->buf[0]) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
+
+            decoder->first_frame = 0;
+            return 0;
+        } else {
+            av_log(avctx, AV_LOG_ERROR, "Failed to retrieve the frame buffer, frame is dropped (code = %d)\n", ret);
+            mpp_frame_deinit(&mppframe);
+        }
+    } else if (decoder->eos_reached) {
+        return AVERROR_EOF;
+    } else if (ret == MPP_ERR_TIMEOUT) {
+        av_log(avctx, AV_LOG_DEBUG, "Timeout when trying to get a frame from MPP\n");
+    }
+
+    return AVERROR(EAGAIN);
+
+fail:
+    if (mppframe)
+        mpp_frame_deinit(&mppframe);
+
+    if (framecontext)
+        av_buffer_unref(&framecontext->decoder_ref);
+
+    if (framecontextref)
+        av_buffer_unref(&framecontextref);
+
+    if (primedata)
+        av_free(primedata);
+
+    return ret;
+}
+
+static int ffrkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+    MPP_RET ret = MPP_NOK;
+    AVPacket pkt = {0};
+    RK_S32 freeslots;
+
+    if (!decoder->eos_reached) {
+        // we get the available slots in decoder
+        ret = decoder->mpi->control(decoder->ctx, MPP_DEC_GET_FREE_PACKET_SLOT_COUNT, &freeslots);
+        if (ret != MPP_OK) {
+            av_log(avctx, AV_LOG_ERROR, "Failed to get decoder free slots (code = %d).\n", ret);
+            return ret;
+        }
+
+        if (freeslots > 0) {
+            ret = ff_decode_get_packet(avctx, &pkt);
+            if (ret < 0 && ret != AVERROR_EOF) {
+                return ret;
+            }
+
+            ret = ffrkmpp_send_packet(avctx, &pkt);
+            av_packet_unref(&pkt);
+
+            if (ret < 0) {
+                av_log(avctx, AV_LOG_ERROR, "Failed to send packet to decoder (code = %d)\n", ret);
+                return ret;
+            }
+        }
+
+        // make sure we keep decoder full
+        if (freeslots > 1 && decoder->first_frame)
+            return AVERROR(EAGAIN);
+    }
+
+    return ffrkmpp_retrieve_frame(avctx, frame);
+}
+
+static void ffrkmpp_flush(AVCodecContext *avctx)
+{
+    RKMPPDecodeContext *rk_context = avctx->priv_data;
+    RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data;
+    MPP_RET ret = MPP_NOK;
+
+    av_log(avctx, AV_LOG_DEBUG, "Flush.\n");
+
+    ret = decoder->mpi->reset(decoder->ctx);
+    if (ret == MPP_OK) {
+        decoder->first_frame = 1;
+        decoder->first_packet = 1;
+    } else
+        av_log(avctx, AV_LOG_ERROR, "Failed to reset MPI (code = %d)\n", ret);
+}
+
+#define FFRKMPP_DEC_HWACCEL(NAME, ID) \
+  AVHWAccel ff_##NAME##_rkmpp_hwaccel = { \
+      .name     = #NAME "_rkmpp", \
+      .type     = AVMEDIA_TYPE_VIDEO,\
+      .id       = ID, \
+      .pix_fmt  = AV_PIX_FMT_DRMPRIME,\
+  };
+
+#define FFRKMPP_DEC_CLASS(NAME) \
+    static const AVClass ffrkmpp_##NAME##_dec_class = { \
+        .class_name = "rkmpp_" #NAME "_dec", \
+        .version    = LIBAVUTIL_VERSION_INT, \
+    };
+
+#define FFRKMPP_DEC(NAME, ID, BSFS) \
+    FFRKMPP_DEC_CLASS(NAME) \
+    FFRKMPP_DEC_HWACCEL(NAME, ID) \
+    AVCodec ff_##NAME##_rkmpp_decoder = { \
+        .name           = #NAME "_rkmpp", \
+        .long_name      = NULL_IF_CONFIG_SMALL(#NAME " (rkmpp)"), \
+        .type           = AVMEDIA_TYPE_VIDEO, \
+        .id             = ID, \
+        .priv_data_size = sizeof(RKMPPDecodeContext), \
+        .init           = ffrkmpp_init_decoder, \
+        .close          = ffrkmpp_close_decoder, \
+        .receive_frame  = ffrkmpp_receive_frame, \
+        .flush          = ffrkmpp_flush, \
+        .priv_class     = &ffrkmpp_##NAME##_dec_class, \
+        .capabilities   = AV_CODEC_CAP_DELAY, \
+        .caps_internal  = FF_CODEC_CAP_SETS_PKT_DTS, \
+        .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRMPRIME, \
+                                                         AV_PIX_FMT_NONE}, \
+        .bsfs           = #BSFS, \
+    };
+
+FFRKMPP_DEC(h264, AV_CODEC_ID_H264, h264_mp4toannexb)
+FFRKMPP_DEC(hevc, AV_CODEC_ID_HEVC, hevc_mp4toannexb)
+FFRKMPP_DEC(vp8,  AV_CODEC_ID_VP8,  )
diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c
index d4a7a8b..1eed823 100644
--- a/libavutil/pixdesc.c
+++ b/libavutil/pixdesc.c
@@ -2028,6 +2028,10 @@  static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
         .name = "cuda",
         .flags = AV_PIX_FMT_FLAG_HWACCEL,
     },
+    [AV_PIX_FMT_DRMPRIME] = {
+        .name = "drmprime",
+        .flags = AV_PIX_FMT_FLAG_HWACCEL,
+    },
     [AV_PIX_FMT_AYUV64LE] = {
         .name = "ayuv64le",
         .nb_components = 4,
diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h
index 6b7eea8..5c128a4 100644
--- a/libavutil/pixfmt.h
+++ b/libavutil/pixfmt.h
@@ -248,6 +248,11 @@  enum AVPixelFormat {
      */
     AV_PIX_FMT_CUDA,
 
+    /**
+     *  HW acceleration allowing to get drmprime information, data[3] contains a av_drmprime pointer
+     */
+    AV_PIX_FMT_DRMPRIME,
+
     AV_PIX_FMT_0RGB=0x123+4,///< packed RGB 8:8:8, 32bpp, XRGBXRGB...   X=unused/undefined
     AV_PIX_FMT_RGB0,        ///< packed RGB 8:8:8, 32bpp, RGBXRGBX...   X=unused/undefined
     AV_PIX_FMT_0BGR,        ///< packed BGR 8:8:8, 32bpp, XBGRXBGR...   X=unused/undefined