PR #24032 opened by Steven Xiao (younengxiao)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24032
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24032.patch

This commit adds AV1 B-frame support.
    - Enable B-frame scheduling for the D3D12VA AV1 encoder by setting the 
ref_l0/ref_l1 capability.
    - Stash hidden (non-independent) anchor frames coded data and prepend it to 
the next visible frame packet (show_existing_frame handling).
    - Add FF_HW_FLAG_TIMESTAMP_NO_DELAY to avoiding non-monotonic DTS warnings 
at higher B-frame reorder depths.
    - Set 2 B-frames as default(align with D3D12VA H.264 and HEVC encoder)

Example usage:
    - default (2 B-frames will be applied):
              ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.mp4 
-c:v av1_d3d12va output.mp4
    - 3 B-frames:
              ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.mp4 
-c:v av1_d3d12va -bf 3 output.mp4



From 2730cf27f0338ede0149f465160c653940ea7f85 Mon Sep 17 00:00:00 2001
From: younengxiao <[email protected]>
Date: Thu, 16 Jul 2026 15:13:31 -0400
Subject: [PATCH] avcodec/d3d12va_encode_av1: add AV1 B-frame (compound
 prediction) support

This commit adds AV1 B-frame support.
    - Enable B-frame scheduling for the D3D12VA AV1 encoder by setting the
      ref_l0/ref_l1 capability.
    - Stash hidden (non-independent) anchor frames coded data and prepend
      it to the next visible frame packet (show_existing_frame handling).
    - Add FF_HW_FLAG_TIMESTAMP_NO_DELAY to avoiding non-monotonic DTS warnings
      at higher B-frame reorder depths.
    - Set 2 B-frames as default(align with D3D12VA H.264 and HEVC encoder)

Example usage:
    - default (2 B-frames will be applied):
      ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.mp4 -c:v 
av1_d3d12va output.mp4
    - 3 B-frames:
      ffmpeg -hwaccel d3d12va -hwaccel_output_format d3d12 -i input.mp4 -c:v 
av1_d3d12va -bf 3 output.mp4

Signed-off-by: younengxiao <[email protected]>
---
 libavcodec/d3d12va_encode.c     |  30 ++++-
 libavcodec/d3d12va_encode.h     |   5 +
 libavcodec/d3d12va_encode_av1.c | 194 ++++++++++++++++++++++++++------
 libavcodec/hw_base_encode.h     |   3 +
 4 files changed, 192 insertions(+), 40 deletions(-)

diff --git a/libavcodec/d3d12va_encode.c b/libavcodec/d3d12va_encode.c
index 442dbc6a4a..4151c554ee 100644
--- a/libavcodec/d3d12va_encode.c
+++ b/libavcodec/d3d12va_encode.c
@@ -911,13 +911,31 @@ static int d3d12va_encode_output(AVCodecContext *avctx,
     if (err < 0)
         return err;
 
+    if (pic->non_independent_frame) {
+        if (pic->tail_size) {
+            if (base_ctx->tail_pkt->size) {
+                err = AVERROR_BUG;
+                goto end;
+            }
+            err = ff_get_encode_buffer(avctx, base_ctx->tail_pkt, 
pic->tail_size, 0);
+            if (err < 0)
+                goto end;
+            memcpy(base_ctx->tail_pkt->data, pic->tail_data, pic->tail_size);
+            pkt_ptr = base_ctx->tail_pkt;
+        }
+    }
+
     av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
            base_pic->display_order, base_pic->encode_order);
 
+    /* FF_HW_FLAG_TIMESTAMP_NO_DELAY: DTS = PTS for codecs whose output is
+     * already in display order (e.g. AV1 with show_existing_frame). */
     ff_hw_base_encode_set_output_property(base_ctx, avctx, 
(FFHWBaseEncodePicture *)base_pic,
-                                          pkt_ptr, 0);
+                                          pkt_ptr,
+                                          ctx->codec->flags & 
FF_HW_FLAG_TIMESTAMP_NO_DELAY);
 
-    return 0;
+end:
+    return err;
 }
 
 static int d3d12va_encode_set_profile(AVCodecContext *avctx)
@@ -1350,8 +1368,12 @@ static int 
d3d12va_encode_init_gop_structure(AVCodecContext *avctx)
 #if CONFIG_AV1_D3D12VA_ENCODER
             case D3D12_VIDEO_ENCODER_CODEC_AV1:
                 ref_l0 = 
support.PictureSupport.pAV1Support->MaxUniqueReferencesPerFrame;
-                // AV1 doesn't use traditional L1 references like H.264/HEVC
-                ref_l1 = 0;
+                if (support.PictureSupport.pAV1Support->PredictionMode ==
+                    
D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_COMPOUND_REFERENCE ||
+                    ref_l0 >= 2)
+                    ref_l1 = 1;
+                else
+                    ref_l1 = 0;
                 break;
 #endif
             default:
diff --git a/libavcodec/d3d12va_encode.h b/libavcodec/d3d12va_encode.h
index f2e97da7d2..bfc5dd5578 100644
--- a/libavcodec/d3d12va_encode.h
+++ b/libavcodec/d3d12va_encode.h
@@ -61,6 +61,11 @@ typedef struct D3D12VAEncodePicture {
     // ROI delta QP map (void* to support both INT8 for H.264/HEVC and INT16 
for AV1)
     void           *qp_map;
     int             qp_map_size;
+
+    // Hidden-frame (AV1 show_existing_frame) support
+    int             non_independent_frame;
+    char            tail_data[MAX_PARAM_BUFFER_SIZE];
+    size_t          tail_size;
 } D3D12VAEncodePicture;
 
 typedef struct D3D12VAEncodeProfile {
diff --git a/libavcodec/d3d12va_encode_av1.c b/libavcodec/d3d12va_encode_av1.c
index 89b727ca33..6165eceafd 100644
--- a/libavcodec/d3d12va_encode_av1.c
+++ b/libavcodec/d3d12va_encode_av1.c
@@ -104,6 +104,7 @@ typedef struct D3D12VAEncodeAV1Context {
 
     uint8_t q_idx_idr;
     uint8_t   q_idx_p;
+    uint8_t   q_idx_b;
 
     // Writer structures.
     D3D12VAHWBaseEncodeAV1         units;
@@ -123,6 +124,10 @@ typedef struct D3D12VAEncodeAV1Context {
     uint16_t context_update_tile_id;
     uint8_t    width_in_sbs_minus_1[AV1_MAX_TILE_COLS];
     uint8_t   height_in_sbs_minus_1[AV1_MAX_TILE_ROWS];
+
+    // Stash for hidden (non-independent) anchor frame coded bytes
+    uint8_t *stash_data;
+    size_t   stash_size;
 } D3D12VAEncodeAV1Context;
 
 typedef struct D3D12VAEncodeAV1Level {
@@ -325,17 +330,29 @@ static int 
d3d12va_encode_av1_write_picture_header(AVCodecContext *avctx,
                                                    char *data, size_t 
*data_len)
 {
     D3D12VAEncodeAV1Context *priv = avctx->priv_data;
+    D3D12VAEncodeContext     *ctx = avctx->priv_data;
+    CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
     CodedBitstreamFragment  *obu  = &priv->current_obu;
     AV1RawOBU    *frameheader_obu = av_mallocz(sizeof(AV1RawOBU));
+    int                 show_slot = 0;
     int                       err = 0;
 
+    if (!frameheader_obu)
+        return AVERROR(ENOMEM);
+
     av_fifo_read(priv->picture_header_list, frameheader_obu, 1);
     err = d3d12va_encode_av1_update_current_frame_picture_header(avctx, 
pic,frameheader_obu);
     if (err < 0) {
         av_log(avctx, AV_LOG_ERROR, "Failed to update current frame picture 
header: %d.\n", err);
+        av_freep(&frameheader_obu);
         return err;
     }
 
+    // The DPB slot this frame refreshes (single bit for anchor P frames)
+    if (frameheader_obu->obu.frame_header.refresh_frame_flags) {
+        show_slot = 
ff_ctz(frameheader_obu->obu.frame_header.refresh_frame_flags);
+    }
+
     // Add the frame header OBU
     frameheader_obu->header.obu_has_size_field = 1;
 
@@ -343,6 +360,38 @@ static int 
d3d12va_encode_av1_write_picture_header(AVCodecContext *avctx,
     if (err < 0)
         goto fail;
     err = d3d12va_encode_av1_write_obu(avctx, data, data_len, obu);
+    if (err < 0)
+        goto fail;
+
+    // For hidden anchor frames, build the show_existing_frame tail OBU now
+    pic->tail_size = 0;
+    if (pic->non_independent_frame) {
+        AV1RawOBU rep_obu = { 0 };
+        AV1RawFrameHeader *rep_fh = &rep_obu.obu.frame_header;
+        size_t tail_bit_len = 0;
+
+        ff_cbs_fragment_reset(obu);
+
+        rep_obu.header.obu_type           = AV1_OBU_FRAME_HEADER;
+        rep_obu.header.obu_has_size_field = 1;
+        rep_fh->show_existing_frame       = 1;
+        rep_fh->frame_to_show_map_idx     = show_slot;
+        rep_fh->frame_type                = AV1_FRAME_INTER;
+        rep_fh->frame_width_minus_1       = ctx->resolution.Width - 1;
+        rep_fh->frame_height_minus_1      = ctx->resolution.Height - 1;
+        rep_fh->render_width_minus_1      = rep_fh->frame_width_minus_1;
+        rep_fh->render_height_minus_1     = rep_fh->frame_height_minus_1;
+
+        cbctx->seen_frame_header = 0;
+
+        err = d3d12va_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, 
&rep_obu);
+        if (err < 0)
+            goto fail;
+        err = d3d12va_encode_av1_write_obu(avctx, pic->tail_data, 
&tail_bit_len, obu);
+        if (err < 0)
+            goto fail;
+        pic->tail_size = tail_bit_len / 8;
+    }
 
 fail:
     ff_cbs_fragment_reset(obu);
@@ -460,6 +509,7 @@ static int d3d12va_encode_av1_get_coded_data(AVCodecContext 
*avctx,
     size_t   obu_size             = 0;
     size_t   tile_payload_size    = 0;
     size_t   total_size           = 0;
+    size_t   prev_stash_sz        = 0;
     uint64_t nb_subregions        = 0;
     int      output_buffer_mapped = 0;
 
@@ -525,10 +575,34 @@ static int 
d3d12va_encode_av1_get_coded_data(AVCodecContext *avctx,
     obu_size = bit_len / 8;
 
     total_size = pic->header_size + av1_pic_hd_size + obu_size;
-    err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
-    if (err < 0)
-        goto end;
-    ptr = pkt->data;
+
+    /*
+     * Hidden anchor frame: stash its coded bytes so they will be prepended
+     * to the next visible frame's packet. Visible frame: allocate a packet
+     * large enough for any stashed hidden frame bytes followed by this
+     * frame's coded data.
+     */
+    if (pic->non_independent_frame) {
+        uint8_t *new_stash = av_realloc(priv->stash_data,
+                                        priv->stash_size + total_size);
+        if (!new_stash) {
+            err = AVERROR(ENOMEM);
+            goto end;
+        }
+        priv->stash_data = new_stash;
+        ptr = priv->stash_data + priv->stash_size;
+    } else {
+        prev_stash_sz = priv->stash_size;
+        err = ff_get_encode_buffer(avctx, pkt, prev_stash_sz + total_size, 0);
+        if (err < 0)
+            goto end;
+        if (prev_stash_sz) {
+            memcpy(pkt->data, priv->stash_data, prev_stash_sz);
+            av_freep(&priv->stash_data);
+            priv->stash_size = 0;
+        }
+        ptr = pkt->data + prev_stash_sz;
+    }
 
     memcpy(ptr, mapped_data, pic->header_size);
     ptr += pic->header_size;
@@ -538,6 +612,9 @@ static int d3d12va_encode_av1_get_coded_data(AVCodecContext 
*avctx,
 
     memcpy(ptr, obu_buf, obu_size);
 
+    if (pic->non_independent_frame)
+        priv->stash_size += total_size;
+
     av_log(avctx, AV_LOG_DEBUG, "AV1 packet: %"PRIu64" tiles, header %d, "
            "pic header %zu, tile group %zu, total %zu bytes.\n",
            nb_subregions, pic->header_size, av1_pic_hd_size, obu_size, 
total_size);
@@ -734,8 +811,8 @@ static int 
d3d12va_encode_av1_init_sequence_params(AVCodecContext *avctx)
 
     seq->max_frame_width_minus_1 = ctx->resolution.Width - 1;
     seq->max_frame_height_minus_1 = ctx->resolution.Height - 1;
-    seq->frame_width_bits_minus_1 = av_log2(ctx->resolution.Width);
-    seq->frame_height_bits_minus_1 = av_log2(ctx->resolution.Height);
+    seq->frame_width_bits_minus_1 = av_log2(ctx->resolution.Width - 1);
+    seq->frame_height_bits_minus_1 = av_log2(ctx->resolution.Height - 1);
 
     seqheader_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER;
 
@@ -1037,6 +1114,7 @@ static int d3d12va_encode_av1_configure(AVCodecContext 
*avctx)
 
     if (ctx->rc.Mode == D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP) {
         D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP *cqp_ctl;
+        int fixed_qp_b;
         fixed_qp_inter = av_clip_uintp2(ctx->rc_quality, 8);
 
         if (avctx->i_quant_factor > 0.0)
@@ -1045,9 +1123,15 @@ static int d3d12va_encode_av1_configure(AVCodecContext 
*avctx)
         else
             fixed_qp_key = fixed_qp_inter;
 
+        if (avctx->b_quant_factor > 0.0)
+            fixed_qp_b = av_clip_uintp2((avctx->b_quant_factor * 
fixed_qp_inter +
+                                  avctx->b_quant_offset) + 0.5, 8);
+        else
+            fixed_qp_b = fixed_qp_inter;
+
         av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = "
-               "%d / %d for Key / Inter frames.\n",
-               fixed_qp_key, fixed_qp_inter);
+               "%d / %d / %d for Key / Inter / B frames.\n",
+               fixed_qp_key, fixed_qp_inter, fixed_qp_b);
 
         ctx->rc.ConfigParams.DataSize = 
sizeof(D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP);
         cqp_ctl = av_mallocz(ctx->rc.ConfigParams.DataSize);
@@ -1056,12 +1140,13 @@ static int d3d12va_encode_av1_configure(AVCodecContext 
*avctx)
 
         cqp_ctl->ConstantQP_FullIntracodedFrame                  = 
fixed_qp_key;
         cqp_ctl->ConstantQP_InterPredictedFrame_PrevRefOnly      = 
fixed_qp_inter;
-        cqp_ctl->ConstantQP_InterPredictedFrame_BiDirectionalRef = 
fixed_qp_inter;
+        cqp_ctl->ConstantQP_InterPredictedFrame_BiDirectionalRef = fixed_qp_b;
 
         ctx->rc.ConfigParams.pConfiguration_CQP = cqp_ctl;
 
         priv->q_idx_idr = fixed_qp_key;
         priv->q_idx_p   = fixed_qp_inter;
+        priv->q_idx_b   = fixed_qp_b;
 
     }
 
@@ -1148,8 +1233,8 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
     AV1RawFrameHeader                       *fh = 
&frameheader_obu->obu.frame_header;
 
     FFHWBaseEncodePicture *ref;
-    D3D12VAEncodeAV1Picture *href;
-    int i;
+    D3D12VAEncodeAV1Picture *href, *href_l0, *href_l1;
+    int i, phys;
 
     static const int8_t 
default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] =
         { 1, 0, 0, 0, -1, 0, -1, -1 };
@@ -1163,6 +1248,11 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
     if (!d3d12va_pic->pic_ctl.pAV1PicData)
         return AVERROR(ENOMEM);
 
+    for (i = 0; i < AV1_NUM_REF_FRAMES; i++) {
+        
d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i]
+            .ReconstructedPictureResourceIndex = 
D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX;
+    }
+
     // Initialize frame type and reference frame management
     switch(pic->type) {
         case FF_HW_PICTURE_TYPE_IDR:
@@ -1172,6 +1262,8 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
             hpic->slot = 0;
             hpic->last_idr_frame = pic->display_order;
             fh->tx_mode = AV1_TX_MODE_LARGEST;
+            d3d12va_pic->pic_ctl.pAV1PicData->CompoundPredictionType =
+                D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_SINGLE_REFERENCE;
             break;
 
         case FF_HW_PICTURE_TYPE_P:
@@ -1182,6 +1274,9 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
             ref = pic->refs[0][pic->nb_refs[0] - 1];
             href = ref->codec_priv;
 
+            d3d12va_pic->pic_ctl.pAV1PicData->CompoundPredictionType =
+                D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_SINGLE_REFERENCE;
+
             /**
              * The encoder uses a simple alternating reference frame strategy:
              * - For P-frames, it uses the last reconstructed frame as a 
reference.
@@ -1212,18 +1307,58 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
                 fh->ref_frame_idx[3] = href->slot;
                 fh->ref_order_hint[href->slot] = ref->display_order - 
href->last_idr_frame;
             } else if (base_ctx->ref_l0 == 1) {
+                // Keep the other slot's order hint consistent
+                href = pic->refs[0][0]->codec_priv;
                 fh->ref_order_hint[!href->slot] = 
cbctx->ref[!href->slot].order_hint;
             }
             break;
 
         case FF_HW_PICTURE_TYPE_B:
-            av_log(avctx, AV_LOG_ERROR, "D3D12 AV1 video encode on this device 
requires B-frame support, "
-                "but it's not implemented.\n");
-            return AVERROR_PATCHWELCOME;
+            fh->frame_type          = AV1_FRAME_INTER;
+            fh->base_q_idx          = priv->q_idx_b;
+            fh->tx_mode             = AV1_TX_MODE_SELECT;
+            fh->refresh_frame_flags = 0x0;   // B-frames don't refresh any DPB 
slot
+            fh->reference_select    = 1;     // compound prediction
+
+            d3d12va_pic->pic_ctl.pAV1PicData->CompoundPredictionType =
+                
D3D12_VIDEO_ENCODER_AV1_COMP_PREDICTION_TYPE_COMPOUND_REFERENCE;
+
+            assert(pic->nb_refs[0] >= 1 && pic->nb_refs[1] >= 1);
+
+            // L0 reference (LAST = previous anchor)
+            ref     = pic->refs[0][pic->nb_refs[0] - 1];
+            href_l0 = ref->codec_priv;
+            hpic->last_idr_frame              = href_l0->last_idr_frame;
+            fh->primary_ref_frame             = href_l0->slot;
+            fh->ref_order_hint[href_l0->slot] = ref->display_order - 
href_l0->last_idr_frame;
+
+            // LAST, LAST2, LAST3, GOLDEN → L0 slot
+            for (i = 0; i < AV1_REF_FRAME_GOLDEN; i++)
+                fh->ref_frame_idx[i] = href_l0->slot;
+
+            // L1 reference (BWDREF = future anchor)
+            ref     = pic->refs[1][pic->nb_refs[1] - 1];
+            href_l1 = ref->codec_priv;
+            fh->ref_order_hint[href_l1->slot] = ref->display_order - 
href_l1->last_idr_frame;
+
+            // BWDREF, ALTREF2, ALTREF → L1 slot
+            for (i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++)
+                fh->ref_frame_idx[i] = href_l1->slot;
+            break;
+
         default:
             av_log(avctx, AV_LOG_ERROR, "Unsupported picture type %d.\n", 
pic->type);
+            return AVERROR(EINVAL);
     }
 
+    // Assign ppTexture2Ds indices in list order (L0 first, then L1).
+    for (phys = 0, i = 0; i < 2; i++) {
+        for (int j = 0; j < pic->nb_refs[i]; j++) {
+            D3D12VAEncodeAV1Picture *hr = pic->refs[i][j]->codec_priv;
+            
d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[hr->slot]
+                .ReconstructedPictureResourceIndex = phys++;
+        }
+    }
 
     cbctx->seen_frame_header = 0;
 
@@ -1264,30 +1399,14 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
     d3d12va_pic->pic_ctl.pAV1PicData->TemporalLayerIndexPlus1 = 
hpic->temporal_id + 1;
     d3d12va_pic->pic_ctl.pAV1PicData->SpatialLayerIndexPlus1 = 
hpic->spatial_id + 1;
     d3d12va_pic->pic_ctl.pAV1PicData->PictureIndex = pic->display_order;
+    d3d12va_pic->pic_ctl.pAV1PicData->OrderHint = fh->order_hint;
     d3d12va_pic->pic_ctl.pAV1PicData->InterpolationFilter = 
D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE;
     d3d12va_pic->pic_ctl.pAV1PicData->PrimaryRefFrame = fh->primary_ref_frame;
     if (fh->error_resilient_mode)
         d3d12va_pic->pic_ctl.pAV1PicData->Flags |= 
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_FLAG_ENABLE_ERROR_RESILIENT_MODE;
 
-    if (pic->type == FF_HW_PICTURE_TYPE_IDR)
-    {
-        for (int i = 0; i < AV1_NUM_REF_FRAMES; i++) {
-            
d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex
 =
-            D3D12_VIDEO_ENCODER_AV1_INVALID_DPB_RESOURCE_INDEX;
-        }
-    } else if (pic->type == FF_HW_PICTURE_TYPE_P) {
-        for (i = 0; i < pic->nb_refs[0]; i++) {
-            FFHWBaseEncodePicture *ref_pic = pic->refs[0][i];
-            
d3d12va_pic->pic_ctl.pAV1PicData->ReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex
 =
-            ((D3D12VAEncodeAV1Picture*)ref_pic->codec_priv)->slot;
-        }
-    }
-    // Set reference frame management
-    memset(d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices, 0, sizeof(UINT) 
* AV1_REFS_PER_FRAME);
-    if (pic->type == FF_HW_PICTURE_TYPE_P) {
-        for (i = 0; i < AV1_REFS_PER_FRAME; i++)
-            d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices[i] = 
fh->ref_frame_idx[i];
-    }
+    for (i = 0; i < AV1_REFS_PER_FRAME; i++)
+        d3d12va_pic->pic_ctl.pAV1PicData->ReferenceIndices[i] = 
fh->ref_frame_idx[i];
 
     // Process ROI side data if present and supported
     if (base_ctx->roi_allowed && d3d12va_pic->qp_map && 
d3d12va_pic->qp_map_size > 0) {
@@ -1295,6 +1414,8 @@ static int 
d3d12va_encode_av1_init_picture_params(AVCodecContext *avctx,
         d3d12va_pic->pic_ctl.pAV1PicData->pRateControlQPMap = (INT16 
*)d3d12va_pic->qp_map;
     }
 
+    d3d12va_pic->non_independent_frame = (pic->display_order > 
pic->encode_order);
+
     return av_fifo_write(priv->picture_header_list, 
&priv->units.raw_frame_header, 1);
 }
 
@@ -1305,8 +1426,8 @@ static const D3D12VAEncodeType d3d12va_encode_type_av1 = {
     .d3d12_codec            = D3D12_VIDEO_ENCODER_CODEC_AV1,
 
     .flags                  = FF_HW_FLAG_B_PICTURES |
-                              FF_HW_FLAG_B_PICTURE_REFERENCES |
-                              FF_HW_FLAG_NON_IDR_KEY_PICTURES,
+                              FF_HW_FLAG_NON_IDR_KEY_PICTURES |
+                              FF_HW_FLAG_TIMESTAMP_NO_DELAY,
 
     .default_quality        = 25,
 
@@ -1372,6 +1493,7 @@ static int d3d12va_encode_av1_close(AVCodecContext *avctx)
     av_freep(&priv->common.subregions_layout.pTilesPartition_AV1);
 
     av_fifo_freep2(&priv->picture_header_list);
+    av_freep(&priv->stash_data);
 
     return ff_d3d12va_encode_close(avctx);
 }
@@ -1446,7 +1568,7 @@ static const AVOption d3d12va_encode_av1_options[] = {
 
 static const FFCodecDefault d3d12va_encode_av1_defaults[] = {
     { "b",              "0"   },
-    { "bf",             "0"   },
+    { "bf",             "2"   },
     { "g",              "120" },
     { "i_qfactor",      "1"   },
     { "i_qoffset",      "0"   },
diff --git a/libavcodec/hw_base_encode.h b/libavcodec/hw_base_encode.h
index e768579722..e026679c1d 100644
--- a/libavcodec/hw_base_encode.h
+++ b/libavcodec/hw_base_encode.h
@@ -56,6 +56,9 @@ enum {
     // Codec supports non-IDR key pictures (that is, key pictures do
     // not necessarily empty the DPB).
     FF_HW_FLAG_NON_IDR_KEY_PICTURES  = 1 << 5,
+    // Output is in display order; set DTS = PTS on every packet
+    // (e.g. AV1 hidden anchor frames with show_existing_frame).
+    FF_HW_FLAG_TIMESTAMP_NO_DELAY    = 1 << 6,
 };
 
 typedef struct FFHWBaseEncodePicture {
-- 
2.52.0

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

Reply via email to