mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 21:00:41 +08:00
avcodec/d3d12va_encode: support motion estimation precision mode
By default, the D3D12 video encoder uses MAXIMUM, which means no restriction—it uses the highest precision supported by the driver. Applications may want to reduce precision to improve speed or reduce power consumption. This requires the encoder to support user-defined motion estimation precision modes. D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE defines several precision modes: maximum: No restriction, uses the maximum precision supported by the driver. full_pixel: Allows only full-pixel precision. half_pixel: Allows half-pixel precision. quarter-pixel: Allows quarter-pixel precision. eighth-pixel: Allows eighth-pixel precision (introduced in Windows 11). Sample Command Line: ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -extra_hw_frames 20 -i input.mp4 -an -c:v h264_d3d12va -me_precision half_pixel out.mp4
This commit is contained in:
2
configure
vendored
2
configure
vendored
@@ -2624,6 +2624,7 @@ CONFIG_EXTRA="
|
||||
celp_math
|
||||
d3d12_intra_refresh
|
||||
d3d12va_encode
|
||||
d3d12va_me_precision_eighth_pixel
|
||||
deflate_wrapper
|
||||
dirac_parse
|
||||
dnn
|
||||
@@ -6979,6 +6980,7 @@ test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_VIDEO feature = D3D12_FEATU
|
||||
test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOURCE_REQUIREMENTS req" && enable d3d12_encoder_feature
|
||||
test_code cc "windows.h d3d12video.h" "D3D12_VIDEO_ENCODER_CODEC c = D3D12_VIDEO_ENCODER_CODEC_AV1; (void)c;" && enable d3d12va_av1_headers
|
||||
test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_DATA_VIDEO_ENCODER_INTRA_REFRESH_MODE check = { 0 };" && enable d3d12_intra_refresh
|
||||
test_code cc "windows.h d3d12video.h" "D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE m = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_EIGHTH_PIXEL; (void)m;" && enable d3d12va_me_precision_eighth_pixel
|
||||
check_type "windows.h" "DPI_AWARENESS_CONTEXT" -D_WIN32_WINNT=0x0A00
|
||||
check_type "windows.h security.h schnlsp.h" SecPkgContext_KeyingMaterialInfo -DSECURITY_WIN32
|
||||
check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602
|
||||
|
||||
@@ -1143,6 +1143,91 @@ rc_mode_found:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int d3d12va_encode_init_motion_estimation_precision(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
D3D12VAEncodeContext *ctx = avctx->priv_data;
|
||||
AVD3D12VAFramesContext *hwctx = base_ctx->input_frames->hwctx;
|
||||
HRESULT hr;
|
||||
|
||||
if (ctx->me_precision == D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM)
|
||||
return 0;
|
||||
|
||||
D3D12_VIDEO_ENCODER_PROFILE_DESC profile = { 0 };
|
||||
D3D12_VIDEO_ENCODER_PROFILE_H264 h264_profile = D3D12_VIDEO_ENCODER_PROFILE_H264_MAIN;
|
||||
D3D12_VIDEO_ENCODER_PROFILE_HEVC hevc_profile = D3D12_VIDEO_ENCODER_PROFILE_HEVC_MAIN;
|
||||
#if CONFIG_AV1_D3D12VA_ENCODER
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE av1_profile = D3D12_VIDEO_ENCODER_AV1_PROFILE_MAIN;
|
||||
#endif
|
||||
|
||||
D3D12_VIDEO_ENCODER_LEVEL_SETTING level = { 0 };
|
||||
D3D12_VIDEO_ENCODER_LEVELS_H264 h264_level = { 0 };
|
||||
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevc_level = { 0 };
|
||||
#if CONFIG_AV1_D3D12VA_ENCODER
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1_level = { 0 };
|
||||
#endif
|
||||
|
||||
switch (ctx->codec->d3d12_codec) {
|
||||
case D3D12_VIDEO_ENCODER_CODEC_H264:
|
||||
profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_H264);
|
||||
profile.pH264Profile = &h264_profile;
|
||||
level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264);
|
||||
level.pH264LevelSetting = &h264_level;
|
||||
break;
|
||||
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
|
||||
profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_PROFILE_HEVC);
|
||||
profile.pHEVCProfile = &hevc_profile;
|
||||
level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC);
|
||||
level.pHEVCLevelSetting = &hevc_level;
|
||||
break;
|
||||
#if CONFIG_AV1_D3D12VA_ENCODER
|
||||
case D3D12_VIDEO_ENCODER_CODEC_AV1:
|
||||
profile.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PROFILE);
|
||||
profile.pAV1Profile = &av1_profile;
|
||||
level.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS);
|
||||
level.pAV1LevelSetting = &av1_level;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
av_assert0(0);
|
||||
}
|
||||
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT support = {
|
||||
.NodeIndex = 0,
|
||||
.Codec = ctx->codec->d3d12_codec,
|
||||
.InputFormat = hwctx->format,
|
||||
.RateControl = ctx->rc,
|
||||
.IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
|
||||
.SubregionFrameEncoding = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
|
||||
.ResolutionsListCount = 1,
|
||||
.pResolutionList = &ctx->resolution,
|
||||
.CodecGopSequence = ctx->gop,
|
||||
.MaxReferenceFramesInDPB = MAX_DPB_SIZE - 1,
|
||||
.CodecConfiguration = ctx->codec_conf,
|
||||
.SuggestedProfile = profile,
|
||||
.SuggestedLevel = level,
|
||||
.pResolutionDependentSupport = &ctx->res_limits,
|
||||
};
|
||||
|
||||
hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
|
||||
&support, sizeof(support));
|
||||
if (FAILED(hr)) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Failed to check encoder support for motion estimation.\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if (!(support.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_MOTION_ESTIMATION_PRECISION_MODE_LIMIT_AVAILABLE)) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Hardware does not support motion estimation "
|
||||
"precision mode limits.\n");
|
||||
return AVERROR(ENOTSUP);
|
||||
}
|
||||
|
||||
av_log(avctx, AV_LOG_VERBOSE, "Hardware supports motion estimation "
|
||||
"precision mode limits.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
@@ -1322,7 +1407,7 @@ static int d3d12va_create_encoder(AVCodecContext *avctx)
|
||||
.EncodeProfile = ctx->profile->d3d12_profile,
|
||||
.InputFormat = frames_hwctx->format,
|
||||
.CodecConfiguration = ctx->codec_conf,
|
||||
.MaxMotionEstimationPrecision = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM,
|
||||
.MaxMotionEstimationPrecision = ctx->me_precision,
|
||||
};
|
||||
|
||||
hr = ID3D12VideoDevice3_CreateVideoEncoder(ctx->video_device3, &desc, &IID_ID3D12VideoEncoder,
|
||||
@@ -1681,6 +1766,10 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = d3d12va_encode_init_motion_estimation_precision(avctx);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
if (ctx->codec->init_sequence_params) {
|
||||
err = ctx->codec->init_sequence_params(avctx);
|
||||
if (err < 0) {
|
||||
|
||||
@@ -277,6 +277,11 @@ typedef struct D3D12VAEncodeContext {
|
||||
*/
|
||||
UINT intra_refresh_frame_index;
|
||||
|
||||
/**
|
||||
* Motion estimation precision mode
|
||||
*/
|
||||
D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE me_precision;
|
||||
|
||||
} D3D12VAEncodeContext;
|
||||
|
||||
typedef struct D3D12VAEncodeType {
|
||||
@@ -362,6 +367,24 @@ int ff_d3d12va_encode_close(AVCodecContext *avctx);
|
||||
{ #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ ## mode }, \
|
||||
0, 0, FLAGS, .unit = "intra_refresh_mode" }
|
||||
|
||||
#if CONFIG_D3D12VA_ME_PRECISION_EIGHTH_PIXEL
|
||||
#define D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAX_VALUE D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_EIGHTH_PIXEL
|
||||
#else
|
||||
#define D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAX_VALUE D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_QUARTER_PIXEL
|
||||
#endif
|
||||
|
||||
#define D3D12VA_ENCODE_ME_PRECISION_MODE(name, mode, desc) \
|
||||
{ #name, #desc " pixel precision", 0, AV_OPT_TYPE_CONST, \
|
||||
{ .i64 = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_ ## mode }, \
|
||||
0, 0, FLAGS, .unit = "me_precision" }
|
||||
|
||||
#if CONFIG_D3D12VA_ME_PRECISION_EIGHTH_PIXEL
|
||||
#define FFPP_D3D12VA_ME_PRECISION_EIGHTH_PIXEL \
|
||||
, D3D12VA_ENCODE_ME_PRECISION_MODE(eighth_pixel, EIGHTH_PIXEL, Eighth)
|
||||
#else
|
||||
#define FFPP_D3D12VA_ME_PRECISION_EIGHTH_PIXEL
|
||||
#endif
|
||||
|
||||
#define D3D12VA_ENCODE_COMMON_OPTIONS \
|
||||
{ "max_frame_size", \
|
||||
"Maximum frame size (in bytes)",\
|
||||
@@ -378,7 +401,20 @@ int ff_d3d12va_encode_close(AVCodecContext *avctx);
|
||||
{ "intra_refresh_duration", \
|
||||
"Number of frames over which to spread intra refresh (0 = GOP size)", \
|
||||
OFFSET(common.intra_refresh.IntraRefreshDuration), AV_OPT_TYPE_INT, \
|
||||
{ .i64 = 0 }, 0, INT_MAX, FLAGS }
|
||||
{ .i64 = 0 }, 0, INT_MAX, FLAGS }, \
|
||||
{ "me_precision", "Motion estimation precision mode", \
|
||||
OFFSET(common.me_precision), AV_OPT_TYPE_INT, \
|
||||
{ .i64 = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM }, \
|
||||
D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM, \
|
||||
D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAX_VALUE, \
|
||||
FLAGS, .unit = "me_precision" }, \
|
||||
{ "maximum", "Maximum (best quality, slowest)", 0, AV_OPT_TYPE_CONST, \
|
||||
{ .i64 = D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE_MAXIMUM }, \
|
||||
0, 0, FLAGS, .unit = "me_precision" }, \
|
||||
D3D12VA_ENCODE_ME_PRECISION_MODE(full_pixel, FULL_PIXEL, Full), \
|
||||
D3D12VA_ENCODE_ME_PRECISION_MODE(half_pixel, HALF_PIXEL, Half), \
|
||||
D3D12VA_ENCODE_ME_PRECISION_MODE(quarter_pixel, QUARTER_PIXEL, Quarter) \
|
||||
FFPP_D3D12VA_ME_PRECISION_EIGHTH_PIXEL
|
||||
|
||||
#define D3D12VA_ENCODE_RC_MODE(name, desc) \
|
||||
{ #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \
|
||||
|
||||
Reference in New Issue
Block a user