@@ -89,6 +89,7 @@ static const AVOption options[] = {
{ "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
{ "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
{ "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
+ { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
{ NULL },
};
@@ -3435,6 +3436,45 @@ static void build_chunks(MOVTrack *trk)
}
}
+/** Assign track ids. If use_stream_ids_as_track_ids is set, the
+ stream ids are used as track ids special case is taken to generate
+ track ids for generated tracks, which don't have a 1:1 stream to
+ copy the stream id from. This the order of tracks is the same in
+ both mov->tracks and s->streams (and no holes). */
+static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
+{
+ int i;
+
+ if (mov->track_ids_ok)
+ return 0;
+
+ if (mov->use_stream_ids_as_track_ids) {
+ int next_generated_track_id = 0;
+ for (i = 0; i < s->nb_streams; i++) {
+ if (s->streams[i]->id > next_generated_track_id)
+ next_generated_track_id = s->streams[i]->id;
+ }
+
+ for (i = 0; i < mov->nb_streams; i++) {
+ if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
+ continue;
+
+ mov->tracks[i].track_id = i >= s->nb_streams ? ++next_generated_track_id : s->streams[i]->id;
+ }
+ } else {
+ for (i = 0; i < mov->nb_streams; i++) {
+ if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
+ continue;
+
+ mov->tracks[i].track_id = i + 1;
+ }
+ }
+
+ mov->track_ids_ok = 1;
+
+ return 0;
+}
+
static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
AVFormatContext *s)
{
@@ -3443,12 +3483,13 @@ static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
avio_wb32(pb, 0); /* size placeholder*/
ffio_wfourcc(pb, "moov");
+ mov_setup_track_ids(mov, s);
+
for (i = 0; i < mov->nb_streams; i++) {
if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
continue;
mov->tracks[i].time = mov->time;
- mov->tracks[i].track_id = i + 1;
if (mov->tracks[i].entry)
build_chunks(&mov->tracks[i]);
@@ -3529,7 +3570,7 @@ static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *va
avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
}
-static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov)
+static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
{
int64_t pos = avio_tell(pb);
int i;
@@ -3552,12 +3593,13 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov)
avio_printf(pb, "</head>\n");
avio_printf(pb, "<body>\n");
avio_printf(pb, "<switch>\n");
+
+ mov_setup_track_ids(mov, s);
+
for (i = 0; i < mov->nb_streams; i++) {
MOVTrack *track = &mov->tracks[i];
const char *type;
- /* track->track_id is initialized in write_moov, and thus isn't known
- * here yet */
- int track_id = i + 1;
+ int track_id = track->track_id;
if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
type = "video";
@@ -5773,7 +5815,7 @@ static int mov_write_header(AVFormatContext *s)
avio_flush(pb);
if (mov->flags & FF_MOV_FLAG_ISML)
- mov_write_isml_manifest(pb, mov);
+ mov_write_isml_manifest(pb, mov, s);
if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
@@ -217,6 +217,8 @@ typedef struct MOVMuxContext {
int need_rewrite_extradata;
+ int use_stream_ids_as_track_ids;
+ int track_ids_ok;
} MOVMuxContext;
#define FF_MOV_FLAG_RTP_HINT (1 << 0)