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 2/7] matroskaenc: reserve_video_track_space option Date: Tue, 9 Sep 2025 14:39:22 +0200 Message-ID: <dbc97e16-33eb-4f5a-88ce-0ddaf6f3aff3@mediaarea.net> (raw) In-Reply-To: <d65a0f50-3766-4539-b140-55d7ac12810d@mediaarea.net> [-- Attachment #1: 0002-matroskaenc-reserve_video_track_space-option.patch --] [-- Type: text/plain, Size: 10162 bytes --] >From b8a59df6a484beb391898de9b8c38f7387ad7ee5 Mon Sep 17 00:00:00 2001 From: Jerome Martinez <jerome@mediaarea.net> Date: Wed, 3 Sep 2025 21:33:50 +0200 Subject: [PATCH 2/7] matroskaenc: reserve_video_track_space option The number of block additions is not known in advance, so we need to be able to set more reserved space for when we add a lot more block additions. It is also possible to reduce the reserved space (or even eliminate it) for those who want to keep the smallest header possible. --- libavformat/matroskaenc.c | 82 ++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 23 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 5339b6fd33..c7b804a3e5 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -80,6 +80,8 @@ * and so has avio_write(). */ #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 MODE_MATROSKAv2 0x01 #define MODE_WEBM 0x02 @@ -196,6 +198,7 @@ typedef struct mkv_track { int64_t duration; int64_t duration_offset; uint64_t max_blockaddid; + int itu_t_t35_count; int64_t blockadditionmapping_offset; int codecpriv_offset; unsigned codecpriv_size; ///< size reserved for CodecPrivate excluding header+length field @@ -249,6 +252,7 @@ typedef struct MatroskaMuxContext { int wrote_tags; int reserve_cues_space; + int reserve_video_track_space; int cluster_size_limit; int64_t cluster_time_limit; int write_crc; @@ -1706,19 +1710,12 @@ static void mkv_write_blockadditionmapping(AVFormatContext *s, const MatroskaMux const AVDOVIDecoderConfigurationRecord *dovi; const AVPacketSideData *sd; - if (IS_SEEKABLE(s->pb, mkv) && par->codec_type == AVMEDIA_TYPE_VIDEO) { + if (IS_SEEKABLE(s->pb, mkv) && par->codec_type == AVMEDIA_TYPE_VIDEO && mkv->reserve_video_track_space > 1) { track->blockadditionmapping_offset = avio_tell(pb); // We can't know at this point if there will be a block with BlockAdditions, so // we either write the default value here, or a void element. Either of them will // be overwritten when finishing the track. - if (par->codec_type == AVMEDIA_TYPE_VIDEO) { - // Similarly, reserve space for an eventual - // HDR10+ ITU T.35 metadata BlockAdditionMapping. - put_ebml_void(pb, 4 /* MaxBlockAdditionID */ - + 3 /* BlockAdditionMapping */ - + 4 /* BlockAddIDValue */ - + 4 /* BlockAddIDType */); - } + put_ebml_void(pb, mkv->reserve_video_track_space); } sd = av_packet_side_data_get(par->coded_side_data, par->nb_coded_side_data, @@ -2796,6 +2793,31 @@ static void mkv_write_blockadditional(EbmlWriter *writer, const uint8_t *buf, ebml_writer_close_master(writer); } +static int mkv_simulate_blockadditional_header(AVFormatContext *s, int* remaining_video_track_space, uint64_t additional_type, uint64_t additional_id) +{ + int size = 0; + size += uint_size(MATROSKA_ID_BLKADDIDTYPE) + 1 + uint_size(additional_type); + size += uint_size(MATROSKA_ID_BLKADDIDVALUE) + 1 + uint_size(additional_id); + size += uint_size(MATROSKA_ID_TRACKBLKADDMAPPING) + uint_size(size); + if (size > *remaining_video_track_space || *remaining_video_track_space - size == 1) { /* min element full size is 2 so 1 byte is not something which can be let alone */ + av_log(s, AV_LOG_WARNING, "Block addition mapping in track header is not written for type %"PRIu64" id %"PRIu64" due to lack of reserved bytes.\n", additional_type, additional_id); + return 0; + } + *remaining_video_track_space -= size; + return 1; +} + +static void mkv_write_blockadditional_header(AVFormatContext *s, uint64_t additional_type, uint64_t additional_id) +{ + /* when you modify this function, adapt mkv_simulate_blockadditional_header accordingly */ + MatroskaMuxContext *mkv = s->priv_data; + AVIOContext *writer = mkv->track.bc; + ebml_master mapping_master = start_ebml_master(writer, MATROSKA_ID_TRACKBLKADDMAPPING, 8); + put_ebml_uint(writer, MATROSKA_ID_BLKADDIDTYPE, additional_type); + put_ebml_uint(writer, MATROSKA_ID_BLKADDIDVALUE, additional_id); + end_ebml_master(writer, mapping_master); +} + static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv, AVIOContext *pb, const AVCodecParameters *par, mkv_track *track, const AVPacket *pkt, @@ -2807,7 +2829,7 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv, size_t side_data_size; uint64_t additional_id; unsigned track_number = track->track_num; - EBML_WRITER(12); + EBML_WRITER(11 + MAX_MATROSKA_BLOCK_ADD_ITU_T_T35); int ret; mkv->cur_block.track = track; @@ -2882,6 +2904,7 @@ static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv, MATROSKA_BLOCK_ADD_ID_ITU_T_T35); track->max_blockaddid = FFMAX(track->max_blockaddid, MATROSKA_BLOCK_ADD_ID_ITU_T_T35); + track->itu_t_t35_count = 1; } } @@ -3293,24 +3316,36 @@ after_cues: for (unsigned i = 0; i < s->nb_streams; i++) { const mkv_track *track = &mkv->tracks[i]; + int remaining_video_track_space = mkv->reserve_video_track_space; + 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; - if (!track->max_blockaddid || !track->blockadditionmapping_offset) + if (!track->max_blockaddid) continue; - // We reserved a single byte to write this value. - av_assert0(track->max_blockaddid <= 0xFF); + /* check what is possible to write in the reserved space, in priority order */ + 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); + } + if (remaining_video_track_space >= max_block_add_id_size && remaining_video_track_space != max_block_add_id_size + 1) { /* min element full size is 2 so 1 byte is not something which can be let alone */ + max_block_add_id_count++; + remaining_video_track_space -= max_block_add_id_size; + } + /* write what is possible to write in the reserved space */ + /* when you modify this part, adapt the check part above accordingly */ + if (!track->blockadditionmapping_offset) + continue; avio_seek(track_bc, track->blockadditionmapping_offset, SEEK_SET); - - put_ebml_uint(track_bc, MATROSKA_ID_TRACKMAXBLKADDID, - track->max_blockaddid); - if (track->max_blockaddid == MATROSKA_BLOCK_ADD_ID_ITU_T_T35) { - ebml_master mapping_master = start_ebml_master(track_bc, MATROSKA_ID_TRACKBLKADDMAPPING, 8); - put_ebml_uint(track_bc, MATROSKA_ID_BLKADDIDTYPE, - MATROSKA_BLOCK_ADD_ID_TYPE_ITU_T_T35); - put_ebml_uint(track_bc, MATROSKA_ID_BLKADDIDVALUE, - MATROSKA_BLOCK_ADD_ID_ITU_T_T35); - end_ebml_master(track_bc, mapping_master); + if (max_block_add_id_count) { + put_ebml_uint(track_bc, MATROSKA_ID_TRACKMAXBLKADDID, track->max_blockaddid); + } + 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); + } + if (remaining_video_track_space > 1) { + put_ebml_void(track_bc, remaining_video_track_space); } } } @@ -3545,6 +3580,7 @@ static const AVCodecTag additional_subtitle_tags[] = { #define FLAGS AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "reserve_index_space", "reserve a given amount of space (in bytes) at the beginning of the file for the index (cues)", OFFSET(reserve_cues_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { "reserve_video_track_space", "reserve a given amount of space (in bytes) at the beginning of the file for the block additions (HDR, timecodes...)", OFFSET(reserve_video_track_space), AV_OPT_TYPE_INT, { .i64 = 15 }, 0, INT_MAX, FLAGS }, /* the number of block additions is not known in advance, so the default value strikes a balance between the size of the reserved header size and the maximum number of block additions that can be registered at the end of writing */ { "cues_to_front", "move Cues (the index) to the front by shifting data if necessary", OFFSET(move_cues_to_front), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS }, { "cluster_size_limit", "store at most the provided amount of bytes in a cluster", OFFSET(cluster_size_limit), AV_OPT_TYPE_INT , { .i64 = -1 }, -1, INT_MAX, FLAGS }, { "cluster_time_limit", "store at most the provided number of milliseconds in a cluster", OFFSET(cluster_time_limit), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS }, -- 2.46.0.windows.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
next prev parent reply other threads:[~2025-09-09 12:40 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 ` Jerome Martinez via ffmpeg-devel [this message] 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 ` [FFmpeg-devel] [PATCH 7/7] matroskaenc: write " Jerome Martinez via ffmpeg-devel 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=dbc97e16-33eb-4f5a-88ce-0ddaf6f3aff3@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