aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/nvenc.c
diff options
context:
space:
mode:
authorTimo Rothenpieler <timo@rothenpieler.org>2023-06-16 21:35:45 +0200
committerTimo Rothenpieler <timo@rothenpieler.org>2023-06-16 22:10:42 +0200
commit16fdb48e0dead244bddf3a0ae9d459d02b4443b1 (patch)
tree4753cd95dd72607e766dc4b2866e10575d8dcd56 /libavcodec/nvenc.c
parent6c418ae25ede55fa1f896a7449ebaffd18886002 (diff)
downloadffmpeg-16fdb48e0dead244bddf3a0ae9d459d02b4443b1.tar.gz
avcodec/nvenc: handle frame durations and AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE
Diffstat (limited to 'libavcodec/nvenc.c')
-rw-r--r--libavcodec/nvenc.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index 177e23d7e4..d56ebc68e2 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -971,6 +971,10 @@ static av_cold int nvenc_recalc_surfaces(AVCodecContext *avctx)
ctx->nb_surfaces = FFMAX(1, FFMIN(MAX_REGISTERED_FRAMES, ctx->nb_surfaces));
ctx->async_depth = FFMIN(ctx->async_depth, ctx->nb_surfaces - 1);
+ // Output in the worst case will only start when the surface buffer is completely full.
+ // Hence we need to keep at least the max amount of surfaces plus the max reorder delay around.
+ ctx->frame_data_array_nb = ctx->nb_surfaces + ctx->encode_config.frameIntervalP - 1;
+
return 0;
}
@@ -1767,6 +1771,10 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx)
if (!ctx->surfaces)
return AVERROR(ENOMEM);
+ ctx->frame_data_array = av_calloc(ctx->frame_data_array_nb, sizeof(*ctx->frame_data_array));
+ if (!ctx->frame_data_array)
+ return AVERROR(ENOMEM);
+
ctx->timestamp_list = av_fifo_alloc2(ctx->nb_surfaces, sizeof(int64_t), 0);
if (!ctx->timestamp_list)
return AVERROR(ENOMEM);
@@ -1857,6 +1865,12 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
av_fifo_freep2(&ctx->output_surface_queue);
av_fifo_freep2(&ctx->unused_surface_queue);
+ if (ctx->frame_data_array) {
+ for (i = 0; i < ctx->nb_surfaces; i++)
+ av_buffer_unref(&ctx->frame_data_array[i].frame_opaque_ref);
+ av_freep(&ctx->frame_data_array);
+ }
+
if (ctx->surfaces && (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11)) {
for (i = 0; i < ctx->nb_registered_frames; i++) {
if (ctx->registered_frames[i].mapped)
@@ -2233,6 +2247,65 @@ FF_ENABLE_DEPRECATION_WARNINGS
return 0;
}
+static int nvenc_store_frame_data(AVCodecContext *avctx, NV_ENC_PIC_PARAMS *pic_params, const AVFrame *frame)
+{
+ NvencContext *ctx = avctx->priv_data;
+ int res = 0;
+
+ int idx = ctx->frame_data_array_pos;
+ NvencFrameData *frame_data = &ctx->frame_data_array[idx];
+
+ // in case the encoder got reconfigured, there might be leftovers
+ av_buffer_unref(&frame_data->frame_opaque_ref);
+
+ if (frame && frame->opaque_ref && avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
+ frame_data->frame_opaque_ref = av_buffer_ref(frame->opaque_ref);
+ if (!frame_data->frame_opaque_ref)
+ return AVERROR(ENOMEM);
+ }
+
+ frame_data->duration = frame->duration;
+ frame_data->frame_opaque = frame->opaque;
+
+#if FF_API_REORDERED_OPAQUE
+FF_DISABLE_DEPRECATION_WARNINGS
+ frame_data->reordered_opaque = frame->reordered_opaque;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+ ctx->frame_data_array_pos = (ctx->frame_data_array_pos + 1) % ctx->frame_data_array_nb;
+ pic_params->inputDuration = idx;
+
+ return res;
+}
+
+static int nvenc_retrieve_frame_data(AVCodecContext *avctx, NV_ENC_LOCK_BITSTREAM *lock_params, AVPacket *pkt)
+{
+ NvencContext *ctx = avctx->priv_data;
+ int res = 0;
+
+ int idx = lock_params->outputDuration;
+ NvencFrameData *frame_data = &ctx->frame_data_array[idx];
+
+ pkt->duration = frame_data->duration;
+
+#if FF_API_REORDERED_OPAQUE
+FF_DISABLE_DEPRECATION_WARNINGS
+ avctx->reordered_opaque = frame_data->reordered_opaque;
+FF_ENABLE_DEPRECATION_WARNINGS
+#endif
+
+ if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
+ pkt->opaque = frame_data->frame_opaque;
+ pkt->opaque_ref = frame_data->frame_opaque_ref;
+ frame_data->frame_opaque_ref = NULL;
+ }
+
+ av_buffer_unref(&frame_data->frame_opaque_ref);
+
+ return res;
+}
+
static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSurface *tmpoutsurf)
{
NvencContext *ctx = avctx->priv_data;
@@ -2319,6 +2392,10 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
if (res < 0)
goto error2;
+ res = nvenc_retrieve_frame_data(avctx, &lock_params, pkt);
+ if (res < 0)
+ goto error2;
+
return 0;
error:
@@ -2614,6 +2691,10 @@ static int nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
sei_count = res;
}
+ res = nvenc_store_frame_data(avctx, &pic_params, frame);
+ if (res < 0)
+ return res;
+
nvenc_codec_specific_pic_params(avctx, &pic_params, ctx->sei_data, sei_count);
} else {
pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;