PR #24635 opened by Kacper Michajłow (kasper93) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24635 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24635.patch
From 19d860b3a412c0d62edb947da357c81ea55bf1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Tue, 22 Sep 2026 11:39:11 +0200 Subject: [PATCH 1/3] avcodec/dxva2: derive the DXVA2 decoder format from the frames context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dxva2_create_decoder picked the D3D9 surface format from sw_pix_fmt with a hardcoded choice between NV12 and P010, while the surfaces it decodes into come from the frames context, whose format is chosen separately in ff_dxva2_common_frame_params. Map frames_ctx->sw_format to the D3DFORMAT instead, like the D3D11 path already does, so the two cannot drift apart. DXVA2 is only offered for 4:2:0 8-bit and 10-bit streams, so this code path only ever sees NV12 and P010. But it's nicer to be explicit here, and return D3DFMT_UNKNOWN for any unexpected format, if ever added. Signed-off-by: Kacper Michajłow <[email protected]> --- libavcodec/dxva2.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index c761f8eebb..3ad80dfaad 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -352,22 +352,31 @@ static int dxva2_get_decoder_configuration(AVCodecContext *avctx, const GUID *de return ret; } +static D3DFORMAT dxva2_map_sw_to_hw_format(enum AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_NV12: return MKTAG('N', 'V', '1', '2'); + case AV_PIX_FMT_P010: return MKTAG('P', '0', '1', '0'); + case AV_PIX_FMT_P012: return MKTAG('P', '0', '1', '6'); + default: return D3DFMT_UNKNOWN; + } +} + static int dxva2_create_decoder(AVCodecContext *avctx) { FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); GUID *guid_list; unsigned guid_count; GUID device_guid; - D3DFORMAT surface_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? - MKTAG('P', '0', '1', '0') : MKTAG('N', 'V', '1', '2'); + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx; + AVDXVA2DeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + D3DFORMAT surface_format = dxva2_map_sw_to_hw_format(frames_ctx->sw_format); DXVA2_VideoDesc desc = { 0 }; DXVA2_ConfigPictureDecode config; HRESULT hr; int ret; HANDLE device_handle; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx; - AVDXVA2DeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, &device_handle); -- 2.52.0 From 7c6410061d7a6eca4982a3695bd1c4b57f8235af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Tue, 22 Sep 2026 11:39:11 +0200 Subject: [PATCH 2/3] avcodec/dxva2: map 4:2:2 and 4:4:4 surface formats for hwcontext use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 586c392bc7 av1dec offers AV_PIX_FMT_D3D11 for 8-bit and 10-bit 4:2:2 and 4:4:4 streams, but only the legacy hwaccel_context path could use it. With hw_device_ctx or hw_frames_ctx the shared ff_dxva2_common_frame_params mapped these streams to NV12 and d3d11va_map_sw_to_hw_format had no entry for the packed formats, so the decoder either failed the render target check or was created over surfaces of the wrong format. Map the 4:2:2 and 4:4:4 software formats to YUY2, Y210, Y216, AYUV, Y410 and Y416 as the DXVA specifications define them, so the D3D11 path now works for such streams. Signed-off-by: Kacper Michajłow <[email protected]> --- libavcodec/dxva2.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index 3ad80dfaad..052474e612 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -357,7 +357,16 @@ static D3DFORMAT dxva2_map_sw_to_hw_format(enum AVPixelFormat pix_fmt) switch (pix_fmt) { case AV_PIX_FMT_NV12: return MKTAG('N', 'V', '1', '2'); case AV_PIX_FMT_P010: return MKTAG('P', '0', '1', '0'); - case AV_PIX_FMT_P012: return MKTAG('P', '0', '1', '6'); + case AV_PIX_FMT_P012: + case AV_PIX_FMT_P016: return MKTAG('P', '0', '1', '6'); + case AV_PIX_FMT_YUYV422: return MKTAG('Y', 'U', 'Y', '2'); + case AV_PIX_FMT_Y210: return MKTAG('Y', '2', '1', '0'); + case AV_PIX_FMT_Y212: + case AV_PIX_FMT_Y216: return MKTAG('Y', '2', '1', '6'); + case AV_PIX_FMT_VUYX: return MKTAG('A', 'Y', 'U', 'V'); + case AV_PIX_FMT_XV30: return MKTAG('Y', '4', '1', '0'); + case AV_PIX_FMT_XV36: + case AV_PIX_FMT_XV48: return MKTAG('Y', '4', '1', '6'); default: return D3DFMT_UNKNOWN; } } @@ -479,7 +488,16 @@ static DXGI_FORMAT d3d11va_map_sw_to_hw_format(enum AVPixelFormat pix_fmt) switch (pix_fmt) { case AV_PIX_FMT_NV12: return DXGI_FORMAT_NV12; case AV_PIX_FMT_P010: return DXGI_FORMAT_P010; - case AV_PIX_FMT_P012: return DXGI_FORMAT_P016; + case AV_PIX_FMT_P012: + 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: + case AV_PIX_FMT_Y216: 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: + case AV_PIX_FMT_XV48: return DXGI_FORMAT_Y416; case AV_PIX_FMT_YUV420P: return DXGI_FORMAT_420_OPAQUE; default: return DXGI_FORMAT_UNKNOWN; } @@ -652,6 +670,12 @@ int ff_dxva2_common_frame_params(AVCodecContext *avctx, switch (avctx->sw_pix_fmt) { case AV_PIX_FMT_YUV420P10: frames_ctx->sw_format = AV_PIX_FMT_P010; break; case AV_PIX_FMT_YUV420P12: frames_ctx->sw_format = AV_PIX_FMT_P012; break; + case AV_PIX_FMT_YUV422P: frames_ctx->sw_format = AV_PIX_FMT_YUYV422; break; + case AV_PIX_FMT_YUV422P10: frames_ctx->sw_format = AV_PIX_FMT_Y210; break; + case AV_PIX_FMT_YUV422P12: frames_ctx->sw_format = AV_PIX_FMT_Y212; break; + case AV_PIX_FMT_YUV444P: frames_ctx->sw_format = AV_PIX_FMT_VUYX; break; + case AV_PIX_FMT_YUV444P10: frames_ctx->sw_format = AV_PIX_FMT_XV30; break; + case AV_PIX_FMT_YUV444P12: frames_ctx->sw_format = AV_PIX_FMT_XV36; break; default: frames_ctx->sw_format = AV_PIX_FMT_NV12; break; } frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment); -- 2.52.0 From 4201172253c6e094a47cf9b6391971a86bcdbaf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= <[email protected]> Date: Tue, 22 Sep 2026 11:39:12 +0200 Subject: [PATCH 3/3] avcodec: offer AV_PIX_FMT_D3D11 only when the d3d11va2 hwaccel is built MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don't know why CONFIG_<codec>_D3D11VA2_HWACCEL was ignored before, but clearly it should be checked here. Signed-off-by: Kacper Michajłow <[email protected]> --- libavcodec/av1dec.c | 17 ++++++++++++++++- libavcodec/h264_slice.c | 5 ++++- libavcodec/hevc/hevcdec.c | 7 ++++++- libavcodec/mpeg12dec.c | 2 ++ libavcodec/vc1dec.c | 2 ++ libavcodec/vp9.c | 5 ++++- 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index d7ccebfbd5..24d7b87dde 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -540,7 +540,8 @@ static int get_pixel_format(AVCodecContext *avctx) int ret; enum AVPixelFormat pix_fmt = get_sw_pixel_format(avctx, seq); #define HWACCEL_MAX (CONFIG_AV1_DXVA2_HWACCEL + \ - CONFIG_AV1_D3D11VA_HWACCEL * 2 + \ + CONFIG_AV1_D3D11VA_HWACCEL + \ + CONFIG_AV1_D3D11VA2_HWACCEL + \ CONFIG_AV1_D3D12VA_HWACCEL + \ CONFIG_AV1_NVDEC_HWACCEL + \ CONFIG_AV1_NVDEC_CUARRAY_HWACCEL + \ @@ -560,6 +561,8 @@ static int get_pixel_format(AVCodecContext *avctx) #endif #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_D3D12VA_HWACCEL @@ -590,6 +593,8 @@ static int get_pixel_format(AVCodecContext *avctx) #endif #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_D3D12VA_HWACCEL @@ -617,6 +622,8 @@ static int get_pixel_format(AVCodecContext *avctx) case AV_PIX_FMT_YUV420P12: #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_D3D12VA_HWACCEL @@ -629,6 +636,8 @@ static int get_pixel_format(AVCodecContext *avctx) case AV_PIX_FMT_YUV422P: #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_VULKAN_HWACCEL @@ -638,6 +647,8 @@ static int get_pixel_format(AVCodecContext *avctx) case AV_PIX_FMT_YUV422P10: #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_VULKAN_HWACCEL @@ -652,6 +663,8 @@ static int get_pixel_format(AVCodecContext *avctx) case AV_PIX_FMT_YUV444P: #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_VULKAN_HWACCEL @@ -661,6 +674,8 @@ static int get_pixel_format(AVCodecContext *avctx) case AV_PIX_FMT_YUV444P10: #if CONFIG_AV1_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_AV1_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_AV1_VULKAN_HWACCEL diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 2bcb64378d..c2f54ecc96 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -790,7 +790,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback, int data_partitioning) { #define HWACCEL_MAX (CONFIG_H264_DXVA2_HWACCEL + \ - (CONFIG_H264_D3D11VA_HWACCEL * 2) + \ + CONFIG_H264_D3D11VA_HWACCEL + \ + CONFIG_H264_D3D11VA2_HWACCEL + \ CONFIG_H264_D3D12VA_HWACCEL + \ CONFIG_H264_NVDEC_HWACCEL + \ CONFIG_H264_NVDEC_CUARRAY_HWACCEL + \ @@ -903,6 +904,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback, #endif #if CONFIG_H264_D3D11VA_HWACCEL *fmt++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_H264_D3D11VA2_HWACCEL *fmt++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_H264_D3D12VA_HWACCEL diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c index b6234a6c34..bbfbe8294d 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -580,7 +580,8 @@ static enum AVPixelFormat map_to_alpha_format(HEVCContext *s, static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \ - CONFIG_HEVC_D3D11VA_HWACCEL * 2 + \ + CONFIG_HEVC_D3D11VA_HWACCEL + \ + CONFIG_HEVC_D3D11VA2_HWACCEL + \ CONFIG_HEVC_D3D12VA_HWACCEL + \ CONFIG_HEVC_NVDEC_HWACCEL + \ CONFIG_HEVC_NVDEC_CUARRAY_HWACCEL + \ @@ -603,6 +604,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_D3D11VA_HWACCEL *fmt++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_HEVC_D3D11VA2_HWACCEL *fmt++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_HEVC_D3D12VA_HWACCEL @@ -633,6 +636,8 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_D3D11VA_HWACCEL *fmt++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_HEVC_D3D11VA2_HWACCEL *fmt++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_HEVC_D3D12VA_HWACCEL diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index bef003704a..f1e621ce4f 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -816,6 +816,8 @@ static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { #endif #if CONFIG_MPEG2_D3D11VA_HWACCEL AV_PIX_FMT_D3D11VA_VLD, +#endif +#if CONFIG_MPEG2_D3D11VA2_HWACCEL AV_PIX_FMT_D3D11, #endif #if CONFIG_MPEG2_D3D12VA_HWACCEL diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 1102e8123e..5fa7987bc5 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -58,6 +58,8 @@ static const enum AVPixelFormat vc1_hwaccel_pixfmt_list_420[] = { #endif #if CONFIG_VC1_D3D11VA_HWACCEL AV_PIX_FMT_D3D11VA_VLD, +#endif +#if CONFIG_VC1_D3D11VA2_HWACCEL AV_PIX_FMT_D3D11, #endif #if CONFIG_VC1_D3D12VA_HWACCEL diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index ce4e197c9d..8a8a3a1061 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -166,7 +166,8 @@ static void vp9_frame_replace(VP9Frame *dst, const VP9Frame *src) static int update_size(AVCodecContext *avctx, int w, int h) { #define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + \ - CONFIG_VP9_D3D11VA_HWACCEL * 2 + \ + CONFIG_VP9_D3D11VA_HWACCEL + \ + CONFIG_VP9_D3D11VA2_HWACCEL + \ CONFIG_VP9_D3D12VA_HWACCEL + \ CONFIG_VP9_NVDEC_HWACCEL + \ CONFIG_VP9_NVDEC_CUARRAY_HWACCEL + \ @@ -196,6 +197,8 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif #if CONFIG_VP9_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; +#endif +#if CONFIG_VP9_D3D11VA2_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_VP9_D3D12VA_HWACCEL -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
