diff --git a/libavcodec/vulkan_encode.c b/libavcodec/vulkan_encode.c index e5c0496f1c..7b534ffa30 100644 --- a/libavcodec/vulkan_encode.c +++ b/libavcodec/vulkan_encode.c @@ -464,6 +464,9 @@ static int vulkan_encode_output(AVCodecContext *avctx, VkResult ret; FFVulkanEncodePicture *vp = base_pic->priv; FFVulkanEncodeContext *ctx = avctx->priv_data; + FFHWBaseEncodeContext *base_ctx = &ctx->base; + AVPacket *pkt_ptr = pkt; + FFVkBuffer *sd_buf = (FFVkBuffer *)vp->pkt_buf->data; uint32_t *query_data; @@ -513,20 +516,56 @@ static int vulkan_encode_output(AVCodecContext *avctx, vk->FlushMappedMemoryRanges(ctx->s.hwctx->act_dev, 1, &invalidate_buf); } - pkt->data = sd_buf->mapped_mem; - pkt->size = vp->slices_offset + /* base offset */ - query_data[0] /* secondary offset */ + - query_data[1] /* size */; + if (vp->non_independent_frame) { + av_assert0(!ctx->prev_buf_ref); + size_t prev_buf_size = vp->slices_offset + query_data[0] + query_data[1]; + ctx->prev_buf_ref = vp->pkt_buf; + ctx->prev_buf_size = prev_buf_size; + vp->pkt_buf = NULL; - /* Move reference */ - pkt->buf = vp->pkt_buf; - vp->pkt_buf = NULL; + if (vp->tail_size) { + if (base_ctx->tail_pkt->size) + return AVERROR_BUG; + + ret = ff_get_encode_buffer(avctx, base_ctx->tail_pkt, vp->tail_size, 0); + if (ret < 0) + return ret; + + memcpy(base_ctx->tail_pkt->data, vp->tail_data, vp->tail_size); + pkt_ptr = base_ctx->tail_pkt; + } + } else { + if (ctx->prev_buf_ref) { + FFVkBuffer *prev_sd_buf = (FFVkBuffer *)ctx->prev_buf_ref->data; + size_t prev_size = ctx->prev_buf_size; + size_t size = (vp->slices_offset + query_data[0] + query_data[1]); + + ret = ff_get_encode_buffer(avctx, pkt, prev_size + size, 0); + if (ret < 0) + return ret; + + memcpy(pkt->data, prev_sd_buf->mapped_mem, prev_size); + memcpy(pkt->data + prev_size, sd_buf->mapped_mem, size); + + av_buffer_unref(&ctx->prev_buf_ref); + av_buffer_unref(&vp->pkt_buf); + } else { + pkt->data = sd_buf->mapped_mem; + pkt->size = vp->slices_offset + /* base offset */ + query_data[0] /* secondary offset */ + + query_data[1] /* size */; + + /* Move reference */ + pkt->buf = vp->pkt_buf; + vp->pkt_buf = NULL; + } + } av_log(avctx, AV_LOG_DEBUG, "Frame %"PRId64"/%"PRId64 " encoded\n", base_pic->display_order, base_pic->encode_order); return ff_hw_base_encode_set_output_property(&ctx->base, avctx, - base_pic, pkt, + base_pic, pkt_ptr, ctx->codec->flags & VK_ENC_FLAG_NO_DELAY); } diff --git a/libavcodec/vulkan_encode.h b/libavcodec/vulkan_encode.h index 3df06e11d0..cf5f255628 100644 --- a/libavcodec/vulkan_encode.h +++ b/libavcodec/vulkan_encode.h @@ -57,6 +57,10 @@ typedef struct FFVulkanEncodePicture { FFVkExecContext *exec; AVBufferRef *pkt_buf; int slices_offset; + + int non_independent_frame; + char tail_data[16]; + size_t tail_size; } FFVulkanEncodePicture; /** @@ -192,6 +196,9 @@ typedef struct FFVulkanEncodeContext { FFVkExecPool enc_pool; FFHWBaseEncodePicture *slots[32]; + + AVBufferRef *prev_buf_ref; + size_t prev_buf_size; } FFVulkanEncodeContext; #define VULKAN_ENCODE_COMMON_OPTIONS \ diff --git a/libavcodec/vulkan_encode_av1.c b/libavcodec/vulkan_encode_av1.c index 1f26b37316..42ba30b302 100644 --- a/libavcodec/vulkan_encode_av1.c +++ b/libavcodec/vulkan_encode_av1.c @@ -80,6 +80,8 @@ typedef struct VulkanEncodeAV1Context { AV1RawOBU seq_hdr_obu; AV1RawOBU meta_cll_obu; AV1RawOBU meta_mastering_obu; + AV1RawOBU hidden_obu; + AV1RawOBU tail_obu; VkVideoEncodeAV1ProfileInfoKHR profile; @@ -172,7 +174,6 @@ static void set_name_slot(int slot, int *slot_indices, uint32_t allowed_idx, int av_assert0(0); } - static int init_pic_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, VkVideoEncodeInfoKHR *encode_info) { @@ -542,6 +543,45 @@ static int init_pic_params(AVCodecContext *avctx, FFHWBaseEncodePicture *pic, } } + FFVulkanEncodePicture *vp = pic->priv; + vp->tail_size = 0; + vp->non_independent_frame = pic->encode_order < pic->display_order; + if (vp->non_independent_frame) { + AV1RawOBU *obu = &enc->hidden_obu; + AV1RawFrameHeader *fh = &obu->obu.frame_header; + + /** hidden frame header */ + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_FRAME_HEADER; + obu->header.obu_has_size_field = 1; + + fh->frame_type = AV1_FRAME_INTER; + fh->refresh_frame_flags = 1 << ap->slot; + fh->frame_width_minus_1 = base_ctx->surface_width - 1; + fh->frame_height_minus_1 = base_ctx->surface_height - 1; + fh->render_width_minus_1 = fh->frame_width_minus_1; + fh->render_height_minus_1 = fh->frame_height_minus_1; + + memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas, + AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t)); + + obu = &enc->tail_obu; + fh = &obu->obu.frame_header; + + /** tail frame header */ + memset(obu, 0, sizeof(*obu)); + obu->header.obu_type = AV1_OBU_FRAME_HEADER; + obu->header.obu_has_size_field = 1; + + fh->show_existing_frame = 1; + fh->frame_to_show_map_idx = ap->slot != 0; + fh->frame_type = AV1_FRAME_INTER; + fh->frame_width_minus_1 = base_ctx->surface_width - 1; + fh->frame_height_minus_1 = base_ctx->surface_height - 1; + fh->render_width_minus_1 = fh->frame_width_minus_1; + fh->render_height_minus_1 = fh->frame_height_minus_1; + } + return 0; } @@ -1079,8 +1119,31 @@ static int write_extra_headers(AVCodecContext *avctx, int err; VulkanEncodeAV1Context *enc = avctx->priv_data; VulkanEncodeAV1Picture *ap = base_pic->codec_priv; + FFVulkanEncodePicture *vp = base_pic->priv; CodedBitstreamFragment *obu = &enc->current_access_unit; + if (vp->non_independent_frame) { + err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &enc->hidden_obu); + if (err < 0) + goto fail; + + // Only for tracking ref frame in context, not to be output + err = ff_cbs_write_fragment_data(enc->cbs, obu); + if (err < 0) + goto fail; + + ff_cbs_fragment_reset(obu); + ((CodedBitstreamAV1Context *)enc->cbs->priv_data)->seen_frame_header = 0; + + err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &enc->tail_obu); + if (err < 0) + goto fail; + + err = vulkan_encode_av1_write_obu(avctx, vp->tail_data, &vp->tail_size, obu); + if (err < 0) + goto fail; + } + if (ap->units_needed & UNIT_MASTERING_DISPLAY) { err = vulkan_encode_av1_add_obu(avctx, obu, AV1_OBU_METADATA,