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 7b2ae2ccf7 avcodec/d3d12va_encode: add intra refresh support for 
d3d12va encode
7b2ae2ccf7 is described below

commit 7b2ae2ccf79954fb7d3e3a668e0bd50bd512040d
Author:     stevxiao <[email protected]>
AuthorDate: Fri Nov 21 20:39:22 2025 -0500
Commit:     Tong Wu <[email protected]>
CommitDate: Thu Dec 4 08:26:26 2025 +0000

    avcodec/d3d12va_encode: add intra refresh support for d3d12va encode
    
    Intra refresh is a technique that gradually refreshes the video by encoding 
rows or regions as intra macroblocks/CTUs spread over multiple frames, rather 
than using periodic I-frames.
    This provides better error resilience for video streaming while maintaining 
more consistent bitrate.
    
    Disable Intra Refresh (This is the default)
    ffmpeg -init_hw_device d3d12va -hwaccel d3d12va -hwaccel_output_format 
d3d12 \
    -i input.mp4 \
    -c:v h264_d3d12va \
    -intra_refresh_mode none \
    -intra_refresh_duration 30 \
    -g 60 \
    output.h264
    
    Enable Intra Refresh
    ffmpeg -init_hw_device d3d12va -hwaccel d3d12va -hwaccel_output_format 
d3d12 \
    -i input.mp4 \
    -c:v h264_d3d12va \
    -intra_refresh_mode row_based \
    -intra_refresh_duration 30 \
    -g 60 \
    output.h264
    
    Parameters
    - `-intra_refresh_mode`: Set to `row_based` to enable row-based intra 
refresh, or `NONE` to disable
    - `-intra_refresh_duration`: Number of frames over which to spread the 
intra refresh (default: 0 = use GOP size)
    - `-g`: GOP size (should typically be larger than intra refresh duration)
---
 configure                        |  2 +
 libavcodec/d3d12va_encode.c      | 98 ++++++++++++++++++++++++++++++++++++++--
 libavcodec/d3d12va_encode.h      | 29 +++++++++++-
 libavcodec/d3d12va_encode_av1.c  |  3 +-
 libavcodec/d3d12va_encode_h264.c |  2 +-
 libavcodec/d3d12va_encode_hevc.c |  2 +-
 6 files changed, 129 insertions(+), 7 deletions(-)

diff --git a/configure b/configure
index 883539e361..04e086c32a 100755
--- a/configure
+++ b/configure
@@ -2615,6 +2615,7 @@ CONFIG_EXTRA="
     cbs_vp8
     cbs_vp9
     celp_math
+    d3d12_intra_refresh
     d3d12va_encode
     deflate_wrapper
     dirac_parse
@@ -6964,6 +6965,7 @@ check_type "windows.h d3d12video.h" "ID3D12VideoEncoder"
 test_code cc "windows.h d3d12video.h" "D3D12_FEATURE_VIDEO feature = 
D3D12_FEATURE_VIDEO_ENCODER_CODEC" && \
 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
 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 5a82a42c5f..f15df37b96 100644
--- a/libavcodec/d3d12va_encode.c
+++ b/libavcodec/d3d12va_encode.c
@@ -211,10 +211,17 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
     int barriers_ref_index = 0;
     D3D12_RESOURCE_BARRIER *barriers_ref = NULL;
 
+    D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS seq_flags = 
D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE;
+
+    // Request intra refresh if enabled
+    if (ctx->intra_refresh.Mode != 
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) {
+        seq_flags |= 
D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_REQUEST_INTRA_REFRESH;
+    }
+
     D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS input_args = {
         .SequenceControlDesc = {
-            .Flags = D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_NONE,
-            .IntraRefreshConfig = { 0 },
+            .Flags = seq_flags,
+            .IntraRefreshConfig = ctx->intra_refresh,
             .RateControl = ctx->rc,
             .PictureTargetResolution = ctx->resolution,
             .SelectedLayoutMode = 
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
@@ -359,7 +366,7 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
         }
     }
 
-    input_args.PictureControlDesc.IntraRefreshFrameIndex  = 0;
+    input_args.PictureControlDesc.IntraRefreshFrameIndex  = 
ctx->intra_refresh_frame_index;
     if (base_pic->is_reference)
         input_args.PictureControlDesc.Flags |= 
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
 
@@ -547,6 +554,12 @@ static int d3d12va_encode_issue(AVCodecContext *avctx,
 
     pic->fence_value = ctx->sync_ctx.fence_value;
 
+    // Update intra refresh frame index for next frame
+    if (ctx->intra_refresh.Mode != 
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE) {
+        ctx->intra_refresh_frame_index =
+            (ctx->intra_refresh_frame_index + 1) % 
ctx->intra_refresh.IntraRefreshDuration;
+    }
+
     if (d3d12_refs.ppTexture2Ds)
         av_freep(&d3d12_refs.ppTexture2Ds);
 
@@ -1220,6 +1233,81 @@ static int 
d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
     return 0;
 }
 
+static int d3d12va_encode_init_intra_refresh(AVCodecContext *avctx)
+{
+    FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
+    D3D12VAEncodeContext       *ctx = avctx->priv_data;
+
+    if (ctx->intra_refresh.Mode == D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE)
+        return 0;
+
+    // Check for SDK API availability
+#if CONFIG_D3D12_INTRA_REFRESH
+    HRESULT hr;
+    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:
+            level.DataSize = sizeof(D3D12_VIDEO_ENCODER_LEVELS_H264);
+            level.pH264LevelSetting = &h264_level;
+            break;
+        case D3D12_VIDEO_ENCODER_CODEC_HEVC:
+            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:
+            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_INTRA_REFRESH_MODE intra_refresh_support 
= {
+        .NodeIndex = 0,
+        .Codec = ctx->codec->d3d12_codec,
+        .Profile = ctx->profile->d3d12_profile,
+        .Level = level,
+        .IntraRefreshMode = ctx->intra_refresh.Mode,
+    };
+
+    hr = ID3D12VideoDevice3_CheckFeatureSupport(ctx->video_device3,
+        D3D12_FEATURE_VIDEO_ENCODER_INTRA_REFRESH_MODE,
+        &intra_refresh_support, sizeof(intra_refresh_support));
+
+    if (FAILED(hr) || !intra_refresh_support.IsSupported) {
+        av_log(avctx, AV_LOG_ERROR, "Requested intra refresh mode not 
supported by driver.\n");
+        return AVERROR(ENOTSUP);
+    }
+#else
+    // Older SDK - validation will occur in init_sequence_params via 
D3D12_FEATURE_VIDEO_ENCODER_SUPPORT
+    av_log(avctx, AV_LOG_VERBOSE, "Intra refresh explicit check not available 
in this SDK.\n"
+           "Support will be validated during encoder initialization.\n");
+#endif
+
+    // Set duration: use GOP size if not specified
+    if (ctx->intra_refresh.IntraRefreshDuration == 0) {
+        ctx->intra_refresh.IntraRefreshDuration = base_ctx->gop_size;
+        av_log(avctx, AV_LOG_VERBOSE, "Intra refresh duration set to GOP size: 
%d\n",
+               ctx->intra_refresh.IntraRefreshDuration);
+    }
+
+    // Initialize frame index
+    ctx->intra_refresh_frame_index = 0;
+
+    av_log(avctx, AV_LOG_VERBOSE, "Intra refresh: mode=%d, duration=%d 
frames\n",
+           ctx->intra_refresh.Mode, ctx->intra_refresh.IntraRefreshDuration);
+
+    return 0;
+}
+
 static int d3d12va_create_encoder(AVCodecContext *avctx)
 {
     FFHWBaseEncodeContext  *base_ctx     = avctx->priv_data;
@@ -1570,6 +1658,10 @@ int ff_d3d12va_encode_init(AVCodecContext *avctx)
     if (err < 0)
         goto fail;
 
+    err = d3d12va_encode_init_intra_refresh(avctx);
+    if (err < 0)
+        goto fail;
+
     if (!(ctx->codec->flags & FF_HW_FLAG_SLICE_CONTROL) && avctx->slices > 0) {
         av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested "
                "but this codec does not support controlling slices.\n");
diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h
index b7cfea0582..699d8d2077 100644
--- a/libavcodec/d3d12va_encode.h
+++ b/libavcodec/d3d12va_encode.h
@@ -266,6 +266,17 @@ typedef struct D3D12VAEncodeContext {
     D3D12_VIDEO_ENCODER_LEVEL_SETTING level;
 
     D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA 
subregions_layout;
+
+    /**
+     * Intra refresh configuration
+     */
+    D3D12_VIDEO_ENCODER_INTRA_REFRESH intra_refresh;
+
+    /**
+     * Current frame index within intra refresh cycle
+     */
+    UINT intra_refresh_frame_index;
+
 } D3D12VAEncodeContext;
 
 typedef struct D3D12VAEncodeType {
@@ -347,11 +358,27 @@ int ff_d3d12va_encode_receive_packet(AVCodecContext 
*avctx, AVPacket *pkt);
 int ff_d3d12va_encode_init(AVCodecContext *avctx);
 int ff_d3d12va_encode_close(AVCodecContext *avctx);
 
+#define D3D12VA_ENCODE_INTRA_REFRESH_MODE(name, mode, desc) \
+    { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = 
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ ## mode }, \
+      0, 0, FLAGS, .unit = "intra_refresh_mode" }
+
 #define D3D12VA_ENCODE_COMMON_OPTIONS \
     { "max_frame_size", \
       "Maximum frame size (in bytes)",\
       OFFSET(common.max_frame_size), AV_OPT_TYPE_INT, \
-      { .i64 = 0 }, 0, INT_MAX / 8, FLAGS }
+      { .i64 = 0 }, 0, INT_MAX / 8, FLAGS }, \
+    { "intra_refresh_mode", \
+      "Set intra refresh mode", \
+      OFFSET(common.intra_refresh.Mode), AV_OPT_TYPE_INT, \
+      { .i64 = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE }, \
+      D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE, \
+      D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED, FLAGS, .unit = 
"intra_refresh_mode" }, \
+    D3D12VA_ENCODE_INTRA_REFRESH_MODE(none, NONE, "Disable intra refresh"), \
+    D3D12VA_ENCODE_INTRA_REFRESH_MODE(row_based, ROW_BASED, "Row-based intra 
refresh"), \
+    { "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 }
 
 #define D3D12VA_ENCODE_RC_MODE(name, desc) \
     { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \
diff --git a/libavcodec/d3d12va_encode_av1.c b/libavcodec/d3d12va_encode_av1.c
index 34e803db98..31d3df33bd 100644
--- a/libavcodec/d3d12va_encode_av1.c
+++ b/libavcodec/d3d12va_encode_av1.c
@@ -559,7 +559,7 @@ static int 
d3d12va_encode_av1_init_sequence_params(AVCodecContext *avctx)
         .Codec                            = D3D12_VIDEO_ENCODER_CODEC_AV1,
         .InputFormat                      = hwctx->format,
         .RateControl                      = ctx->rc,
-        .IntraRefresh                     = 
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
+        .IntraRefresh                     = ctx->intra_refresh.Mode,
         .SubregionFrameEncoding           = 
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
         .ResolutionsListCount             = 1,
         .pResolutionList                  = &ctx->resolution,
@@ -1082,6 +1082,7 @@ static int d3d12va_encode_av1_close(AVCodecContext *avctx)
 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
 static const AVOption d3d12va_encode_av1_options[] = {
     HW_BASE_ENCODE_COMMON_OPTIONS,
+    D3D12VA_ENCODE_COMMON_OPTIONS,
     D3D12VA_ENCODE_RC_OPTIONS,
 
     { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)",
diff --git a/libavcodec/d3d12va_encode_h264.c b/libavcodec/d3d12va_encode_h264.c
index 967544ea24..bcf5a326e5 100644
--- a/libavcodec/d3d12va_encode_h264.c
+++ b/libavcodec/d3d12va_encode_h264.c
@@ -178,7 +178,7 @@ static int 
d3d12va_encode_h264_init_sequence_params(AVCodecContext *avctx)
         .Codec                            = D3D12_VIDEO_ENCODER_CODEC_H264,
         .InputFormat                      = hwctx->format,
         .RateControl                      = ctx->rc,
-        .IntraRefresh                     = 
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
+        .IntraRefresh                     = ctx->intra_refresh.Mode,
         .SubregionFrameEncoding           = 
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
         .ResolutionsListCount             = 1,
         .pResolutionList                  = &ctx->resolution,
diff --git a/libavcodec/d3d12va_encode_hevc.c b/libavcodec/d3d12va_encode_hevc.c
index 01e5b4cb4c..e00ecbb4de 100644
--- a/libavcodec/d3d12va_encode_hevc.c
+++ b/libavcodec/d3d12va_encode_hevc.c
@@ -250,7 +250,7 @@ static int 
d3d12va_encode_hevc_init_sequence_params(AVCodecContext *avctx)
         .Codec                            = D3D12_VIDEO_ENCODER_CODEC_HEVC,
         .InputFormat                      = hwctx->format,
         .RateControl                      = ctx->rc,
-        .IntraRefresh                     = 
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
+        .IntraRefresh                     = ctx->intra_refresh.Mode,
         .SubregionFrameEncoding           = 
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME,
         .ResolutionsListCount             = 1,
         .pResolutionList                  = &ctx->resolution,

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to