[PR] avcodec/d3d12va_encode_av1: add AV1 B-frame (compound prediction) support (PR #24032)

Steven Xiao via ffmpeg-devel <[email protected]>
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178602835235.59.293924295157698331@29965ddac10e>
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]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.