diff mbox series

[FFmpeg-devel,1/2] Add support d3d11va Intel Hevc Rext decoder.

Message ID 13e245fe-7b6d-4dbc-a0bc-481deae9b658@mail.ru
State New
Headers show
Series [FFmpeg-devel,1/2] Add support d3d11va Intel Hevc Rext decoder. | expand

Checks

Context Check Description
yinshiyou/commit_msg_loongarch64 warning The first line of the commit message must start with a context terminated by a colon and a space, for example "lavu/opt: " or "doc: ".
andriy/commit_msg_x86 warning The first line of the commit message must start with a context terminated by a colon and a space, for example "lavu/opt: " or "doc: ".
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Водянников А.В. Feb. 25, 2024, 2:22 a.m. UTC
From ed8fda62bbdbc62f7565891c935966c931d001ca Mon Sep 17 00:00:00 2001
From: Aleksoid <Aleksoid1978@mail.ru>
Date: Thu, 22 Feb 2024 19:15:48 +1000
Subject: [PATCH 1/2] Add support d3d11va Intel Hevc Rext decoder.

Signed-off-by: Aleksoid <Aleksoid1978@mail.ru>
---
 libavcodec/d3d12va_hevc.c     |  2 +-
 libavcodec/dxva2.c            | 68 +++++++++++++++++++++++++++++++++--
 libavcodec/dxva2_hevc.c       | 41 ++++++++++++++++++---
 libavcodec/dxva2_internal.h   | 38 +++++++++++++++++++-
 libavcodec/hevcdec.c          | 16 +++++++++
 libavutil/hwcontext_d3d11va.c | 26 +++++++++++---
 6 files changed, 178 insertions(+), 13 deletions(-)

Comments

Mark Thompson Feb. 25, 2024, 10:36 a.m. UTC | #1
On 25/02/2024 02:22, Водянников А.В. via ffmpeg-devel wrote:
 > From ed8fda62bbdbc62f7565891c935966c931d001ca Mon Sep 17 00:00:00 2001
 > From: Aleksoid <Aleksoid1978@mail.ru>
 > Date: Thu, 22 Feb 2024 19:15:48 +1000
 > Subject: [PATCH 1/2] Add support d3d11va Intel Hevc Rext decoder.
 >
 > Signed-off-by: Aleksoid <Aleksoid1978@mail.ru>
 > ---
 >  libavcodec/d3d12va_hevc.c     |  2 +-
 >  libavcodec/dxva2.c            | 68 +++++++++++++++++++++++++++++++++--
 >  libavcodec/dxva2_hevc.c       | 41 ++++++++++++++++++---
 >  libavcodec/dxva2_internal.h   | 38 +++++++++++++++++++-
 >  libavcodec/hevcdec.c          | 16 +++++++++
 >  libavutil/hwcontext_d3d11va.c | 26 +++++++++++---
 >  6 files changed, 178 insertions(+), 13 deletions(-)

What elements are Intel-specific about this?

Presumably there will be an official rext mode for D3D in future; are there any possible problems with having this vendor extension in that case?

 > diff --git a/libavcodec/d3d12va_hevc.c b/libavcodec/d3d12va_hevc.c
 > index a4964a05c6..0912e01b7d 100644
 > --- a/libavcodec/d3d12va_hevc.c
 > +++ b/libavcodec/d3d12va_hevc.c
 > @@ -62,7 +62,7 @@ static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8
 >
 >      ctx->used_mask = 0;
 >
 > -    ff_dxva2_hevc_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, &ctx_pic->pp);
 > +    ff_dxva2_hevc_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, (DXVA_PicParams_HEVC_Rext*)&ctx_pic->pp);

Get the type right to avoid the cast.

 >
 >      ff_dxva2_hevc_fill_scaling_lists(avctx, (AVDXVAContext *)ctx, &ctx_pic->qm);
 >
 > diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
 > index 59025633f7..a611989911 100644
 > --- a/libavcodec/dxva2.c
 > +++ b/libavcodec/dxva2.c
 > @@ -50,6 +50,13 @@ DEFINE_GUID(ff_DXVA2_NoEncrypt,          0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x0
 >  DEFINE_GUID(ff_GUID_NULL,                0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
 >  DEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
 >
 > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main12_Intel,     0x8FF8A3AA, 0xC456, 0x4132, 0xB6, 0xEF, 0x69, 0xD9, 0xDD, 0x72, 0x57, 0x1D);
 > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main422_10_Intel, 0xE484DCB8, 0xCAC9, 0x4859, 0x99, 0xF5, 0x5C, 0x0D, 0x45, 0x06, 0x90, 0x89);
 > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main422_12_Intel, 0xC23DD857, 0x874B, 0x423C, 0xB6, 0xE0, 0x82, 0xCE, 0xAA, 0x9B, 0x11, 0x8A);
 > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_Intel,    0x41A5AF96, 0xE415, 0x4B0C, 0x9D, 0x03, 0x90, 0x78, 0x58, 0xE2, 0x3E, 0x78);
 > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_10_Intel, 0x6A6A81BA, 0x912A, 0x485D, 0xB5, 0x7F, 0xCC, 0xD2, 0xD3, 0x7B, 0x8D, 0x94);
 > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_12_Intel, 0x5B08E35D, 0x0C66, 0x4C51, 0xA6, 0xF1, 0x89, 0xD0, 0x0C, 0xB2, 0xC1, 0x97);

Where are these GUIDs documented?

 > +
 >  typedef struct dxva_mode {
 >      const GUID     *guid;
 >      enum AVCodecID codec;
 > @@ -75,6 +82,8 @@ static const int prof_vp9_profile2[] = {AV_PROFILE_VP9_2,
 >                                          AV_PROFILE_UNKNOWN};
 >  static const int prof_av1_profile0[] = {AV_PROFILE_AV1_MAIN,
 >                                          AV_PROFILE_UNKNOWN};
 > +static const int prof_hevc_rext[]    = {AV_PROFILE_HEVC_REXT,
 > +                                        AV_PROFILE_UNKNOWN};
 >
 >  static const dxva_mode dxva_modes[] = {
 >      /* MPEG-2 */
 > @@ -104,6 +113,14 @@ static const dxva_mode dxva_modes[] = {
 >      /* AV1 */
 >      { &ff_DXVA2_ModeAV1_VLD_Profile0,       AV_CODEC_ID_AV1, prof_av1_profile0 },
 >
 > +    /* HEVC/H.265 Rext */
 > +    { &ff_DXVA2_HEVC_VLD_Main12_Intel,     AV_CODEC_ID_HEVC, prof_hevc_rext },
 > +    { &ff_DXVA2_HEVC_VLD_Main422_10_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
 > +    { &ff_DXVA2_HEVC_VLD_Main422_12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
 > +    { &ff_DXVA2_HEVC_VLD_Main444_Intel,    AV_CODEC_ID_HEVC, prof_hevc_rext },
 > +    { &ff_DXVA2_HEVC_VLD_Main444_10_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
 > +    { &ff_DXVA2_HEVC_VLD_Main444_12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },

Doesn't this need more detail about what the modes actually support?  Declaring that any one of these supports all rext streams does not seem right.

Related: what is the desired behaviour if you have a YUV 4:2:0 8-bit stream but the profile is rext?

 > +
 >      { NULL,                          0 },
 >  };
 >
 > @@ -301,6 +318,14 @@ static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *sur
 >      if (IsEqualGUID(decoder_guid, &ff_DXVADDI_Intel_ModeH264_E))
 >          sctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
 >
 > +    av_log(avctx, AV_LOG_VERBOSE,
 > +           "Used guid : {%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}\n",
 > +           (unsigned)decoder_guid->Data1, decoder_guid->Data2, decoder_guid->Data3,
 > +           decoder_guid->Data4[0], decoder_guid->Data4[1],
 > +           decoder_guid->Data4[2], decoder_guid->Data4[3],
 > +           decoder_guid->Data4[4], decoder_guid->Data4[5],
 > +           decoder_guid->Data4[6], decoder_guid->Data4[7]);
 > +
 >      return 0;
 >  }
 >
 > @@ -458,6 +483,13 @@ static DXGI_FORMAT d3d11va_map_sw_to_hw_format(enum AVPixelFormat pix_fmt)
 >      case AV_PIX_FMT_NV12:       return DXGI_FORMAT_NV12;
 >      case AV_PIX_FMT_P010:       return DXGI_FORMAT_P010;
 >      case AV_PIX_FMT_YUV420P:    return DXGI_FORMAT_420_OPAQUE;
 > +    case AV_PIX_FMT_P016:       return DXGI_FORMAT_P016;

The profiles above suggest that this does not support 16-bit, so you shouldn't have AV_PIX_FMT_P016 here.  Probably you want P012?

(The ffmpeg formats contain the depth information where the DXGI ones are just containers.  You need to set the format correctly or later components will believe there are significant low bits.)

 > +    case AV_PIX_FMT_YUYV422:    return DXGI_FORMAT_YUY2;
 > +    case AV_PIX_FMT_Y210:       return DXGI_FORMAT_Y210;
 > +    case AV_PIX_FMT_Y212:       return DXGI_FORMAT_Y216;
 > +    case AV_PIX_FMT_VUYX:       return DXGI_FORMAT_AYUV;
 > +    case AV_PIX_FMT_XV30:       return DXGI_FORMAT_Y410;
 > +    case AV_PIX_FMT_XV36:       return DXGI_FORMAT_Y416;
 >      default:                    return DXGI_FORMAT_UNKNOWN;
 >      }
 >  }
 > @@ -589,6 +621,39 @@ static void ff_dxva2_unlock(AVCodecContext *avctx)
 >  #endif
 >  }
 >
 > +static enum AVPixelFormat map_sw_pix_format(enum AVPixelFormat pix_fmt, enum AVPixelFormat hw_pix_fmt)
 > +{
 > +#if CONFIG_D3D11VA
 > +    if (hw_pix_fmt == AV_PIX_FMT_D3D11) {

Is this actually locked to be D3D11 only?

 > +        switch (pix_fmt)
 > +        {
 > +        case AV_PIX_FMT_YUV420P10:
 > +        case AV_PIX_FMT_P010:
 > +            return AV_PIX_FMT_P010;
 > +        case AV_PIX_FMT_YUV420P12:
 > +            return AV_PIX_FMT_P016;

Same problem here with it creating extra bit depth out of nowhere.

 > +        case AV_PIX_FMT_YUV422P:
 > +            return AV_PIX_FMT_YUYV422;
 > +        case AV_PIX_FMT_YUV422P10:
 > +            return AV_PIX_FMT_Y210;
 > +        case AV_PIX_FMT_YUV444P:
 > +            return AV_PIX_FMT_VUYX;
 > +        case AV_PIX_FMT_YUV444P10:
 > +            return AV_PIX_FMT_XV30;
 > +        case AV_PIX_FMT_YUV422P12:
 > +            return AV_PIX_FMT_Y212;
 > +        case AV_PIX_FMT_YUV444P12:
 > +            return AV_PIX_FMT_XV36;
 > +        case AV_PIX_FMT_NV12:
 > +        default:
 > +            return AV_PIX_FMT_NV12;
 > +        }
 > +    }
 > +#endif
 > +    return pix_fmt == AV_PIX_FMT_YUV420P10 ?
 > +        AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
 > +}
 > +
 >  int ff_dxva2_common_frame_params(AVCodecContext *avctx,
 >                                   AVBufferRef *hw_frames_ctx)
 >  {
 > @@ -626,8 +691,7 @@ int ff_dxva2_common_frame_params(AVCodecContext *avctx,
 >      else
 >          num_surfaces += 2;
 >
 > -    frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
 > -                            AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
 > +    frames_ctx->sw_format = map_sw_pix_format(avctx->sw_pix_fmt, frames_ctx->format);
 >      frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment);
 >      frames_ctx->height = FFALIGN(avctx->coded_height, surface_alignment);
 >      frames_ctx->initial_pool_size = num_surfaces;
 > diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c
 > index 31d74a7164..7153b2e604 100644
 > --- a/libavcodec/dxva2_hevc.c
 > +++ b/libavcodec/dxva2_hevc.c
 > @@ -32,7 +32,7 @@
 >  #define MAX_SLICES 256
 >
 >  struct hevc_dxva2_picture_context {
 > -    DXVA_PicParams_HEVC   pp;
 > +    DXVA_PicParams_HEVC_Rext   pp;

Use a union here to avoid non-rext code noticing anything about the rext structure?

 >      DXVA_Qmatrix_HEVC     qm;
 >      unsigned              slice_count;
 >      DXVA_Slice_HEVC_Short slice_short[MAX_SLICES];
 > @@ -58,19 +58,49 @@ static int get_refpic_index(const DXVA_PicParams_HEVC *pp, int surface_index)
 >  }
 >
 >  void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx,
 > -                                    DXVA_PicParams_HEVC *pp)
 > +                                    DXVA_PicParams_HEVC_Rext *ppext)
 >  {
 >      const HEVCContext *h = avctx->priv_data;
 >      const HEVCFrame *current_picture = h->ref;
 >      const HEVCSPS *sps = h->ps.sps;
 >      const HEVCPPS *pps = h->ps.pps;
 >      int i, j;
 > +    DXVA_PicParams_HEVC *pp = &ppext->main;
 >
 > -    memset(pp, 0, sizeof(*pp));
 > +    memset(ppext, 0, sizeof(*ppext));
 >
 >      pp->PicWidthInMinCbsY  = sps->min_cb_width;
 >      pp->PicHeightInMinCbsY = sps->min_cb_height;
 >
 > +    if (sps->sps_range_extension_flag) {
 > +        ppext->dwRangeExtensionFlags |= (sps->transform_skip_rotation_enabled_flag     <<  0) |
 > +                                        (sps->transform_skip_context_enabled_flag      <<  1) |
 > +                                        (sps->implicit_rdpcm_enabled_flag              <<  2) |
 > +                                        (sps->explicit_rdpcm_enabled_flag              <<  3) |
 > +                                        (sps->extended_precision_processing_flag       <<  4) |
 > +                                        (sps->intra_smoothing_disabled_flag            <<  5) |
 > +                                        (sps->high_precision_offsets_enabled_flag      <<  5) |

Two << 5 here.  Do you have streams to give test coverage of all of these flags?

Also, given that you have a bitfield representation why not just use it to avoid the manual shifts?

 > +                                        (sps->persistent_rice_adaptation_enabled_flag  <<  7) |
 > +                                        (sps->cabac_bypass_alignment_enabled_flag      <<  8);
 > +    }
 > +    if (pps->pps_range_extensions_flag) {
 > +        ppext->dwRangeExtensionFlags |= (pps->cross_component_prediction_enabled_flag  <<  9) |
 > +                                        (pps->chroma_qp_offset_list_enabled_flag       << 10);
 > +        if (pps->chroma_qp_offset_list_enabled_flag) {
 > +            ppext->diff_cu_chroma_qp_offset_depth   = pps->diff_cu_chroma_qp_offset_depth;
 > +            ppext->chroma_qp_offset_list_len_minus1 = pps->chroma_qp_offset_list_len_minus1;
 > +            for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) {
 > +                ppext->cb_qp_offset_list[i] = pps->cb_qp_offset_list[i];
 > +                ppext->cr_qp_offset_list[i] = pps->cr_qp_offset_list[i];
 > +            }
 > +        }
 > +        ppext->log2_sao_offset_scale_luma   = pps->log2_sao_offset_scale_luma;
 > +        ppext->log2_sao_offset_scale_chroma = pps->log2_sao_offset_scale_chroma;
 > +        if (pps->transform_skip_enabled_flag) {
 > +            ppext->log2_max_transform_skip_block_size_minus2 = pps->log2_max_transform_skip_block_size - 2;
 > +        }
 > +    }

Suggest putting the rext stuff at the end of the function, after all of the common parts.

 > +
 >      pp->wFormatAndSequenceInfoFlags = (sps->chroma_format_idc             <<  0) |
 >                                        (sps->separate_colour_plane_flag    <<  2) |
 >                                        ((sps->bit_depth - 8)               <<  3) |
 > @@ -409,14 +439,15 @@ static int dxva2_hevc_end_frame(AVCodecContext *avctx)
 >  {
 >      HEVCContext *h = avctx->priv_data;
 >      struct hevc_dxva2_picture_context *ctx_pic = h->ref->hwaccel_picture_private;
 > -    int scale = ctx_pic->pp.dwCodingParamToolFlags & 1;
 > +    int scale = ctx_pic->pp.main.dwCodingParamToolFlags & 1;
 > +    int rext = avctx->profile == AV_PROFILE_HEVC_REXT && ff_dxva2_is_d3d11(avctx);
 >      int ret;
 >
 >      if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
 >          return -1;
 >
 >      ret = ff_dxva2_common_end_frame(avctx, h->ref->frame,
 > -                                    &ctx_pic->pp, sizeof(ctx_pic->pp),
 > +                                    &ctx_pic->pp, rext ? sizeof(ctx_pic->pp) : sizeof(ctx_pic->pp.main),
 >                                      scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0,
 >                                      commit_bitstream_and_slice_buffer);
 >      return ret;
 > diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h
 > index 224a867ebc..38e34ce64f 100644
 > --- a/libavcodec/dxva2_internal.h
 > +++ b/libavcodec/dxva2_internal.h
 > @@ -64,6 +64,42 @@
 >  #include <dxva.h>
 >  #endif
 >
 > +#pragma pack(push, 1)
 > +typedef struct
 > +{
 > +    DXVA_PicParams_HEVC main;
 > +
 > +    // HEVC Range Extension
 > +    __C89_NAMELESS union {
 > +        __C89_NAMELESS struct {
 > +            UINT32 transform_skip_rotation_enabled_flag : 1;
 > +            UINT32 transform_skip_context_enabled_flag : 1;
 > +            UINT32 implicit_rdpcm_enabled_flag : 1;
 > +            UINT32 explicit_rdpcm_enabled_flag : 1;
 > +            UINT32 extended_precision_processing_flag : 1;
 > +            UINT32 intra_smoothing_disabled_flag : 1;
 > +            UINT32 high_precision_offsets_enabled_flag : 1;
 > +            UINT32 persistent_rice_adaptation_enabled_flag : 1;
 > +            UINT32 cabac_bypass_alignment_enabled_flag : 1;
 > +            UINT32 cross_component_prediction_enabled_flag : 1;
 > +            UINT32 chroma_qp_offset_list_enabled_flag : 1;
 > +            UINT32 BitDepthLuma16 : 1; // TODO merge in ReservedBits5 if not needed
 > +            UINT32 BitDepthChroma16 : 1; // TODO merge in ReservedBits5 if not needed
 > +            UINT32 ReservedBits8 : 19;
 > +        };
 > +        UINT32 dwRangeExtensionFlags;
 > +    };
 > +
 > +    UCHAR diff_cu_chroma_qp_offset_depth;
 > +    UCHAR chroma_qp_offset_list_len_minus1;
 > +    UCHAR log2_sao_offset_scale_luma;
 > +    UCHAR log2_sao_offset_scale_chroma;
 > +    UCHAR log2_max_transform_skip_block_size_minus2;
 > +    CHAR cb_qp_offset_list[6];
 > +    CHAR cr_qp_offset_list[6];
 > +} DXVA_PicParams_HEVC_Rext;
 > +#pragma pack(pop)

Where is this structure copied from?  (Is it under a licence with any relevant conditions?)

 > +
 >  #include "libavutil/hwcontext.h"
 >
 >  #include "avcodec.h"
 > @@ -171,7 +207,7 @@ void ff_dxva2_h264_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo
 >
 >  void ff_dxva2_h264_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_H264 *qm);
 >
 > -void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC *pp);
 > +void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC_Rext *ppext);
 >
 >  void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_HEVC *qm);
 >
 > diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
 > index b5311ae510..508f279933 100644
 > --- a/libavcodec/hevcdec.c
 > +++ b/libavcodec/hevcdec.c
 > @@ -463,6 +463,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 >  #endif
 >          break;
 >      case AV_PIX_FMT_YUV444P:
 > +#if CONFIG_HEVC_D3D11VA_HWACCEL
 > +        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;

Have you tested this with the legacy API?

 > +        *fmt++ = AV_PIX_FMT_D3D11;
 > +#endif
 >  #if CONFIG_HEVC_VAAPI_HWACCEL
 >          *fmt++ = AV_PIX_FMT_VAAPI;
 >  #endif
 > @@ -481,6 +485,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 >          break;
 >      case AV_PIX_FMT_YUV422P:
 >      case AV_PIX_FMT_YUV422P10LE:
 > +#if CONFIG_HEVC_D3D11VA_HWACCEL
 > +        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
 > +        *fmt++ = AV_PIX_FMT_D3D11;
 > +#endif
 >  #if CONFIG_HEVC_VAAPI_HWACCEL
 >         *fmt++ = AV_PIX_FMT_VAAPI;
 >  #endif
 > @@ -498,6 +506,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 >      /* NOTE: fallthrough */
 >      case AV_PIX_FMT_YUV420P12:
 >      case AV_PIX_FMT_YUV444P12:
 > +#if CONFIG_HEVC_D3D11VA_HWACCEL
 > +        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
 > +        *fmt++ = AV_PIX_FMT_D3D11;
 > +#endif
 >  #if CONFIG_HEVC_VAAPI_HWACCEL
 >         *fmt++ = AV_PIX_FMT_VAAPI;
 >  #endif
 > @@ -512,6 +524,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 >  #endif
 >          break;
 >      case AV_PIX_FMT_YUV422P12:
 > +#if CONFIG_HEVC_D3D11VA_HWACCEL
 > +        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
 > +        *fmt++ = AV_PIX_FMT_D3D11;
 > +#endif
 >  #if CONFIG_HEVC_VAAPI_HWACCEL
 >         *fmt++ = AV_PIX_FMT_VAAPI;
 >  #endif
 > diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
 > index 2fd3561c88..79b1f34b3b 100644
 > --- a/libavutil/hwcontext_d3d11va.c
 > +++ b/libavutil/hwcontext_d3d11va.c

Move the changes to the hwcontext into a separate patch.

 > @@ -94,6 +94,7 @@ static const struct {
 >      { DXGI_FORMAT_Y210,         AV_PIX_FMT_Y210 },
 >      { DXGI_FORMAT_Y410,         AV_PIX_FMT_XV30 },
 >      { DXGI_FORMAT_P016,         AV_PIX_FMT_P012 },
 > +    { DXGI_FORMAT_P016,         AV_PIX_FMT_P016 },

Ok here because it only maps AV -> DXGI.

 >      { DXGI_FORMAT_Y216,         AV_PIX_FMT_Y212 },
 >      { DXGI_FORMAT_Y416,         AV_PIX_FMT_XV36 },
 >      // Special opaque formats. The pix_fmt is merely a place holder, as the
 > @@ -394,11 +395,28 @@ static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
 >                                D3D11_TEXTURE2D_DESC *desc,
 >                                D3D11_MAPPED_SUBRESOURCE *map)
 >  {
 > -    int i;
 > -
 > -    for (i = 0; i < 4; i++)
 > -        linesize[i] = map->RowPitch;
 > +    int width;
 > +    int codedbytes = 1;
 > +
 > +    switch (ctx->sw_format) {
 > +    case AV_PIX_FMT_P010:
 > +    case AV_PIX_FMT_P016:
 > +    case AV_PIX_FMT_YUYV422:
 > +        codedbytes = 2;
 > +        break;
 > +    case AV_PIX_FMT_Y210:
 > +    case AV_PIX_FMT_Y212:
 > +    case AV_PIX_FMT_VUYX:
 > +    case AV_PIX_FMT_XV30:
 > +        codedbytes = 4;
 > +        break;
 > +    case AV_PIX_FMT_XV36:
 > +        codedbytes = 8;
 > +        break;
 > +    }
 >
 > +    width = map->RowPitch / codedbytes;
 > +    av_image_fill_linesizes(linesize, ctx->sw_format, width);
 >      av_image_fill_pointers(data, ctx->sw_format, desc->Height,
 >                             (uint8_t*)map->pData, linesize);

Can you explain why this change is being made?

(av_image_fill_pointers() has been given the format and finds the element sizes from pixdesc, so I think it should be working.  If it isn't then maybe it should be fixed.)

 >  }
 > --
 > 2.43.0.windows.1

Thanks,

- Mark
Hendrik Leppkes Feb. 25, 2024, 3:46 p.m. UTC | #2
On Sun, Feb 25, 2024 at 11:36 AM Mark Thompson <sw@jkqxz.net> wrote:
>
> On 25/02/2024 02:22, Водянников А.В. via ffmpeg-devel wrote:
>  > From ed8fda62bbdbc62f7565891c935966c931d001ca Mon Sep 17 00:00:00 2001
>  > From: Aleksoid <Aleksoid1978@mail.ru>
>  > Date: Thu, 22 Feb 2024 19:15:48 +1000
>  > Subject: [PATCH 1/2] Add support d3d11va Intel Hevc Rext decoder.
>  >
>  > Signed-off-by: Aleksoid <Aleksoid1978@mail.ru>
>  > ---
>  >  libavcodec/d3d12va_hevc.c     |  2 +-
>  >  libavcodec/dxva2.c            | 68 +++++++++++++++++++++++++++++++++--
>  >  libavcodec/dxva2_hevc.c       | 41 ++++++++++++++++++---
>  >  libavcodec/dxva2_internal.h   | 38 +++++++++++++++++++-
>  >  libavcodec/hevcdec.c          | 16 +++++++++
>  >  libavutil/hwcontext_d3d11va.c | 26 +++++++++++---
>  >  6 files changed, 178 insertions(+), 13 deletions(-)
>
> What elements are Intel-specific about this?
>
> Presumably there will be an official rext mode for D3D in future; are there any possible problems with having this vendor extension in that case?
>

The next Windows SDK is presumably supposed to contain RExt support,
but so far only partial information is present in the pre-release
SDKs. It might be wise to wait for that.

- Hendrik
Водянников А.В. Feb. 25, 2024, 9:55 p.m. UTC | #3
Уважаемые разработчики.
Я просто написал патч, протестировал его работу на Intel с поддержкой Hevc Rext декодированием на все возможных форматах HEVC — 420 12bit, 422 8/10/12bit, 444 8/10/12bit.
Расписывать почему именно так или так как-то нет особого желания. Но он сейчас в полностью рабочем состоянии, а нем прописаны корректные AV_PIX_FMT… и правильно работает копирование из GPU.
Вот тут:
    (sps->intra_smoothing_disabled_flag            <<  5) |
    (sps->high_precision_offsets_enabled_flag      <<  5) |
видимо да, опечатка.
 
  
>Воскресенье, 25 февраля 2024, 20:36 +10:00 от Mark Thompson <sw@jkqxz.net>:

>On 25/02/2024 02:22, Водянников А.В. via ffmpeg-devel wrote:
> > From ed8fda62bbdbc62f7565891c935966c931d001ca Mon Sep 17 00:00:00 2001
> > From: Aleksoid < Aleksoid1978@mail.ru >
> > Date: Thu, 22 Feb 2024 19:15:48 +1000
> > Subject: [PATCH 1/2] Add support d3d11va Intel Hevc Rext decoder.
> >
> > Signed-off-by: Aleksoid < Aleksoid1978@mail.ru >
> > ---
> > libavcodec/d3d12va_hevc.c | 2 +-
> > libavcodec/dxva2.c | 68 +++++++++++++++++++++++++++++++++--
> > libavcodec/dxva2_hevc.c | 41 ++++++++++++++++++---
> > libavcodec/dxva2_internal.h | 38 +++++++++++++++++++-
> > libavcodec/hevcdec.c | 16 +++++++++
> > libavutil/hwcontext_d3d11va.c | 26 +++++++++++---
> > 6 files changed, 178 insertions(+), 13 deletions(-)
>
>What elements are Intel-specific about this?
>
>Presumably there will be an official rext mode for D3D in future; are there any possible problems with having this vendor extension in that case?
>
> > diff --git a/libavcodec/d3d12va_hevc.c b/libavcodec/d3d12va_hevc.c
> > index a4964a05c6..0912e01b7d 100644
> > --- a/libavcodec/d3d12va_hevc.c
> > +++ b/libavcodec/d3d12va_hevc.c
> > @@ -62,7 +62,7 @@ static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8
> >
> > ctx->used_mask = 0;
> >
> > - ff_dxva2_hevc_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, &ctx_pic->pp);
> > + ff_dxva2_hevc_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, (DXVA_PicParams_HEVC_Rext*)&ctx_pic->pp);
>
>Get the type right to avoid the cast.
>
> >
> > ff_dxva2_hevc_fill_scaling_lists(avctx, (AVDXVAContext *)ctx, &ctx_pic->qm);
> >
> > diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
> > index 59025633f7..a611989911 100644
> > --- a/libavcodec/dxva2.c
> > +++ b/libavcodec/dxva2.c
> > @@ -50,6 +50,13 @@ DEFINE_GUID(ff_DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x0
> > DEFINE_GUID(ff_GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
> > DEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
> >
> > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main12_Intel, 0x8FF8A3AA, 0xC456, 0x4132, 0xB6, 0xEF, 0x69, 0xD9, 0xDD, 0x72, 0x57, 0x1D);
> > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main422_10_Intel, 0xE484DCB8, 0xCAC9, 0x4859, 0x99, 0xF5, 0x5C, 0x0D, 0x45, 0x06, 0x90, 0x89);
> > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main422_12_Intel, 0xC23DD857, 0x874B, 0x423C, 0xB6, 0xE0, 0x82, 0xCE, 0xAA, 0x9B, 0x11, 0x8A);
> > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_Intel, 0x41A5AF96, 0xE415, 0x4B0C, 0x9D, 0x03, 0x90, 0x78, 0x58, 0xE2, 0x3E, 0x78);
> > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_10_Intel, 0x6A6A81BA, 0x912A, 0x485D, 0xB5, 0x7F, 0xCC, 0xD2, 0xD3, 0x7B, 0x8D, 0x94);
> > +DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_12_Intel, 0x5B08E35D, 0x0C66, 0x4C51, 0xA6, 0xF1, 0x89, 0xD0, 0x0C, 0xB2, 0xC1, 0x97);
>
>Where are these GUIDs documented?
>
> > +
> > typedef struct dxva_mode {
> > const GUID *guid;
> > enum AVCodecID codec;
> > @@ -75,6 +82,8 @@ static const int prof_vp9_profile2[] = {AV_PROFILE_VP9_2,
> > AV_PROFILE_UNKNOWN};
> > static const int prof_av1_profile0[] = {AV_PROFILE_AV1_MAIN,
> > AV_PROFILE_UNKNOWN};
> > +static const int prof_hevc_rext[] = {AV_PROFILE_HEVC_REXT,
> > + AV_PROFILE_UNKNOWN};
> >
> > static const dxva_mode dxva_modes[] = {
> > /* MPEG-2 */
> > @@ -104,6 +113,14 @@ static const dxva_mode dxva_modes[] = {
> > /* AV1 */
> > { &ff_DXVA2_ModeAV1_VLD_Profile0, AV_CODEC_ID_AV1, prof_av1_profile0 },
> >
> > + /* HEVC/H.265 Rext */
> > + { &ff_DXVA2_HEVC_VLD_Main12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
> > + { &ff_DXVA2_HEVC_VLD_Main422_10_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
> > + { &ff_DXVA2_HEVC_VLD_Main422_12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
> > + { &ff_DXVA2_HEVC_VLD_Main444_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
> > + { &ff_DXVA2_HEVC_VLD_Main444_10_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
> > + { &ff_DXVA2_HEVC_VLD_Main444_12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
>
>Doesn't this need more detail about what the modes actually support? Declaring that any one of these supports all rext streams does not seem right.
>
>Related: what is the desired behaviour if you have a YUV 4:2:0 8-bit stream but the profile is rext?
>
> > +
> > { NULL, 0 },
> > };
> >
> > @@ -301,6 +318,14 @@ static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *sur
> > if (IsEqualGUID(decoder_guid, &ff_DXVADDI_Intel_ModeH264_E))
> > sctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
> >
> > + av_log(avctx, AV_LOG_VERBOSE,
> > + "Used guid : {%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}\n",
> > + (unsigned)decoder_guid->Data1, decoder_guid->Data2, decoder_guid->Data3,
> > + decoder_guid->Data4[0], decoder_guid->Data4[1],
> > + decoder_guid->Data4[2], decoder_guid->Data4[3],
> > + decoder_guid->Data4[4], decoder_guid->Data4[5],
> > + decoder_guid->Data4[6], decoder_guid->Data4[7]);
> > +
> > return 0;
> > }
> >
> > @@ -458,6 +483,13 @@ static DXGI_FORMAT d3d11va_map_sw_to_hw_format(enum AVPixelFormat pix_fmt)
> > case AV_PIX_FMT_NV12: return DXGI_FORMAT_NV12;
> > case AV_PIX_FMT_P010: return DXGI_FORMAT_P010;
> > case AV_PIX_FMT_YUV420P: return DXGI_FORMAT_420_OPAQUE;
> > + case AV_PIX_FMT_P016: return DXGI_FORMAT_P016;
>
>The profiles above suggest that this does not support 16-bit, so you shouldn't have AV_PIX_FMT_P016 here. Probably you want P012?
>
>(The ffmpeg formats contain the depth information where the DXGI ones are just containers. You need to set the format correctly or later components will believe there are significant low bits.)
>
> > + case AV_PIX_FMT_YUYV422: return DXGI_FORMAT_YUY2;
> > + case AV_PIX_FMT_Y210: return DXGI_FORMAT_Y210;
> > + case AV_PIX_FMT_Y212: return DXGI_FORMAT_Y216;
> > + case AV_PIX_FMT_VUYX: return DXGI_FORMAT_AYUV;
> > + case AV_PIX_FMT_XV30: return DXGI_FORMAT_Y410;
> > + case AV_PIX_FMT_XV36: return DXGI_FORMAT_Y416;
> > default: return DXGI_FORMAT_UNKNOWN;
> > }
> > }
> > @@ -589,6 +621,39 @@ static void ff_dxva2_unlock(AVCodecContext *avctx)
> > #endif
> > }
> >
> > +static enum AVPixelFormat map_sw_pix_format(enum AVPixelFormat pix_fmt, enum AVPixelFormat hw_pix_fmt)
> > +{
> > +#if CONFIG_D3D11VA
> > + if (hw_pix_fmt == AV_PIX_FMT_D3D11) {
>
>Is this actually locked to be D3D11 only?
>
> > + switch (pix_fmt)
> > + {
> > + case AV_PIX_FMT_YUV420P10:
> > + case AV_PIX_FMT_P010:
> > + return AV_PIX_FMT_P010;
> > + case AV_PIX_FMT_YUV420P12:
> > + return AV_PIX_FMT_P016;
>
>Same problem here with it creating extra bit depth out of nowhere.
>
> > + case AV_PIX_FMT_YUV422P:
> > + return AV_PIX_FMT_YUYV422;
> > + case AV_PIX_FMT_YUV422P10:
> > + return AV_PIX_FMT_Y210;
> > + case AV_PIX_FMT_YUV444P:
> > + return AV_PIX_FMT_VUYX;
> > + case AV_PIX_FMT_YUV444P10:
> > + return AV_PIX_FMT_XV30;
> > + case AV_PIX_FMT_YUV422P12:
> > + return AV_PIX_FMT_Y212;
> > + case AV_PIX_FMT_YUV444P12:
> > + return AV_PIX_FMT_XV36;
> > + case AV_PIX_FMT_NV12:
> > + default:
> > + return AV_PIX_FMT_NV12;
> > + }
> > + }
> > +#endif
> > + return pix_fmt == AV_PIX_FMT_YUV420P10 ?
> > + AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
> > +}
> > +
> > int ff_dxva2_common_frame_params(AVCodecContext *avctx,
> > AVBufferRef *hw_frames_ctx)
> > {
> > @@ -626,8 +691,7 @@ int ff_dxva2_common_frame_params(AVCodecContext *avctx,
> > else
> > num_surfaces += 2;
> >
> > - frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
> > - AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
> > + frames_ctx->sw_format = map_sw_pix_format(avctx->sw_pix_fmt, frames_ctx->format);
> > frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment);
> > frames_ctx->height = FFALIGN(avctx->coded_height, surface_alignment);
> > frames_ctx->initial_pool_size = num_surfaces;
> > diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c
> > index 31d74a7164..7153b2e604 100644
> > --- a/libavcodec/dxva2_hevc.c
> > +++ b/libavcodec/dxva2_hevc.c
> > @@ -32,7 +32,7 @@
> > #define MAX_SLICES 256
> >
> > struct hevc_dxva2_picture_context {
> > - DXVA_PicParams_HEVC pp;
> > + DXVA_PicParams_HEVC_Rext pp;
>
>Use a union here to avoid non-rext code noticing anything about the rext structure?
>
> > DXVA_Qmatrix_HEVC qm;
> > unsigned slice_count;
> > DXVA_Slice_HEVC_Short slice_short[MAX_SLICES];
> > @@ -58,19 +58,49 @@ static int get_refpic_index(const DXVA_PicParams_HEVC *pp, int surface_index)
> > }
> >
> > void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx,
> > - DXVA_PicParams_HEVC *pp)
> > + DXVA_PicParams_HEVC_Rext *ppext)
> > {
> > const HEVCContext *h = avctx->priv_data;
> > const HEVCFrame *current_picture = h->ref;
> > const HEVCSPS *sps = h->ps.sps;
> > const HEVCPPS *pps = h->ps.pps;
> > int i, j;
> > + DXVA_PicParams_HEVC *pp = &ppext->main;
> >
> > - memset(pp, 0, sizeof(*pp));
> > + memset(ppext, 0, sizeof(*ppext));
> >
> > pp->PicWidthInMinCbsY = sps->min_cb_width;
> > pp->PicHeightInMinCbsY = sps->min_cb_height;
> >
> > + if (sps->sps_range_extension_flag) {
> > + ppext->dwRangeExtensionFlags |= (sps->transform_skip_rotation_enabled_flag << 0) |
> > + (sps->transform_skip_context_enabled_flag << 1) |
> > + (sps->implicit_rdpcm_enabled_flag << 2) |
> > + (sps->explicit_rdpcm_enabled_flag << 3) |
> > + (sps->extended_precision_processing_flag << 4) |
> > + (sps->intra_smoothing_disabled_flag << 5) |
> > + (sps->high_precision_offsets_enabled_flag << 5) |
>
>Two << 5 here. Do you have streams to give test coverage of all of these flags?
>
>Also, given that you have a bitfield representation why not just use it to avoid the manual shifts?
>
> > + (sps->persistent_rice_adaptation_enabled_flag << 7) |
> > + (sps->cabac_bypass_alignment_enabled_flag << 8);
> > + }
> > + if (pps->pps_range_extensions_flag) {
> > + ppext->dwRangeExtensionFlags |= (pps->cross_component_prediction_enabled_flag << 9) |
> > + (pps->chroma_qp_offset_list_enabled_flag << 10);
> > + if (pps->chroma_qp_offset_list_enabled_flag) {
> > + ppext->diff_cu_chroma_qp_offset_depth = pps->diff_cu_chroma_qp_offset_depth;
> > + ppext->chroma_qp_offset_list_len_minus1 = pps->chroma_qp_offset_list_len_minus1;
> > + for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) {
> > + ppext->cb_qp_offset_list[i] = pps->cb_qp_offset_list[i];
> > + ppext->cr_qp_offset_list[i] = pps->cr_qp_offset_list[i];
> > + }
> > + }
> > + ppext->log2_sao_offset_scale_luma = pps->log2_sao_offset_scale_luma;
> > + ppext->log2_sao_offset_scale_chroma = pps->log2_sao_offset_scale_chroma;
> > + if (pps->transform_skip_enabled_flag) {
> > + ppext->log2_max_transform_skip_block_size_minus2 = pps->log2_max_transform_skip_block_size - 2;
> > + }
> > + }
>
>Suggest putting the rext stuff at the end of the function, after all of the common parts.
>
> > +
> > pp->wFormatAndSequenceInfoFlags = (sps->chroma_format_idc << 0) |
> > (sps->separate_colour_plane_flag << 2) |
> > ((sps->bit_depth - 8) << 3) |
> > @@ -409,14 +439,15 @@ static int dxva2_hevc_end_frame(AVCodecContext *avctx)
> > {
> > HEVCContext *h = avctx->priv_data;
> > struct hevc_dxva2_picture_context *ctx_pic = h->ref->hwaccel_picture_private;
> > - int scale = ctx_pic->pp.dwCodingParamToolFlags & 1;
> > + int scale = ctx_pic->pp.main.dwCodingParamToolFlags & 1;
> > + int rext = avctx->profile == AV_PROFILE_HEVC_REXT && ff_dxva2_is_d3d11(avctx);
> > int ret;
> >
> > if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
> > return -1;
> >
> > ret = ff_dxva2_common_end_frame(avctx, h->ref->frame,
> > - &ctx_pic->pp, sizeof(ctx_pic->pp),
> > + &ctx_pic->pp, rext ? sizeof(ctx_pic->pp) : sizeof(ctx_pic->pp.main),
> > scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0,
> > commit_bitstream_and_slice_buffer);
> > return ret;
> > diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h
> > index 224a867ebc..38e34ce64f 100644
> > --- a/libavcodec/dxva2_internal.h
> > +++ b/libavcodec/dxva2_internal.h
> > @@ -64,6 +64,42 @@
> > #include <dxva.h>
> > #endif
> >
> > +#pragma pack(push, 1)
> > +typedef struct
> > +{
> > + DXVA_PicParams_HEVC main;
> > +
> > + // HEVC Range Extension
> > + __C89_NAMELESS union {
> > + __C89_NAMELESS struct {
> > + UINT32 transform_skip_rotation_enabled_flag : 1;
> > + UINT32 transform_skip_context_enabled_flag : 1;
> > + UINT32 implicit_rdpcm_enabled_flag : 1;
> > + UINT32 explicit_rdpcm_enabled_flag : 1;
> > + UINT32 extended_precision_processing_flag : 1;
> > + UINT32 intra_smoothing_disabled_flag : 1;
> > + UINT32 high_precision_offsets_enabled_flag : 1;
> > + UINT32 persistent_rice_adaptation_enabled_flag : 1;
> > + UINT32 cabac_bypass_alignment_enabled_flag : 1;
> > + UINT32 cross_component_prediction_enabled_flag : 1;
> > + UINT32 chroma_qp_offset_list_enabled_flag : 1;
> > + UINT32 BitDepthLuma16 : 1; // TODO merge in ReservedBits5 if not needed
> > + UINT32 BitDepthChroma16 : 1; // TODO merge in ReservedBits5 if not needed
> > + UINT32 ReservedBits8 : 19;
> > + };
> > + UINT32 dwRangeExtensionFlags;
> > + };
> > +
> > + UCHAR diff_cu_chroma_qp_offset_depth;
> > + UCHAR chroma_qp_offset_list_len_minus1;
> > + UCHAR log2_sao_offset_scale_luma;
> > + UCHAR log2_sao_offset_scale_chroma;
> > + UCHAR log2_max_transform_skip_block_size_minus2;
> > + CHAR cb_qp_offset_list[6];
> > + CHAR cr_qp_offset_list[6];
> > +} DXVA_PicParams_HEVC_Rext;
> > +#pragma pack(pop)
>
>Where is this structure copied from? (Is it under a licence with any relevant conditions?)
>
> > +
> > #include "libavutil/hwcontext.h"
> >
> > #include "avcodec.h"
> > @@ -171,7 +207,7 @@ void ff_dxva2_h264_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo
> >
> > void ff_dxva2_h264_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_H264 *qm);
> >
> > -void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC *pp);
> > +void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC_Rext *ppext);
> >
> > void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_HEVC *qm);
> >
> > diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
> > index b5311ae510..508f279933 100644
> > --- a/libavcodec/hevcdec.c
> > +++ b/libavcodec/hevcdec.c
> > @@ -463,6 +463,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
> > #endif
> > break;
> > case AV_PIX_FMT_YUV444P:
> > +#if CONFIG_HEVC_D3D11VA_HWACCEL
> > + *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
>
>Have you tested this with the legacy API?
>
> > + *fmt++ = AV_PIX_FMT_D3D11;
> > +#endif
> > #if CONFIG_HEVC_VAAPI_HWACCEL
> > *fmt++ = AV_PIX_FMT_VAAPI;
> > #endif
> > @@ -481,6 +485,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
> > break;
> > case AV_PIX_FMT_YUV422P:
> > case AV_PIX_FMT_YUV422P10LE:
> > +#if CONFIG_HEVC_D3D11VA_HWACCEL
> > + *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
> > + *fmt++ = AV_PIX_FMT_D3D11;
> > +#endif
> > #if CONFIG_HEVC_VAAPI_HWACCEL
> > *fmt++ = AV_PIX_FMT_VAAPI;
> > #endif
> > @@ -498,6 +506,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
> > /* NOTE: fallthrough */
> > case AV_PIX_FMT_YUV420P12:
> > case AV_PIX_FMT_YUV444P12:
> > +#if CONFIG_HEVC_D3D11VA_HWACCEL
> > + *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
> > + *fmt++ = AV_PIX_FMT_D3D11;
> > +#endif
> > #if CONFIG_HEVC_VAAPI_HWACCEL
> > *fmt++ = AV_PIX_FMT_VAAPI;
> > #endif
> > @@ -512,6 +524,10 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
> > #endif
> > break;
> > case AV_PIX_FMT_YUV422P12:
> > +#if CONFIG_HEVC_D3D11VA_HWACCEL
> > + *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
> > + *fmt++ = AV_PIX_FMT_D3D11;
> > +#endif
> > #if CONFIG_HEVC_VAAPI_HWACCEL
> > *fmt++ = AV_PIX_FMT_VAAPI;
> > #endif
> > diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
> > index 2fd3561c88..79b1f34b3b 100644
> > --- a/libavutil/hwcontext_d3d11va.c
> > +++ b/libavutil/hwcontext_d3d11va.c
>
>Move the changes to the hwcontext into a separate patch.
>
> > @@ -94,6 +94,7 @@ static const struct {
> > { DXGI_FORMAT_Y210, AV_PIX_FMT_Y210 },
> > { DXGI_FORMAT_Y410, AV_PIX_FMT_XV30 },
> > { DXGI_FORMAT_P016, AV_PIX_FMT_P012 },
> > + { DXGI_FORMAT_P016, AV_PIX_FMT_P016 },
>
>Ok here because it only maps AV -> DXGI.
>
> > { DXGI_FORMAT_Y216, AV_PIX_FMT_Y212 },
> > { DXGI_FORMAT_Y416, AV_PIX_FMT_XV36 },
> > // Special opaque formats. The pix_fmt is merely a place holder, as the
> > @@ -394,11 +395,28 @@ static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
> > D3D11_TEXTURE2D_DESC *desc,
> > D3D11_MAPPED_SUBRESOURCE *map)
> > {
> > - int i;
> > -
> > - for (i = 0; i < 4; i++)
> > - linesize[i] = map->RowPitch;
> > + int width;
> > + int codedbytes = 1;
> > +
> > + switch (ctx->sw_format) {
> > + case AV_PIX_FMT_P010:
> > + case AV_PIX_FMT_P016:
> > + case AV_PIX_FMT_YUYV422:
> > + codedbytes = 2;
> > + break;
> > + case AV_PIX_FMT_Y210:
> > + case AV_PIX_FMT_Y212:
> > + case AV_PIX_FMT_VUYX:
> > + case AV_PIX_FMT_XV30:
> > + codedbytes = 4;
> > + break;
> > + case AV_PIX_FMT_XV36:
> > + codedbytes = 8;
> > + break;
> > + }
> >
> > + width = map->RowPitch / codedbytes;
> > + av_image_fill_linesizes(linesize, ctx->sw_format, width);
> > av_image_fill_pointers(data, ctx->sw_format, desc->Height,
> > (uint8_t*)map->pData, linesize);
>
>Can you explain why this change is being made?
>
>(av_image_fill_pointers() has been given the format and finds the element sizes from pixdesc, so I think it should be working. If it isn't then maybe it should be fixed.)
>
> > }
> > --
> > 2.43.0.windows.1
>
>Thanks,
>
>- Mark
>_______________________________________________
>ffmpeg-devel mailing list
>ffmpeg-devel@ffmpeg.org
>https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
>To unsubscribe, visit link above, or email
>ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". 
 
 
--
Александр Водянников.
Водянников А.В. Feb. 25, 2024, 11:35 p.m. UTC | #4
I apologize for the previous letter, I forgot to translate)
Dear developers. I simply wrote a patch, tested its operation on Intel with Hevc Rext support by decoding on all possible HEVC formats - 420 12bit, 422 8/10/12bit, 444 8/10/12bit.
There is no particular desire to describe why exactly this or that way.
But it is now in full working order, and the correct AV_PIX_FMT_ +  DXGI_FORMAT_ is registered in it, 
and copying from the GPU works correctly.
You can compile and test it yourself and make sure that everything works correctly.
 
Right here:
    (sps->intra_smoothing_disabled_flag << 5) | (sps->high_precision_offsets_enabled_flag << 5)
apparently yes, a typo, must be
    sps->high_precision_offsets_enabled_flag << 6
 
 
--
Александр Водянников.
diff mbox series

Patch

diff --git a/libavcodec/d3d12va_hevc.c b/libavcodec/d3d12va_hevc.c
index a4964a05c6..0912e01b7d 100644
--- a/libavcodec/d3d12va_hevc.c
+++ b/libavcodec/d3d12va_hevc.c
@@ -62,7 +62,7 @@  static int d3d12va_hevc_start_frame(AVCodecContext *avctx, av_unused const uint8
 
     ctx->used_mask = 0;
 
-    ff_dxva2_hevc_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, &ctx_pic->pp);
+    ff_dxva2_hevc_fill_picture_parameters(avctx, (AVDXVAContext *)ctx, (DXVA_PicParams_HEVC_Rext*)&ctx_pic->pp);
 
     ff_dxva2_hevc_fill_scaling_lists(avctx, (AVDXVAContext *)ctx, &ctx_pic->qm);
 
diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c
index 59025633f7..a611989911 100644
--- a/libavcodec/dxva2.c
+++ b/libavcodec/dxva2.c
@@ -50,6 +50,13 @@  DEFINE_GUID(ff_DXVA2_NoEncrypt,          0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x0
 DEFINE_GUID(ff_GUID_NULL,                0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
 DEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
 
+DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main12_Intel,     0x8FF8A3AA, 0xC456, 0x4132, 0xB6, 0xEF, 0x69, 0xD9, 0xDD, 0x72, 0x57, 0x1D);
+DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main422_10_Intel, 0xE484DCB8, 0xCAC9, 0x4859, 0x99, 0xF5, 0x5C, 0x0D, 0x45, 0x06, 0x90, 0x89);
+DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main422_12_Intel, 0xC23DD857, 0x874B, 0x423C, 0xB6, 0xE0, 0x82, 0xCE, 0xAA, 0x9B, 0x11, 0x8A);
+DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_Intel,    0x41A5AF96, 0xE415, 0x4B0C, 0x9D, 0x03, 0x90, 0x78, 0x58, 0xE2, 0x3E, 0x78);
+DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_10_Intel, 0x6A6A81BA, 0x912A, 0x485D, 0xB5, 0x7F, 0xCC, 0xD2, 0xD3, 0x7B, 0x8D, 0x94);
+DEFINE_GUID(ff_DXVA2_HEVC_VLD_Main444_12_Intel, 0x5B08E35D, 0x0C66, 0x4C51, 0xA6, 0xF1, 0x89, 0xD0, 0x0C, 0xB2, 0xC1, 0x97);
+
 typedef struct dxva_mode {
     const GUID     *guid;
     enum AVCodecID codec;
@@ -75,6 +82,8 @@  static const int prof_vp9_profile2[] = {AV_PROFILE_VP9_2,
                                         AV_PROFILE_UNKNOWN};
 static const int prof_av1_profile0[] = {AV_PROFILE_AV1_MAIN,
                                         AV_PROFILE_UNKNOWN};
+static const int prof_hevc_rext[]    = {AV_PROFILE_HEVC_REXT,
+                                        AV_PROFILE_UNKNOWN};
 
 static const dxva_mode dxva_modes[] = {
     /* MPEG-2 */
@@ -104,6 +113,14 @@  static const dxva_mode dxva_modes[] = {
     /* AV1 */
     { &ff_DXVA2_ModeAV1_VLD_Profile0,       AV_CODEC_ID_AV1, prof_av1_profile0 },
 
+    /* HEVC/H.265 Rext */
+    { &ff_DXVA2_HEVC_VLD_Main12_Intel,     AV_CODEC_ID_HEVC, prof_hevc_rext },
+    { &ff_DXVA2_HEVC_VLD_Main422_10_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
+    { &ff_DXVA2_HEVC_VLD_Main422_12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
+    { &ff_DXVA2_HEVC_VLD_Main444_Intel,    AV_CODEC_ID_HEVC, prof_hevc_rext },
+    { &ff_DXVA2_HEVC_VLD_Main444_10_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
+    { &ff_DXVA2_HEVC_VLD_Main444_12_Intel, AV_CODEC_ID_HEVC, prof_hevc_rext },
+
     { NULL,                          0 },
 };
 
@@ -301,6 +318,14 @@  static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *sur
     if (IsEqualGUID(decoder_guid, &ff_DXVADDI_Intel_ModeH264_E))
         sctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
 
+    av_log(avctx, AV_LOG_VERBOSE,
+           "Used guid : {%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}\n",
+           (unsigned)decoder_guid->Data1, decoder_guid->Data2, decoder_guid->Data3,
+           decoder_guid->Data4[0], decoder_guid->Data4[1],
+           decoder_guid->Data4[2], decoder_guid->Data4[3],
+           decoder_guid->Data4[4], decoder_guid->Data4[5],
+           decoder_guid->Data4[6], decoder_guid->Data4[7]);
+
     return 0;
 }
 
@@ -458,6 +483,13 @@  static DXGI_FORMAT d3d11va_map_sw_to_hw_format(enum AVPixelFormat pix_fmt)
     case AV_PIX_FMT_NV12:       return DXGI_FORMAT_NV12;
     case AV_PIX_FMT_P010:       return DXGI_FORMAT_P010;
     case AV_PIX_FMT_YUV420P:    return DXGI_FORMAT_420_OPAQUE;
+    case AV_PIX_FMT_P016:       return DXGI_FORMAT_P016;
+    case AV_PIX_FMT_YUYV422:    return DXGI_FORMAT_YUY2;
+    case AV_PIX_FMT_Y210:       return DXGI_FORMAT_Y210;
+    case AV_PIX_FMT_Y212:       return DXGI_FORMAT_Y216;
+    case AV_PIX_FMT_VUYX:       return DXGI_FORMAT_AYUV;
+    case AV_PIX_FMT_XV30:       return DXGI_FORMAT_Y410;
+    case AV_PIX_FMT_XV36:       return DXGI_FORMAT_Y416;
     default:                    return DXGI_FORMAT_UNKNOWN;
     }
 }
@@ -589,6 +621,39 @@  static void ff_dxva2_unlock(AVCodecContext *avctx)
 #endif
 }
 
+static enum AVPixelFormat map_sw_pix_format(enum AVPixelFormat pix_fmt, enum AVPixelFormat hw_pix_fmt)
+{
+#if CONFIG_D3D11VA
+    if (hw_pix_fmt == AV_PIX_FMT_D3D11) {
+        switch (pix_fmt)
+        {
+        case AV_PIX_FMT_YUV420P10:
+        case AV_PIX_FMT_P010:
+            return AV_PIX_FMT_P010;
+        case AV_PIX_FMT_YUV420P12:
+            return AV_PIX_FMT_P016;
+        case AV_PIX_FMT_YUV422P:
+            return AV_PIX_FMT_YUYV422;
+        case AV_PIX_FMT_YUV422P10:
+            return AV_PIX_FMT_Y210;
+        case AV_PIX_FMT_YUV444P:
+            return AV_PIX_FMT_VUYX;
+        case AV_PIX_FMT_YUV444P10:
+            return AV_PIX_FMT_XV30;
+        case AV_PIX_FMT_YUV422P12:
+            return AV_PIX_FMT_Y212;
+        case AV_PIX_FMT_YUV444P12:
+            return AV_PIX_FMT_XV36;
+        case AV_PIX_FMT_NV12:
+        default:
+            return AV_PIX_FMT_NV12;
+        }
+    }
+#endif
+    return pix_fmt == AV_PIX_FMT_YUV420P10 ?
+        AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
+}
+
 int ff_dxva2_common_frame_params(AVCodecContext *avctx,
                                  AVBufferRef *hw_frames_ctx)
 {
@@ -626,8 +691,7 @@  int ff_dxva2_common_frame_params(AVCodecContext *avctx,
     else
         num_surfaces += 2;
 
-    frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
-                            AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
+    frames_ctx->sw_format = map_sw_pix_format(avctx->sw_pix_fmt, frames_ctx->format);
     frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment);
     frames_ctx->height = FFALIGN(avctx->coded_height, surface_alignment);
     frames_ctx->initial_pool_size = num_surfaces;
diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c
index 31d74a7164..7153b2e604 100644
--- a/libavcodec/dxva2_hevc.c
+++ b/libavcodec/dxva2_hevc.c
@@ -32,7 +32,7 @@ 
 #define MAX_SLICES 256
 
 struct hevc_dxva2_picture_context {
-    DXVA_PicParams_HEVC   pp;
+    DXVA_PicParams_HEVC_Rext   pp;
     DXVA_Qmatrix_HEVC     qm;
     unsigned              slice_count;
     DXVA_Slice_HEVC_Short slice_short[MAX_SLICES];
@@ -58,19 +58,49 @@  static int get_refpic_index(const DXVA_PicParams_HEVC *pp, int surface_index)
 }
 
 void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx,
-                                    DXVA_PicParams_HEVC *pp)
+                                    DXVA_PicParams_HEVC_Rext *ppext)
 {
     const HEVCContext *h = avctx->priv_data;
     const HEVCFrame *current_picture = h->ref;
     const HEVCSPS *sps = h->ps.sps;
     const HEVCPPS *pps = h->ps.pps;
     int i, j;
+    DXVA_PicParams_HEVC *pp = &ppext->main;
 
-    memset(pp, 0, sizeof(*pp));
+    memset(ppext, 0, sizeof(*ppext));
 
     pp->PicWidthInMinCbsY  = sps->min_cb_width;
     pp->PicHeightInMinCbsY = sps->min_cb_height;
 
+    if (sps->sps_range_extension_flag) {
+        ppext->dwRangeExtensionFlags |= (sps->transform_skip_rotation_enabled_flag     <<  0) |
+                                        (sps->transform_skip_context_enabled_flag      <<  1) |
+                                        (sps->implicit_rdpcm_enabled_flag              <<  2) |
+                                        (sps->explicit_rdpcm_enabled_flag              <<  3) |
+                                        (sps->extended_precision_processing_flag       <<  4) |
+                                        (sps->intra_smoothing_disabled_flag            <<  5) |
+                                        (sps->high_precision_offsets_enabled_flag      <<  5) |
+                                        (sps->persistent_rice_adaptation_enabled_flag  <<  7) |
+                                        (sps->cabac_bypass_alignment_enabled_flag      <<  8);
+    }
+    if (pps->pps_range_extensions_flag) {
+        ppext->dwRangeExtensionFlags |= (pps->cross_component_prediction_enabled_flag  <<  9) |
+                                        (pps->chroma_qp_offset_list_enabled_flag       << 10);
+        if (pps->chroma_qp_offset_list_enabled_flag) {
+            ppext->diff_cu_chroma_qp_offset_depth   = pps->diff_cu_chroma_qp_offset_depth;
+            ppext->chroma_qp_offset_list_len_minus1 = pps->chroma_qp_offset_list_len_minus1;
+            for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) {
+                ppext->cb_qp_offset_list[i] = pps->cb_qp_offset_list[i];
+                ppext->cr_qp_offset_list[i] = pps->cr_qp_offset_list[i];
+            }
+        }
+        ppext->log2_sao_offset_scale_luma   = pps->log2_sao_offset_scale_luma;
+        ppext->log2_sao_offset_scale_chroma = pps->log2_sao_offset_scale_chroma;
+        if (pps->transform_skip_enabled_flag) {
+            ppext->log2_max_transform_skip_block_size_minus2 = pps->log2_max_transform_skip_block_size - 2;
+        }
+    }
+
     pp->wFormatAndSequenceInfoFlags = (sps->chroma_format_idc             <<  0) |
                                       (sps->separate_colour_plane_flag    <<  2) |
                                       ((sps->bit_depth - 8)               <<  3) |
@@ -409,14 +439,15 @@  static int dxva2_hevc_end_frame(AVCodecContext *avctx)
 {
     HEVCContext *h = avctx->priv_data;
     struct hevc_dxva2_picture_context *ctx_pic = h->ref->hwaccel_picture_private;
-    int scale = ctx_pic->pp.dwCodingParamToolFlags & 1;
+    int scale = ctx_pic->pp.main.dwCodingParamToolFlags & 1;
+    int rext = avctx->profile == AV_PROFILE_HEVC_REXT && ff_dxva2_is_d3d11(avctx);
     int ret;
 
     if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
         return -1;
 
     ret = ff_dxva2_common_end_frame(avctx, h->ref->frame,
-                                    &ctx_pic->pp, sizeof(ctx_pic->pp),
+                                    &ctx_pic->pp, rext ? sizeof(ctx_pic->pp) : sizeof(ctx_pic->pp.main),
                                     scale ? &ctx_pic->qm : NULL, scale ? sizeof(ctx_pic->qm) : 0,
                                     commit_bitstream_and_slice_buffer);
     return ret;
diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h
index 224a867ebc..38e34ce64f 100644
--- a/libavcodec/dxva2_internal.h
+++ b/libavcodec/dxva2_internal.h
@@ -64,6 +64,42 @@ 
 #include <dxva.h>
 #endif
 
+#pragma pack(push, 1)
+typedef struct
+{
+    DXVA_PicParams_HEVC main;
+
+    // HEVC Range Extension
+    __C89_NAMELESS union {
+        __C89_NAMELESS struct {
+            UINT32 transform_skip_rotation_enabled_flag : 1;
+            UINT32 transform_skip_context_enabled_flag : 1;
+            UINT32 implicit_rdpcm_enabled_flag : 1;
+            UINT32 explicit_rdpcm_enabled_flag : 1;
+            UINT32 extended_precision_processing_flag : 1;
+            UINT32 intra_smoothing_disabled_flag : 1;
+            UINT32 high_precision_offsets_enabled_flag : 1;
+            UINT32 persistent_rice_adaptation_enabled_flag : 1;
+            UINT32 cabac_bypass_alignment_enabled_flag : 1;
+            UINT32 cross_component_prediction_enabled_flag : 1;
+            UINT32 chroma_qp_offset_list_enabled_flag : 1;
+            UINT32 BitDepthLuma16 : 1; // TODO merge in ReservedBits5 if not needed
+            UINT32 BitDepthChroma16 : 1; // TODO merge in ReservedBits5 if not needed
+            UINT32 ReservedBits8 : 19;
+        };
+        UINT32 dwRangeExtensionFlags;
+    };
+
+    UCHAR diff_cu_chroma_qp_offset_depth;
+    UCHAR chroma_qp_offset_list_len_minus1;
+    UCHAR log2_sao_offset_scale_luma;
+    UCHAR log2_sao_offset_scale_chroma;
+    UCHAR log2_max_transform_skip_block_size_minus2;
+    CHAR cb_qp_offset_list[6];
+    CHAR cr_qp_offset_list[6];
+} DXVA_PicParams_HEVC_Rext;
+#pragma pack(pop)
+
 #include "libavutil/hwcontext.h"
 
 #include "avcodec.h"
@@ -171,7 +207,7 @@  void ff_dxva2_h264_fill_picture_parameters(const AVCodecContext *avctx, AVDXVACo
 
 void ff_dxva2_h264_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_H264 *qm);
 
-void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC *pp);
+void ff_dxva2_hevc_fill_picture_parameters(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_PicParams_HEVC_Rext *ppext);
 
 void ff_dxva2_hevc_fill_scaling_lists(const AVCodecContext *avctx, AVDXVAContext *ctx, DXVA_Qmatrix_HEVC *qm);
 
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index b5311ae510..508f279933 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -463,6 +463,10 @@  static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 #endif
         break;
     case AV_PIX_FMT_YUV444P:
+#if CONFIG_HEVC_D3D11VA_HWACCEL
+        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
+        *fmt++ = AV_PIX_FMT_D3D11;
+#endif
 #if CONFIG_HEVC_VAAPI_HWACCEL
         *fmt++ = AV_PIX_FMT_VAAPI;
 #endif
@@ -481,6 +485,10 @@  static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
         break;
     case AV_PIX_FMT_YUV422P:
     case AV_PIX_FMT_YUV422P10LE:
+#if CONFIG_HEVC_D3D11VA_HWACCEL
+        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
+        *fmt++ = AV_PIX_FMT_D3D11;
+#endif
 #if CONFIG_HEVC_VAAPI_HWACCEL
        *fmt++ = AV_PIX_FMT_VAAPI;
 #endif
@@ -498,6 +506,10 @@  static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
     /* NOTE: fallthrough */
     case AV_PIX_FMT_YUV420P12:
     case AV_PIX_FMT_YUV444P12:
+#if CONFIG_HEVC_D3D11VA_HWACCEL
+        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
+        *fmt++ = AV_PIX_FMT_D3D11;
+#endif
 #if CONFIG_HEVC_VAAPI_HWACCEL
        *fmt++ = AV_PIX_FMT_VAAPI;
 #endif
@@ -512,6 +524,10 @@  static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps)
 #endif
         break;
     case AV_PIX_FMT_YUV422P12:
+#if CONFIG_HEVC_D3D11VA_HWACCEL
+        *fmt++ = AV_PIX_FMT_D3D11VA_VLD;
+        *fmt++ = AV_PIX_FMT_D3D11;
+#endif
 #if CONFIG_HEVC_VAAPI_HWACCEL
        *fmt++ = AV_PIX_FMT_VAAPI;
 #endif
diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
index 2fd3561c88..79b1f34b3b 100644
--- a/libavutil/hwcontext_d3d11va.c
+++ b/libavutil/hwcontext_d3d11va.c
@@ -94,6 +94,7 @@  static const struct {
     { DXGI_FORMAT_Y210,         AV_PIX_FMT_Y210 },
     { DXGI_FORMAT_Y410,         AV_PIX_FMT_XV30 },
     { DXGI_FORMAT_P016,         AV_PIX_FMT_P012 },
+    { DXGI_FORMAT_P016,         AV_PIX_FMT_P016 },
     { DXGI_FORMAT_Y216,         AV_PIX_FMT_Y212 },
     { DXGI_FORMAT_Y416,         AV_PIX_FMT_XV36 },
     // Special opaque formats. The pix_fmt is merely a place holder, as the
@@ -394,11 +395,28 @@  static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
                               D3D11_TEXTURE2D_DESC *desc,
                               D3D11_MAPPED_SUBRESOURCE *map)
 {
-    int i;
-
-    for (i = 0; i < 4; i++)
-        linesize[i] = map->RowPitch;
+    int width;
+    int codedbytes = 1;
+
+    switch (ctx->sw_format) {
+    case AV_PIX_FMT_P010:
+    case AV_PIX_FMT_P016:
+    case AV_PIX_FMT_YUYV422:
+        codedbytes = 2;
+        break;
+    case AV_PIX_FMT_Y210:
+    case AV_PIX_FMT_Y212:
+    case AV_PIX_FMT_VUYX:
+    case AV_PIX_FMT_XV30:
+        codedbytes = 4;
+        break;
+    case AV_PIX_FMT_XV36:
+        codedbytes = 8;
+        break;
+    }
 
+    width = map->RowPitch / codedbytes;
+    av_image_fill_linesizes(linesize, ctx->sw_format, width);
     av_image_fill_pointers(data, ctx->sw_format, desc->Height,
                            (uint8_t*)map->pData, linesize);
 }