diff mbox series

[FFmpeg-devel,5/5] avformat/matroskaenc: Remove limit on the number of tracks

Message ID 20200416235435.20409-3-andreas.rheinhardt@gmail.com
State Accepted
Commit 13c12cd4702e621c7363be8f22a8b55c22a31a02
Headers show
Series [FFmpeg-devel,1/2] fftools/ffmpeg_opt: Check attachment filesize | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Andreas Rheinhardt April 16, 2020, 11:54 p.m. UTC
The Matroska file format has practically no limit on the number of
tracks (the current limit is 2^56 - 1); yet because they are encoded in
a variable length format in (Simple)Blocks this muxer has simply imposed
a limit on the number of tracks in order to ensure that they can always
be written on one byte in order to simplify the muxing process.

This commit removes said limit.

Also, zero is an invalid TrackNumber, so disallow this value in the
dash_track_number option.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
---
 libavformat/matroskaenc.c | 34 +++++++++++++---------------------
 1 file changed, 13 insertions(+), 21 deletions(-)
diff mbox series

Patch

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 92cd819312..fcca4c2e87 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -93,6 +93,7 @@  typedef struct mkv_track {
     int             has_cue;
     uint64_t        uid;
     unsigned        track_num;
+    int             track_num_size;
     int             sample_rate;
     int64_t         sample_rate_offset;
     int64_t         last_timestamp;
@@ -105,10 +106,6 @@  typedef struct mkv_track {
 #define MODE_MATROSKAv2 0x01
 #define MODE_WEBM       0x02
 
-/** Maximum number of tracks allowed in a Matroska file (with track numbers in
- * range 1 to 126 (inclusive) */
-#define MAX_TRACKS 126
-
 typedef struct MatroskaMuxContext {
     const AVClass   *class;
     int             mode;
@@ -1905,9 +1902,9 @@  static int mkv_write_header(AVFormatContext *s)
     return 0;
 }
 
-static int mkv_blockgroup_size(int pkt_size)
+static int mkv_blockgroup_size(int pkt_size, int track_num_size)
 {
-    int size = pkt_size + 4;
+    int size = pkt_size + track_num_size + 3;
     size += ebml_length_size(size);
     size += 2;              // EBML ID for block and block duration
     size += 9;              // max size of block duration incl. length field
@@ -2047,9 +2044,8 @@  static int mkv_write_block(AVFormatContext *s, AVIOContext *pb,
     }
 
     put_ebml_id(pb, blockid);
-    put_ebml_length(pb, size + 4, 0);
-    // this assumes stream_index is less than 126
-    avio_w8(pb, 0x80 | track_number);
+    put_ebml_length(pb, size + track->track_num_size + 3, 0);
+    put_ebml_num(pb, track_number, track->track_num_size);
     avio_wb16(pb, ts - mkv->cluster_pts);
     avio_w8(pb, (blockid == MATROSKA_ID_SIMPLEBLOCK && keyframe) ? (1 << 7) : 0);
     avio_write(pb, data + offset, size);
@@ -2112,11 +2108,12 @@  static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
            size, pkt->pts, pkt->dts, pkt->duration, avio_tell(pb),
            mkv->cluster_pos, track->track_num, 1);
 
-    blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(size));
+    blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
+                                   mkv_blockgroup_size(size, track->track_num_size));
 
     put_ebml_id(pb, MATROSKA_ID_BLOCK);
-    put_ebml_length(pb, size + 4, 0);
-    avio_w8(pb, 0x80 | track->track_num);     // this assumes track_num is less than 126
+    put_ebml_length(pb, size + track->track_num_size + 3, 0);
+    put_ebml_num(pb, track->track_num, track->track_num_size);
     avio_wb16(pb, ts - mkv->cluster_pts);
     avio_w8(pb, flags);
     avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data);
@@ -2290,7 +2287,8 @@  static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_
             duration = mkv_write_vtt_blocks(s, pb, pkt);
         } else {
             ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP,
-                                                       mkv_blockgroup_size(pkt->size));
+                                                       mkv_blockgroup_size(pkt->size,
+                                                                           track->track_num_size));
 
 #if FF_API_CONVERGENCE_DURATION
 FF_DISABLE_DEPRECATION_WARNINGS
@@ -2652,13 +2650,7 @@  static int mkv_init(struct AVFormatContext *s)
 
         nb_tracks++;
         track->track_num = mkv->is_dash ? mkv->dash_track_number : nb_tracks;
-    }
-
-    if (nb_tracks > MAX_TRACKS) {
-        av_log(s, AV_LOG_ERROR,
-               "%u > "AV_STRINGIFY(MAX_TRACKS)" tracks (excluding attachments)"
-               " not supported for muxing in Matroska\n", nb_tracks);
-        return AVERROR(EINVAL);
+        track->track_num_size = ebml_num_size(track->track_num);
     }
 
     return 0;
@@ -2716,7 +2708,7 @@  static const AVOption options[] = {
     { "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 },
     { "dash", "Create a WebM file conforming to WebM DASH specification", OFFSET(is_dash), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
-    { "dash_track_number", "Track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 127, FLAGS },
+    { "dash_track_number", "Track number for the DASH stream", OFFSET(dash_track_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS },
     { "live", "Write files assuming it is a live stream.", OFFSET(is_live), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     { "allow_raw_vfw", "allow RAW VFW mode", OFFSET(allow_raw_vfw), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
     { "write_crc32", "write a CRC32 element inside every Level 1 element", OFFSET(write_crc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },