[FFmpeg-cvslog] avcodec/nvenc: handle frame durations and AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE

Timo Rothenpieler git at videolan.org
Fri Jun 16 23:48:41 EEST 2023


ffmpeg | branch: release/6.0 | Timo Rothenpieler <timo at rothenpieler.org> | Fri Jun 16 21:35:45 2023 +0200| [868af7d7a406b13648c7dff9fc8c4a7221e86849] | committer: Timo Rothenpieler

avcodec/nvenc: handle frame durations and AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=868af7d7a406b13648c7dff9fc8c4a7221e86849
---

 libavcodec/nvenc.c      | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/nvenc.h      | 17 +++++++++++
 libavcodec/nvenc_av1.c  |  3 +-
 libavcodec/nvenc_h264.c |  3 +-
 libavcodec/nvenc_hevc.c |  3 +-
 5 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index aa9cd81485..15dd819a58 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -962,6 +962,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;
 }
 
@@ -1750,6 +1754,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);
@@ -1840,6 +1848,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)
@@ -2211,6 +2225,65 @@ static int nvenc_set_timestamp(AVCodecContext *avctx,
     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;
@@ -2297,6 +2370,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:
@@ -2592,6 +2669,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;
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index 05a7ac48b1..6cedd5bc27 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -31,6 +31,7 @@ typedef void ID3D11Device;
 #include <ffnvcodec/nvEncodeAPI.h>
 
 #include "compat/cuda/dynlink_loader.h"
+#include "libavutil/buffer.h"
 #include "libavutil/fifo.h"
 #include "libavutil/opt.h"
 #include "hwconfig.h"
@@ -90,6 +91,18 @@ typedef struct NvencSurface
     NV_ENC_BUFFER_FORMAT format;
 } NvencSurface;
 
+typedef struct NvencFrameData
+{
+    int64_t duration;
+
+#if FF_API_REORDERED_OPAQUE
+    int64_t reordered_opaque;
+#endif
+
+    void        *frame_opaque;
+    AVBufferRef *frame_opaque_ref;
+} NvencFrameData;
+
 typedef struct NvencDynLoadFunctions
 {
     CudaFunctions *cuda_dl;
@@ -168,6 +181,10 @@ typedef struct NvencContext
     int nb_surfaces;
     NvencSurface *surfaces;
 
+    NvencFrameData *frame_data_array;
+    int frame_data_array_nb;
+    int frame_data_array_pos;
+
     AVFifo *unused_surface_queue;
     AVFifo *output_surface_queue;
     AVFifo *output_surface_ready_queue;
diff --git a/libavcodec/nvenc_av1.c b/libavcodec/nvenc_av1.c
index 2ed99d948b..2b349c7b61 100644
--- a/libavcodec/nvenc_av1.c
+++ b/libavcodec/nvenc_av1.c
@@ -181,7 +181,8 @@ const FFCodec ff_av1_nvenc_encoder = {
     .defaults       = defaults,
     .p.pix_fmts     = ff_nvenc_pix_fmts,
     .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
-                      AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1,
+                      AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 |
+                      AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
     .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
                       FF_CODEC_CAP_INIT_CLEANUP,
     .p.wrapper_name = "nvenc",
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index a69358b03b..5dc2961c3b 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -232,7 +232,8 @@ const FFCodec ff_h264_nvenc_encoder = {
     .p.priv_class   = &h264_nvenc_class,
     .defaults       = defaults,
     .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
-                      AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1,
+                      AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 |
+                      AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
     .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
                       FF_CODEC_CAP_INIT_CLEANUP,
     .p.pix_fmts     = ff_nvenc_pix_fmts,
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index 5ad423444a..1362a927c8 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -214,7 +214,8 @@ const FFCodec ff_hevc_nvenc_encoder = {
     .defaults       = defaults,
     .p.pix_fmts     = ff_nvenc_pix_fmts,
     .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
-                      AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1,
+                      AV_CODEC_CAP_ENCODER_FLUSH | AV_CODEC_CAP_DR1 |
+                      AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
     .caps_internal  = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
                       FF_CODEC_CAP_INIT_CLEANUP,
     .p.wrapper_name = "nvenc",



More information about the ffmpeg-cvslog mailing list