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 }, \