PR #24696 opened by nyanmisaka
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24696
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24696.patch
# Summary of changes
RGB textures bound as render target and imported via
`CreateSurfaceFromDX{9,11}Native()`
may have DCC compression enabled, which the encoder's EFC HW might not support.
Duplicate the AMF surface to disable DCC and ensure it is always compatible.
See also https://github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/574
Signed-off-by: nyanmisaka <[email protected]>
Supersedes https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24688
>From 89a0de464b3b2a79f080ecbf4621587bd5d8c85e Mon Sep 17 00:00:00 2001
From: nyanmisaka <[email protected]>
Date: Sat, 26 Sep 2026 02:25:52 +0800
Subject: [PATCH] avcodec/amfenc: fix encoding RGB DX9/DX11 textures with DCC
enabled
RGB textures bound as render target and imported via
`CreateSurfaceFromDX{9,11}Native()`
may have DCC compression enabled, which the encoder's EFC HW might not support.
Duplicate the AMF surface to disable DCC and ensure it is always compatible.
See also https://github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/574
Signed-off-by: nyanmisaka <[email protected]>
---
libavcodec/amfenc.c | 111 +++++++++++++++++++++++++++++++-------------
libavcodec/amfenc.h | 1 +
2 files changed, 80 insertions(+), 32 deletions(-)
diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c
index 3ffca750d8..7a07e61bbf 100644
--- a/libavcodec/amfenc.c
+++ b/libavcodec/amfenc.c
@@ -22,11 +22,11 @@
#include "libavutil/imgutils.h"
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_amf.h"
+#define COBJMACROS
#if CONFIG_D3D11VA
#include "libavutil/hwcontext_d3d11va.h"
#endif
#if CONFIG_DXVA2
-#define COBJMACROS
#include "libavutil/hwcontext_dxva2.h"
#endif
#include "libavutil/mem.h"
@@ -39,10 +39,6 @@
#define AMF_AV_FRAME_REF L"av_frame_ref"
#define PTS_PROP L"PtsProp"
-#if CONFIG_D3D11VA
-#include <d3d11.h>
-#endif
-
#ifdef _WIN32
#include "compat/w32dlfcn.h"
#else
@@ -79,6 +75,7 @@ static int amf_init_encoder(AVCodecContext *avctx)
{
AMFEncoderContext *ctx = avctx->priv_data;
const wchar_t *codec_id = NULL;
+ const wchar_t *cap_color_conversion = NULL;
AMF_RESULT res;
enum AVPixelFormat pix_fmt;
AVHWDeviceContext *hw_device_ctx =
(AVHWDeviceContext*)ctx->device_ctx_ref->data;
@@ -100,17 +97,20 @@ static int amf_init_encoder(AVCodecContext *avctx)
next_encoder_index++;
switch (avctx->codec->id) {
- case AV_CODEC_ID_H264:
- codec_id = AMFVideoEncoderVCE_AVC;
- break;
- case AV_CODEC_ID_HEVC:
- codec_id = AMFVideoEncoder_HEVC;
- break;
- case AV_CODEC_ID_AV1 :
- codec_id = AMFVideoEncoder_AV1;
- break;
- default:
- break;
+ case AV_CODEC_ID_H264:
+ codec_id = AMFVideoEncoderVCE_AVC;
+ cap_color_conversion = AMF_VIDEO_ENCODER_CAP_COLOR_CONVERSION;
+ break;
+ case AV_CODEC_ID_HEVC:
+ codec_id = AMFVideoEncoder_HEVC;
+ cap_color_conversion = AMF_VIDEO_ENCODER_HEVC_CAP_COLOR_CONVERSION;
+ break;
+ case AV_CODEC_ID_AV1 :
+ codec_id = AMFVideoEncoder_AV1;
+ cap_color_conversion = AMF_VIDEO_ENCODER_AV1_CAP_COLOR_CONVERSION;
+ break;
+ default:
+ break;
}
AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is
not supported\n", avctx->codec->id);
@@ -130,6 +130,22 @@ static int amf_init_encoder(AVCodecContext *avctx)
res =
amf_device_ctx->factory->pVtbl->CreateComponent(amf_device_ctx->factory,
amf_device_ctx->context, codec_id, &ctx->encoder);
AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND,
"CreateComponent(%ls) failed with error %d\n", codec_id, res);
+ ctx->efc = 0;
+ if (cap_color_conversion) {
+ AMFCaps *encoder_caps = NULL;
+ res = ctx->encoder->pVtbl->GetCaps(ctx->encoder, &encoder_caps);
+ if (res == AMF_OK && encoder_caps) {
+ AMFVariantStruct var = { 0 };
+ res = encoder_caps->pVtbl->GetProperty(encoder_caps,
cap_color_conversion, &var);
+ if (res == AMF_OK && var.type == AMF_VARIANT_INT64) {
+ // AMF_ACCEL_GPU: shader-based, supports DCC
+ // AMF_ACCEL_HARDWARE: fixed-function EFC HW, may not support
DCC
+ ctx->efc = var.int64Value == AMF_ACCEL_HARDWARE;
+ AMFVariantClear(&var);
+ }
+ }
+ }
+
ctx->submitted_frame = 0;
ctx->encoded_frame = 0;
ctx->eof = 0;
@@ -167,7 +183,7 @@ int av_cold ff_amf_encode_close(AVCodecContext *avctx)
}
static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame,
- AMFSurface* surface)
+ AMFSurface *surface)
{
AMFPlane *plane;
uint8_t *dst_data[4] = {0};
@@ -389,7 +405,7 @@ static AMF_RESULT
amf_release_attached_frame_ref(AMFEncoderContext *ctx, AMFBuff
return res;
}
-static int amf_submit_frame(AVCodecContext *avctx, AVFrame *frame,
AMFSurface **surface_resubmit)
+static int amf_submit_frame(AVCodecContext *avctx, AVFrame *frame, AMFSurface
**surface_resubmit)
{
AMFEncoderContext *ctx = avctx->priv_data;
AVHWDeviceContext *hw_device_ctx =
(AVHWDeviceContext*)ctx->device_ctx_ref->data;
@@ -398,9 +414,10 @@ static int amf_submit_frame(AVCodecContext *avctx, AVFrame
*frame, AMFSurface
AMF_RESULT res;
int ret;
int hw_surface = 0;
+ int needs_duplicate = 0;
int output_delay = FFMAX(ctx->max_b_frames, 0) +
((avctx->flags & AV_CODEC_FLAG_LOW_DELAY) ? 0 : 1);
-// prepare surface from frame
+ // prepare surface from frame
switch (frame->format) {
#if CONFIG_D3D11VA
case AV_PIX_FMT_D3D11:
@@ -408,12 +425,22 @@ static int amf_submit_frame(AVCodecContext *avctx,
AVFrame *frame, AMFSurface
static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3,
0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } };
ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; //
actual texture
int index = (intptr_t)frame->data[1]; // index is a slice in
texture array is - set to tell AMF which slice to use
- av_assert0(frame->hw_frames_ctx && avctx->hw_frames_ctx
&&
- frame->hw_frames_ctx->data == avctx->hw_frames_ctx->data);
- texture->lpVtbl->SetPrivateData(texture,
&AMFTextureArrayIndexGUID, sizeof(index), &index);
- res =
amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(amf_device_ctx->context,
texture, &surface, NULL); // wrap to AMF surface
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"CreateSurfaceFromDX11Native() failed with error %d\n", res);
- hw_surface = 1;
+ av_assert0(frame->hw_frames_ctx && avctx->hw_frames_ctx &&
+ frame->hw_frames_ctx->data ==
avctx->hw_frames_ctx->data);
+ texture->lpVtbl->SetPrivateData(texture,
&AMFTextureArrayIndexGUID, sizeof(index), &index);
+ res =
amf_device_ctx->context->pVtbl->CreateSurfaceFromDX11Native(amf_device_ctx->context,
texture, &surface, NULL); // wrap to AMF surface
+ AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"CreateSurfaceFromDX11Native() failed with error %d\n", res);
+
+ if (ctx->efc) {
+ const AVPixFmtDescriptor *pix_desc =
av_pix_fmt_desc_get(((AVHWFramesContext*)frame->hw_frames_ctx->data)->sw_format);
+ av_assert0(pix_desc);
+ if (pix_desc->flags & AV_PIX_FMT_FLAG_RGB) {
+ D3D11_TEXTURE2D_DESC tex_desc;
+ ID3D11Texture2D_GetDesc(texture, &tex_desc);
+ needs_duplicate = !!(tex_desc.BindFlags &
D3D11_BIND_RENDER_TARGET);
+ }
+ }
+ hw_surface = 1;
}
break;
#endif
@@ -421,9 +448,19 @@ static int amf_submit_frame(AVCodecContext *avctx, AVFrame
*frame, AMFSurface
case AV_PIX_FMT_DXVA2_VLD:
{
IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3];
// actual texture
- res =
amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(amf_device_ctx->context,
texture, &surface, NULL); // wrap to AMF surface
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"CreateSurfaceFromDX9Native() failed with error %d\n", res);
- hw_surface = 1;
+ res =
amf_device_ctx->context->pVtbl->CreateSurfaceFromDX9Native(amf_device_ctx->context,
texture, &surface, NULL); // wrap to AMF surface
+ AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"CreateSurfaceFromDX9Native() failed with error %d\n", res);
+
+ if (ctx->efc) {
+ const AVPixFmtDescriptor *pix_desc =
av_pix_fmt_desc_get(((AVHWFramesContext*)frame->hw_frames_ctx->data)->sw_format);
+ av_assert0(pix_desc);
+ if (pix_desc->flags & AV_PIX_FMT_FLAG_RGB) {
+ D3DSURFACE_DESC tex_desc;
+ needs_duplicate =
SUCCEEDED(IDirect3DSurface9_GetDesc(texture, &tex_desc)) &&
+ (tex_desc.Usage & D3DUSAGE_RENDERTARGET);
+ }
+ }
+ hw_surface = 1;
}
break;
#endif
@@ -437,23 +474,33 @@ static int amf_submit_frame(AVCodecContext *avctx,
AVFrame *frame, AMFSurface
default:
{
res =
amf_device_ctx->context->pVtbl->AllocSurface(amf_device_ctx->context,
AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface);
- AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"AllocSurface() failed with error %d\n", res);
+ AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"AllocSurface() failed with error %d\n", res);
amf_copy_surface(avctx, frame, surface);
}
break;
}
if (hw_surface) {
+ // RGB textures bound as render target and imported via
CreateSurfaceFromDX{9,11}Native()
+ // may have DCC compression enabled, which the encoder's EFC HW might
not support.
+ // Duplicate the AMF surface to disable DCC and ensure it is always
compatible.
+ if (needs_duplicate) {
+ AMFData *out_surface = NULL;
+ res = surface->pVtbl->Duplicate(surface,
surface->pVtbl->GetMemoryType(surface), &out_surface);
+ surface->pVtbl->Release(surface);
+ AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM),
"Duplicate() failed with error %d\n", res);
+ surface = (AMFSurface*)out_surface;
+ }
amf_store_attached_frame_ref(ctx, frame, surface);
ctx->hwsurfaces_in_queue++;
// input HW surfaces can be vertically aligned by 16; tell AMF the
real size
surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height);
}
- // HDR10 metadata
+ // HDR10 metadata
if (frame->color_trc == AVCOL_TRC_SMPTE2084) {
- AMFBuffer * hdrmeta_buffer = NULL;
+ AMFBuffer *hdrmeta_buffer = NULL;
res =
amf_device_ctx->context->pVtbl->AllocBuffer(amf_device_ctx->context,
AMF_MEMORY_HOST, sizeof(AMFHDRMetadata), &hdrmeta_buffer);
if (res == AMF_OK) {
- AMFHDRMetadata * hdrmeta =
(AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
+ AMFHDRMetadata *hdrmeta =
(AMFHDRMetadata*)hdrmeta_buffer->pVtbl->GetNative(hdrmeta_buffer);
if (av_amf_extract_hdr_metadata(frame, hdrmeta) == 0) {
switch (avctx->codec->id) {
case AV_CODEC_ID_H264:
diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h
index 1571541b9b..0611a539c8 100644
--- a/libavcodec/amfenc.h
+++ b/libavcodec/amfenc.h
@@ -46,6 +46,7 @@ typedef struct AMFEncoderContext {
AMFComponent *encoder; ///< AMF encoder object
amf_bool eof; ///< flag indicating EOF happened
AMF_SURFACE_FORMAT format; ///< AMF surface format
+ amf_bool efc; ///< whether EncoderFormatConversion HW is
supported
wchar_t *pts_property_name;
wchar_t *av_frame_property_name;
--
2.52.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]