[FFmpeg-devel] [PATCH] Add support for VP9 VDPAU hwaccel decode

ManojGuptaBonda mbonda at nvidia.com
Tue Oct 22 15:06:22 EEST 2019


Support for VDPAU accelerated VP9 decoding was added with libvdpau-1.3.
Support for the same in ffmpeg is added with this patch. Profiles
related to VDPAU VP9 can be found in latest vdpau.h present in
libvdpau-1.3. DRC clips are not supported yet due to
http://trac.ffmpeg.org/ticket/8068

Add VP9 VDPAU to list of hwaccels and supported formats
Added file vdpau_vp9.c and Modified configure to add VDPAU VP9 support.
Mapped VP9 profiles to VDPAU VP9 profiles. Populated the codec specific
params that need to be passed to VDPAU.
---
 Changelog                   |   2 +-
 configure                   |   3 +
 libavcodec/Makefile         |   1 +
 libavcodec/hwaccels.h       |   1 +
 libavcodec/vdpau_internal.h |   3 +
 libavcodec/vdpau_vp9.c      | 242 ++++++++++++++++++++++++++++++++++++
 libavcodec/version.h        |   2 +-
 libavcodec/vp9.c            |   9 +-
 8 files changed, 260 insertions(+), 3 deletions(-)
 create mode 100644 libavcodec/vdpau_vp9.c

diff --git a/Changelog b/Changelog
index 44e41848b2..88feb2a415 100644
--- a/Changelog
+++ b/Changelog
@@ -16,7 +16,7 @@ version <next>:
 - photosensitivity filter
 - anlms filter
 - arnndn filter
-
+- VDPAU VP9 hwaccel
 
 version 4.2:
 - tpad filter
diff --git a/configure b/configure
index 8413826f9e..7f63eebc9d 100755
--- a/configure
+++ b/configure
@@ -2979,6 +2979,8 @@ vp9_nvdec_hwaccel_deps="nvdec"
 vp9_nvdec_hwaccel_select="vp9_decoder"
 vp9_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferVP9_bit_depth"
 vp9_vaapi_hwaccel_select="vp9_decoder"
+vp9_vdpau_hwaccel_deps="vdpau VdpPictureInfoVP9"
+vp9_vdpau_hwaccel_select="vp9_decoder"
 wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel"
 wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel"
 wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel"
@@ -6093,6 +6095,7 @@ check_type "windows.h d3d11.h" "ID3D11VideoContext"
 check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602
 
 check_type "vdpau/vdpau.h" "VdpPictureInfoHEVC"
+check_type "vdpau/vdpau.h" "VdpPictureInfoVP9"
 
 if [ -z "$nvccflags" ]; then
     nvccflags=$nvccflags_default
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 37a84a6bb4..34c3a22116 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -913,6 +913,7 @@ OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL)        += dxva2_vp9.o
 OBJS-$(CONFIG_VP9_DXVA2_HWACCEL)          += dxva2_vp9.o
 OBJS-$(CONFIG_VP9_NVDEC_HWACCEL)          += nvdec_vp9.o
 OBJS-$(CONFIG_VP9_VAAPI_HWACCEL)          += vaapi_vp9.o
+OBJS-$(CONFIG_VP9_VDPAU_HWACCEL)          += vdpau_vp9.o
 OBJS-$(CONFIG_VP8_QSV_HWACCEL)            += qsvdec_other.o
 
 # libavformat dependencies
diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h
index 7d73da8676..6109c89bd6 100644
--- a/libavcodec/hwaccels.h
+++ b/libavcodec/hwaccels.h
@@ -68,6 +68,7 @@ extern const AVHWAccel ff_vp9_d3d11va2_hwaccel;
 extern const AVHWAccel ff_vp9_dxva2_hwaccel;
 extern const AVHWAccel ff_vp9_nvdec_hwaccel;
 extern const AVHWAccel ff_vp9_vaapi_hwaccel;
+extern const AVHWAccel ff_vp9_vdpau_hwaccel;
 extern const AVHWAccel ff_wmv3_d3d11va_hwaccel;
 extern const AVHWAccel ff_wmv3_d3d11va2_hwaccel;
 extern const AVHWAccel ff_wmv3_dxva2_hwaccel;
diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h
index 1ee38dbc55..b6ea078cb2 100644
--- a/libavcodec/vdpau_internal.h
+++ b/libavcodec/vdpau_internal.h
@@ -54,6 +54,9 @@ union VDPAUPictureInfo {
 #ifdef VDP_YCBCR_FORMAT_Y_U_V_444
     VdpPictureInfoHEVC444     hevc_444;
 #endif
+#ifdef VDP_DECODER_PROFILE_VP9_PROFILE_0
+    VdpPictureInfoVP9        vp9;
+#endif
 };
 
 typedef struct VDPAUHWContext {
diff --git a/libavcodec/vdpau_vp9.c b/libavcodec/vdpau_vp9.c
new file mode 100644
index 0000000000..f1ee4ac5e0
--- /dev/null
+++ b/libavcodec/vdpau_vp9.c
@@ -0,0 +1,242 @@
+/*
+ * VP9 HW decode acceleration through VDPAU
+ *
+ * Copyright (c) 2019 Manoj Gupta Bonda
+ *
+ * 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 <vdpau/vdpau.h>
+#include "libavutil/pixdesc.h"
+#include "avcodec.h"
+#include "internal.h"
+#include "vp9data.h"
+#include "vp9dec.h"
+#include "hwaccel.h"
+#include "vdpau.h"
+#include "vdpau_internal.h"
+
+static int vdpau_vp9_start_frame(AVCodecContext *avctx,
+                                  const uint8_t *buffer, uint32_t size)
+{
+    VP9Context *s = avctx->priv_data;
+    VP9SharedContext *h = &(s->s);
+    const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt);
+    if (!pixdesc) {
+        return AV_PIX_FMT_NONE;
+    }
+
+    VP9Frame pic = h->frames[CUR_FRAME];
+    struct vdpau_picture_context *pic_ctx = pic.hwaccel_picture_private;
+    int i;
+
+    VdpPictureInfoVP9 *info = &pic_ctx->info.vp9;
+
+    info->width = avctx->width;
+    info->height = avctx->height;
+    /*  fill LvPictureInfoVP9 struct */
+    info->lastReference  = VDP_INVALID_HANDLE;
+    info->goldenReference = VDP_INVALID_HANDLE;
+    info->altReference = VDP_INVALID_HANDLE;
+
+    if (h->refs[h->h.refidx[0]].f && h->refs[h->h.refidx[0]].f->private_ref) {
+        info->lastReference               = ff_vdpau_get_surface_id(h->refs[h->h.refidx[0]].f);
+    }
+    if (h->refs[h->h.refidx[1]].f && h->refs[h->h.refidx[1]].f->private_ref) {
+        info->goldenReference             = ff_vdpau_get_surface_id(h->refs[h->h.refidx[1]].f);
+    }
+    if (h->refs[h->h.refidx[2]].f && h->refs[h->h.refidx[2]].f->private_ref) {
+        info->altReference                = ff_vdpau_get_surface_id(h->refs[h->h.refidx[2]].f);
+    }
+
+    info->profile                  = h->h.profile;
+    info->frameContextIdx          = h->h.framectxid;
+    info->keyFrame                 = h->h.keyframe;
+    info->showFrame                = !h->h.invisible;
+    info->errorResilient           = h->h.errorres;
+    info->frameParallelDecoding    = h->h.parallelmode;
+
+    info->subSamplingX             = pixdesc->log2_chroma_w;
+    info->subSamplingY             = pixdesc->log2_chroma_h;
+
+    info->intraOnly                = h->h.intraonly;
+    info->allowHighPrecisionMv     = h->h.keyframe ? 0 : h->h.highprecisionmvs;
+    info->refreshEntropyProbs      = h->h.refreshctx;
+
+    info->bitDepthMinus8Luma       = pixdesc->comp[0].depth - 8;
+    info->bitDepthMinus8Chroma     = pixdesc->comp[1].depth - 8;
+
+    info->loopFilterLevel          = h->h.filter.level;
+    info->loopFilterSharpness      = h->h.filter.sharpness;
+    info->modeRefLfEnabled         = h->h.lf_delta.enabled;
+
+    info->log2TileColumns          = h->h.tiling.log2_tile_cols;
+    info->log2TileRows             = h->h.tiling.log2_tile_rows;
+
+    info->segmentEnabled           = h->h.segmentation.enabled;
+    info->segmentMapUpdate         = h->h.segmentation.update_map;
+    info->segmentMapTemporalUpdate = h->h.segmentation.temporal;
+    info->segmentFeatureMode       = h->h.segmentation.absolute_vals;
+
+    info->qpYAc                    = h->h.yac_qi;
+    info->qpYDc                    = h->h.ydc_qdelta;
+    info->qpChDc                   = h->h.uvdc_qdelta;
+    info->qpChAc                   = h->h.uvac_qdelta;
+
+    info->resetFrameContext        = h->h.resetctx;
+    info->mcompFilterType          = h->h.filtermode ^ (h->h.filtermode <= 1);
+    info->uncompressedHeaderSize   = h->h.uncompressed_header_size;
+    info->compressedHeaderSize     = h->h.compressed_header_size;
+    info->refFrameSignBias[0]      = 0;
+
+
+    for (i = 0; i < FF_ARRAY_ELEMS(info->mbModeLfDelta); i++)
+        info->mbModeLfDelta[i] = h->h.lf_delta.mode[i];
+
+    for (i = 0; i < FF_ARRAY_ELEMS(info->mbRefLfDelta); i++)
+        info->mbRefLfDelta[i] = h->h.lf_delta.ref[i];
+
+    for (i = 0; i < FF_ARRAY_ELEMS(info->mbSegmentTreeProbs); i++)
+        info->mbSegmentTreeProbs[i] = h->h.segmentation.prob[i];
+
+    for (i = 0; i < FF_ARRAY_ELEMS(info->activeRefIdx); i++) {
+        info->activeRefIdx[i] = h->h.refidx[i];
+        info->segmentPredProbs[i] = h->h.segmentation.pred_prob[i];
+        info->refFrameSignBias[i + 1] = h->h.signbias[i];
+    }
+
+    for (i = 0; i < FF_ARRAY_ELEMS(info->segmentFeatureEnable); i++) {
+        info->segmentFeatureEnable[i][0] = h->h.segmentation.feat[i].q_enabled;
+        info->segmentFeatureEnable[i][1] = h->h.segmentation.feat[i].lf_enabled;
+        info->segmentFeatureEnable[i][2] = h->h.segmentation.feat[i].ref_enabled;
+        info->segmentFeatureEnable[i][3] = h->h.segmentation.feat[i].skip_enabled;
+
+        info->segmentFeatureData[i][0] = h->h.segmentation.feat[i].q_val;
+        info->segmentFeatureData[i][1] = h->h.segmentation.feat[i].lf_val;
+        info->segmentFeatureData[i][2] = h->h.segmentation.feat[i].ref_val;
+        info->segmentFeatureData[i][3] = 0;
+    }
+
+    switch (avctx->colorspace) {
+    default:
+    case AVCOL_SPC_UNSPECIFIED:
+        info->colorSpace = 0;
+        break;
+    case AVCOL_SPC_BT470BG:
+        info->colorSpace = 1;
+        break;
+    case AVCOL_SPC_BT709:
+        info->colorSpace = 2;
+        break;
+    case AVCOL_SPC_SMPTE170M:
+        info->colorSpace = 3;
+        break;
+    case AVCOL_SPC_SMPTE240M:
+        info->colorSpace = 4;
+        break;
+    case AVCOL_SPC_BT2020_NCL:
+        info->colorSpace = 5;
+        break;
+    case AVCOL_SPC_RESERVED:
+        info->colorSpace = 6;
+        break;
+    case AVCOL_SPC_RGB:
+        info->colorSpace = 7;
+        break;
+    }
+
+    return ff_vdpau_common_start_frame(pic_ctx, buffer, size);
+
+}
+
+static const uint8_t start_code_prefix[3] = { 0x00, 0x00, 0x01 };
+
+static int vdpau_vp9_decode_slice(AVCodecContext *avctx,
+                                   const uint8_t *buffer, uint32_t size)
+{
+    VP9SharedContext *h = avctx->priv_data;
+    VP9Frame pic = h->frames[CUR_FRAME];
+    struct vdpau_picture_context *pic_ctx = pic.hwaccel_picture_private;
+
+    int val;
+
+    val = ff_vdpau_add_buffer(pic_ctx, start_code_prefix, 3);
+    if (val)
+        return val;
+
+    val = ff_vdpau_add_buffer(pic_ctx, buffer, size);
+    if (val)
+        return val;
+
+    return 0;
+}
+
+static int vdpau_vp9_end_frame(AVCodecContext *avctx)
+{
+    VP9SharedContext *h = avctx->priv_data;
+    VP9Frame pic = h->frames[CUR_FRAME];
+    struct vdpau_picture_context *pic_ctx = pic.hwaccel_picture_private;
+
+    int val;
+
+    val = ff_vdpau_common_end_frame(avctx, pic.tf.f, pic_ctx);
+    if (val < 0)
+        return val;
+
+    return 0;
+}
+
+static int vdpau_vp9_init(AVCodecContext *avctx)
+{
+    VdpDecoderProfile profile;
+    uint32_t level = avctx->level;
+
+    switch (avctx->profile) {
+    case FF_PROFILE_VP9_0:
+        profile = VDP_DECODER_PROFILE_VP9_PROFILE_0;
+        break;
+    case FF_PROFILE_VP9_1:
+        profile = VDP_DECODER_PROFILE_VP9_PROFILE_1;
+        break;
+    case FF_PROFILE_VP9_2:
+        profile = VDP_DECODER_PROFILE_VP9_PROFILE_2;
+        break;
+    case FF_PROFILE_VP9_3:
+        profile = VDP_DECODER_PROFILE_VP9_PROFILE_3;
+        break;
+    default:
+        return AVERROR(ENOTSUP);
+    }
+
+    return ff_vdpau_common_init(avctx, profile, level);
+}
+
+const AVHWAccel ff_vp9_vdpau_hwaccel = {
+    .name           = "vp9_vdpau",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_VP9,
+    .pix_fmt        = AV_PIX_FMT_VDPAU,
+    .start_frame    = vdpau_vp9_start_frame,
+    .end_frame      = vdpau_vp9_end_frame,
+    .decode_slice   = vdpau_vp9_decode_slice,
+    .frame_priv_data_size = sizeof(struct vdpau_picture_context),
+    .init           = vdpau_vp9_init,
+    .uninit         = ff_vdpau_common_uninit,
+    .frame_params   = ff_vdpau_common_frame_params,
+    .priv_data_size = sizeof(VDPAUContext),
+    .caps_internal  = HWACCEL_CAP_ASYNC_SAFE,
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 2e047a6f51..0992d1eea6 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #define LIBAVCODEC_VERSION_MAJOR  58
 #define LIBAVCODEC_VERSION_MINOR  59
-#define LIBAVCODEC_VERSION_MICRO 102
+#define LIBAVCODEC_VERSION_MICRO 103
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c
index f16462b1e9..0fd15efed3 100644
--- a/libavcodec/vp9.c
+++ b/libavcodec/vp9.c
@@ -173,7 +173,8 @@ static int update_size(AVCodecContext *avctx, int w, int h)
 #define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + \
                      CONFIG_VP9_D3D11VA_HWACCEL * 2 + \
                      CONFIG_VP9_NVDEC_HWACCEL + \
-                     CONFIG_VP9_VAAPI_HWACCEL)
+                     CONFIG_VP9_VAAPI_HWACCEL + \
+                     CONFIG_VP9_VDPAU_HWACCEL)
     enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts;
     VP9Context *s = avctx->priv_data;
     uint8_t *p;
@@ -188,6 +189,9 @@ static int update_size(AVCodecContext *avctx, int w, int h)
 
         switch (s->pix_fmt) {
         case AV_PIX_FMT_YUV420P:
+#if CONFIG_VP9_VDPAU_HWACCEL
+            *fmtp++ = AV_PIX_FMT_VDPAU;
+#endif
         case AV_PIX_FMT_YUV420P10:
 #if CONFIG_VP9_DXVA2_HWACCEL
             *fmtp++ = AV_PIX_FMT_DXVA2_VLD;
@@ -1816,6 +1820,9 @@ AVCodec ff_vp9_decoder = {
 #endif
 #if CONFIG_VP9_VAAPI_HWACCEL
                                HWACCEL_VAAPI(vp9),
+#endif
+#if CONFIG_VP9_VDPAU_HWACCEL
+                               HWACCEL_VDPAU(vp9),
 #endif
                                NULL
                            },
-- 
2.17.1


-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------


More information about the ffmpeg-devel mailing list