[PR] avcodec/nvenc: write AV1 timecode metadata in AV1 syntax (PR #23863)

michaelni via ffmpeg-devel <[email protected]> Tue, 21 Jul 2026 03:22:44 -0000
Newsgroups gmane.comp.video.ffmpeg.devel
Message-ID <178460416490.59.16303049658958099686@29965ddac10e>
PR #23863 opened by michaelni
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23863
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23863.patch

Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/20610

Untested: no working nvidia setup on this box



>From 85dbf470b3466a615dcf11d10645e2fe4e5a8b23 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Tue, 21 Jul 2026 04:47:29 +0200
Subject: [PATCH] avcodec/nvenc: write AV1 timecode metadata in AV1 syntax

Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/20610

Untested: no working nvidia setup on this box
---
 libavcodec/nvenc.c | 48 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 1 deletion(-)

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index dffbb67652..91c2ec815c 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -43,6 +43,7 @@
 #include "codec_desc.h"
 #include "encode.h"
 #include "internal.h"
+#include "put_bits.h"
 
 #define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, dl_fn->cuda_dl, x)
 
@@ -2723,6 +2724,43 @@ static int output_ready(AVCodecContext *avctx, int flush)
     return (nb_ready > 0) && (nb_ready + nb_pending >= ctx->async_depth);
 }
 
+#if CONFIG_AV1_NVENC_ENCODER
+static int alloc_av1_timecode_metadata(const AVFrame *frame, AVRational rate,
+                                       void **data, size_t *size)
+{
+    const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE);
+    const uint32_t *tc = (const uint32_t*)sd->data;
+    unsigned hh, mm, ss, ff, drop;
+    PutBitContext pb;
+
+    *data = NULL;
+    if (!(tc[0] & 3))
+        return 0;
+
+    ff_timecode_set_smpte(&drop, &hh, &mm, &ss, &ff, rate, tc[1], 0, 0);
+
+    *size = 5;
+    *data = av_malloc(*size);
+    if (!*data)
+        return AVERROR(ENOMEM);
+
+    init_put_bits(&pb, *data, *size);
+    put_bits(&pb, 5, 0);    // counting_type
+    put_bits(&pb, 1, 1);    // full_timestamp_flag
+    put_bits(&pb, 1, 0);    // discontinuity_flag
+    put_bits(&pb, 1, drop); // cnt_dropped_flag
+    put_bits(&pb, 9, ff);   // n_frames
+    put_bits(&pb, 6, ss);   // seconds_value
+    put_bits(&pb, 6, mm);   // minutes_value
+    put_bits(&pb, 5, hh);   // hours_value
+    put_bits(&pb, 5, 1);    // time_offset_length
+    put_bits(&pb, 1, 0);    // time_offset_value
+    flush_put_bits(&pb);
+
+    return 0;
+}
+#endif
+
 static int prepare_sei_data_array(AVCodecContext *avctx, const AVFrame *frame)
 {
     NvencContext *ctx = avctx->priv_data;
@@ -2765,8 +2803,16 @@ static int prepare_sei_data_array(AVCodecContext *avctx, const AVFrame *frame)
     if (ctx->s12m_tc && avctx->codec->id != AV_CODEC_ID_H264 && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) {
         void *tc_data = NULL;
         size_t tc_size = 0;
+        int ret;
 
-        if (ff_alloc_timecode_sei(frame, avctx->framerate, 0, &tc_data, &tc_size) < 0) {
+#if CONFIG_AV1_NVENC_ENCODER
+        if (avctx->codec->id == AV_CODEC_ID_AV1)
+            ret = alloc_av1_timecode_metadata(frame, avctx->framerate, &tc_data, &tc_size);
+        else
+#endif
+            ret = ff_alloc_timecode_sei(frame, avctx->framerate, 0, &tc_data, &tc_size);
+
+        if (ret < 0) {
             av_log(ctx, AV_LOG_ERROR, "Not enough memory for timecode sei, skipping\n");
         }
 
-- 
2.52.0

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