Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Jerome Martinez via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: Jerome Martinez <jerome@mediaarea.net>
Subject: [FFmpeg-devel] [PATCH 7/7] matroskaenc: write timecode in BlockAddition
Date: Tue, 9 Sep 2025 14:41:53 +0200
Message-ID: <890ba184-930c-4f51-9cf5-a9f33ff6f7ad@mediaarea.net> (raw)
In-Reply-To: <d65a0f50-3766-4539-b140-55d7ac12810d@mediaarea.net>

[-- Attachment #1: 0007-matroskaenc-write-timecode-in-BlockAddition.patch --]
[-- Type: text/plain, Size: 5981 bytes --]

>From f7aeb160a8ba2e2eefa6206af2ff5179a88f7343 Mon Sep 17 00:00:00 2001
From: Jerome Martinez <jerome@mediaarea.net>
Date: Thu, 4 Sep 2025 20:18:08 +0200
Subject: [PATCH 7/7] matroskaenc: write timecode in BlockAddition

---
 libavformat/matroskaenc.c | 45 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index d304b63663..aa7b8f4443 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -60,6 +60,7 @@
 #include "libavutil/rational.h"
 #include "libavutil/samplefmt.h"
 #include "libavutil/stereo3d.h"
+#include "libavutil/timecode.h"
 
 #include "libavcodec/av1.h"
 #include "libavcodec/bytestream.h"
@@ -81,6 +82,9 @@
 #define MAX_SUPPORTED_EBML_LENGTH FFMIN(MAX_EBML_LENGTH, INT_MAX)
 
 #define MAX_MATROSKA_BLOCK_ADD_ITU_T_T35 1 /* currently only 1 such element is supported */
+#define MAX_MATROSKA_BLOCK_ADD_SMPTE_12M 64 /* balance between intermediate buffer size and reality of non existence if so many timecodes streams for one content */
+
+#define MATROSKA_BLOCK_ADD_ID_SMPTE_12M 101 /* arbitrary value */
 
 #define MODE_MATROSKAv2 0x01
 #define MODE_WEBM       0x02
@@ -199,6 +203,7 @@ typedef struct mkv_track {
     int64_t         duration_offset;
     uint64_t        max_blockaddid;
     int             itu_t_t35_count;
+    int             timecode_count;
     int64_t         blockadditionmapping_offset;
     int             codecpriv_offset;
     unsigned        codecpriv_size;     ///< size reserved for CodecPrivate excluding header+length field
@@ -2825,11 +2830,12 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
                            int force_blockgroup, int64_t relative_packet_pos)
 {
     uint8_t t35_buf[6 + AV_HDR_PLUS_MAX_PAYLOAD_SIZE];
+    uint8_t timecode_buf[MAX_MATROSKA_BLOCK_ADD_SMPTE_12M][8];
     uint8_t *side_data;
     size_t side_data_size;
     uint64_t additional_id;
     unsigned track_number = track->track_num;
-    EBML_WRITER(11 + MAX_MATROSKA_BLOCK_ADD_ITU_T_T35);
+    EBML_WRITER(11 + MAX_MATROSKA_BLOCK_ADD_ITU_T_T35 + MAX_MATROSKA_BLOCK_ADD_SMPTE_12M);
     int ret;
 
     mkv->cur_block.track  = track;
@@ -2908,6 +2914,36 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
         }
     }
 
+    // Extract timecode from side data and write as BlockAdditional
+    if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
+        side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_S12M_TIMECODE, &side_data_size);
+        if (side_data && side_data_size >= sizeof(uint64_t)) {
+            uint64_t *side_data_64 = (uint64_t*)side_data;
+            uint64_t count = side_data_64[0];
+            if (side_data_size / sizeof(uint64_t) - 1 >= count ) {
+                uint64_t written_count = count;
+                side_data_64++;
+                if (count > MAX_MATROSKA_BLOCK_ADD_SMPTE_12M) {
+                    if (count > track->timecode_count) {
+                        av_log(logctx, AV_LOG_WARNING, "Too many SMPTE timecode streams in side data, discarding %"PRIu64" timecode streams.\n", count - MAX_MATROSKA_BLOCK_ADD_SMPTE_12M);
+                    }
+                    written_count = MAX_MATROSKA_BLOCK_ADD_SMPTE_12M;
+                }
+                for (uint64_t i = 0; i < written_count; i++) {
+                    uint64_t tc = side_data_64[i];
+                    uint8_t *payload = timecode_buf[i];
+                    AV_WB64(payload, tc);
+                    av_log(logctx, AV_LOG_DEBUG, "Writing SMPTE timecode from side data, pos %"PRIu64", to BlockAdditional: 0x%016lX (RFC 5484)\n", i + 1, tc);
+
+                    int blockaddid = MATROSKA_BLOCK_ADD_ID_SMPTE_12M + i;
+                    mkv_write_blockadditional(&writer, payload, 8, blockaddid);
+                    track->max_blockaddid = FFMAX(track->max_blockaddid, blockaddid);
+                }
+                track->timecode_count = FFMAX(track->timecode_count, count);
+            }
+        }
+    }
+
     ebml_writer_close_or_discard_master(&writer);
 
     if (!force_blockgroup && writer.nb_elements == 2) {
@@ -3320,11 +3356,15 @@ after_cues:
                 int max_block_add_id_count = 0;
                 int max_block_add_id_size = 3 + uint_size(track->max_blockaddid);
                 int block_type_t35_count = 0;
+                int block_type_timecode_count = 0;
 
                 if (!track->max_blockaddid)
                     continue;
 
                 /* check what is possible to write in the reserved space, in priority order */
+                for (int i = 0; i < track->timecode_count; i++) {
+                    block_type_timecode_count += mkv_simulate_blockadditional_header(s, &remaining_video_track_space, MATROSKA_BLOCK_ADD_ID_TYPE_SMPTE_12M, MATROSKA_BLOCK_ADD_ID_SMPTE_12M + i);
+                }
                 for (int i = 0; i < track->itu_t_t35_count; i++) {
                     block_type_t35_count += mkv_simulate_blockadditional_header(s, &remaining_video_track_space, MATROSKA_BLOCK_ADD_ID_TYPE_ITU_T_T35, MATROSKA_BLOCK_ADD_ID_TYPE_ITU_T_T35);
                 }                
@@ -3344,6 +3384,9 @@ after_cues:
                 for (int i = 0; i < block_type_t35_count; i++) {
                     mkv_write_blockadditional_header(s, MATROSKA_BLOCK_ADD_ID_TYPE_ITU_T_T35, MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
                 }
+                for (int i = 0; i < block_type_timecode_count; i++) {
+                    mkv_write_blockadditional_header(s, MATROSKA_BLOCK_ADD_ID_TYPE_SMPTE_12M, MATROSKA_BLOCK_ADD_ID_SMPTE_12M + i);
+                }
                 if (remaining_video_track_space > 1) {
                     put_ebml_void(track_bc, remaining_video_track_space);
                 }
-- 
2.46.0.windows.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

  parent reply	other threads:[~2025-09-09 12:42 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-09 12:37 [FFmpeg-devel] [PATCH 0/7] matroska: support of timecode Jerome Martinez via ffmpeg-devel
2025-09-09 12:38 ` [FFmpeg-devel] [PATCH 1/7] matroskaenc: remove unused MaxBlockAdditionID Jerome Martinez via ffmpeg-devel
2025-09-09 12:39 ` [FFmpeg-devel] [PATCH 2/7] matroskaenc: reserve_video_track_space option Jerome Martinez via ffmpeg-devel
2025-09-09 12:39 ` [FFmpeg-devel] [PATCH 3/7] matroskaenc: increase default for reserved bytes in video Jerome Martinez via ffmpeg-devel
2025-09-09 12:40 ` [FFmpeg-devel] [PATCH 4/7] 32-bit timecode to 64-bit RFC 5484 timecode functions Jerome Martinez via ffmpeg-devel
2025-09-09 12:41 ` [FFmpeg-devel] [PATCH 5/7] decklink_dec: store timecode in 64-bit RFC 5484 format Jerome Martinez via ffmpeg-devel
2025-09-09 12:41 ` [FFmpeg-devel] [PATCH 6/7] matroskadec: read timecode in BlockAddition Jerome Martinez via ffmpeg-devel
2025-09-09 12:41 ` Jerome Martinez via ffmpeg-devel [this message]
2025-09-11 15:52 ` [FFmpeg-devel] Re: [PATCH 0/7] matroska: support of timecode Dave Rice via ffmpeg-devel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=890ba184-930c-4f51-9cf5-a9f33ff6f7ad@mediaarea.net \
    --to=ffmpeg-devel@ffmpeg.org \
    --cc=jerome@mediaarea.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git