Commit 13c12cd4 authored by Andreas Rheinhardt's avatar Andreas Rheinhardt

avformat/matroskaenc: Remove limit on the number of tracks

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: 's avatarAndreas Rheinhardt <andreas.rheinhardt@gmail.com>
parent 112afacc
...@@ -93,6 +93,7 @@ typedef struct mkv_track { ...@@ -93,6 +93,7 @@ typedef struct mkv_track {
int has_cue; int has_cue;
uint64_t uid; uint64_t uid;
unsigned track_num; unsigned track_num;
int track_num_size;
int sample_rate; int sample_rate;
int64_t sample_rate_offset; int64_t sample_rate_offset;
int64_t last_timestamp; int64_t last_timestamp;
...@@ -105,10 +106,6 @@ typedef struct mkv_track { ...@@ -105,10 +106,6 @@ typedef struct mkv_track {
#define MODE_MATROSKAv2 0x01 #define MODE_MATROSKAv2 0x01
#define MODE_WEBM 0x02 #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 { typedef struct MatroskaMuxContext {
const AVClass *class; const AVClass *class;
int mode; int mode;
...@@ -1899,9 +1896,9 @@ static int mkv_write_header(AVFormatContext *s) ...@@ -1899,9 +1896,9 @@ static int mkv_write_header(AVFormatContext *s)
return 0; 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 += ebml_length_size(size);
size += 2; // EBML ID for block and block duration size += 2; // EBML ID for block and block duration
size += 9; // max size of block duration incl. length field size += 9; // max size of block duration incl. length field
...@@ -2041,9 +2038,8 @@ static int mkv_write_block(AVFormatContext *s, AVIOContext *pb, ...@@ -2041,9 +2038,8 @@ static int mkv_write_block(AVFormatContext *s, AVIOContext *pb,
} }
put_ebml_id(pb, blockid); put_ebml_id(pb, blockid);
put_ebml_length(pb, size + 4, 0); put_ebml_length(pb, size + track->track_num_size + 3, 0);
// this assumes stream_index is less than 126 put_ebml_num(pb, track_number, track->track_num_size);
avio_w8(pb, 0x80 | track_number);
avio_wb16(pb, ts - mkv->cluster_pts); avio_wb16(pb, ts - mkv->cluster_pts);
avio_w8(pb, (blockid == MATROSKA_ID_SIMPLEBLOCK && keyframe) ? (1 << 7) : 0); avio_w8(pb, (blockid == MATROSKA_ID_SIMPLEBLOCK && keyframe) ? (1 << 7) : 0);
avio_write(pb, data + offset, size); avio_write(pb, data + offset, size);
...@@ -2106,11 +2102,12 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p ...@@ -2106,11 +2102,12 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p
size, pkt->pts, pkt->dts, pkt->duration, avio_tell(pb), size, pkt->pts, pkt->dts, pkt->duration, avio_tell(pb),
mkv->cluster_pos, track->track_num, 1); 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_id(pb, MATROSKA_ID_BLOCK);
put_ebml_length(pb, size + 4, 0); put_ebml_length(pb, size + track->track_num_size + 3, 0);
avio_w8(pb, 0x80 | track->track_num); // this assumes track_num is less than 126 put_ebml_num(pb, track->track_num, track->track_num_size);
avio_wb16(pb, ts - mkv->cluster_pts); avio_wb16(pb, ts - mkv->cluster_pts);
avio_w8(pb, flags); avio_w8(pb, flags);
avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data); avio_printf(pb, "%.*s\n%.*s\n%.*s", id_size, id, settings_size, settings, pkt->size, pkt->data);
...@@ -2284,7 +2281,8 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ ...@@ -2284,7 +2281,8 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_
duration = mkv_write_vtt_blocks(s, pb, pkt); duration = mkv_write_vtt_blocks(s, pb, pkt);
} else { } else {
ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, 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 #if FF_API_CONVERGENCE_DURATION
FF_DISABLE_DEPRECATION_WARNINGS FF_DISABLE_DEPRECATION_WARNINGS
...@@ -2646,13 +2644,7 @@ static int mkv_init(struct AVFormatContext *s) ...@@ -2646,13 +2644,7 @@ static int mkv_init(struct AVFormatContext *s)
nb_tracks++; nb_tracks++;
track->track_num = mkv->is_dash ? mkv->dash_track_number : nb_tracks; track->track_num = mkv->is_dash ? mkv->dash_track_number : nb_tracks;
} track->track_num_size = ebml_num_size(track->track_num);
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);
} }
return 0; return 0;
...@@ -2710,7 +2702,7 @@ static const AVOption options[] = { ...@@ -2710,7 +2702,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_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 }, { "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", "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 }, { "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 }, { "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 }, { "write_crc32", "write a CRC32 element inside every Level 1 element", OFFSET(write_crc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment