This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch master
in repository ffmpeg.
The following commit(s) were added to refs/heads/master by this push:
new 64b9be2dc5 avcodec/d3d12va_encode: support motion estimation precision
mode
64b9be2dc5 is described below
commit 64b9be2dc51d49d05ad46edec85d68034dd120e2
Author: stevxiao <[email protected]>
AuthorDate: Wed Nov 19 13:14:17 2025 -0500
Commit: Tong Wu <[email protected]>
CommitDate: Mon Dec 22 05:35:04 2025 +0000
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
---
configure | 2 +
libavcodec/d3d12va_encode.c | 91 ++++++++++++++++++++++++++++++++++++++++++++-
libavcodec/d3d12va_encode.h | 38 ++++++++++++++++++-
3 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/configure b/configure
index 4791a67562..301a3e5e3e 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c
index f15df37b96..de95518be5 100644
--- a/libavcodec/d3d12va_encode.c
+++ b/libavcodec/d3d12va_encode.c
@@ -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) {
diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h
index 699d8d2077..fcb97210b3 100644
--- a/libavcodec/d3d12va_encode.h
+++ b/libavcodec/d3d12va_encode.h
@@ -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 }, \
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]