[FFmpeg-devel] [PATCH] libavformat > matroskaenc : Enable manual setting of disposition:default tag

Elian FARAJ elian.faraj at gmail.com
Thu Jan 8 15:02:15 CET 2015


Hi folks,

In Matroska specifications you can set a stream as default stream using the metadata tag disposition:default. If there is no value, default value is 1, implying the stream is default (...by default). Ffmpeg currently supports this but only when there are default/non default streams in input file, user has no way to set himself what should be default and what shouldn't be. When we're outside of this case (often happens) this causes unwanted behavior : when you have 2 audio streams nothing will be written in disposition:default so according to Matroska standards the 2 streams will be default. If you want to set an audio stream as default (because it's in the language you want as default for example) you cannot - and by the way "two default streams" doesn't make any sense. It's worse if you got subtitles and if you want none as default because your player will show subtitles by default, as subtitles streams are default streams too.

Sorry if this description is pure mess, here are few links with relevant information :
http://thread.gmane.org/gmane.comp.video.ffmpeg.devel/158229
http://article.gmane.org/gmane.comp.video.ffmpeg.devel/158353
http://ffmpeg.org/pipermail/ffmpeg-user/2012-October/010845.html

As stated in the last link users can try to set a metadata tag disposition:default but it will be considered as "extra" metadata and not real default tag. My patch aims to support this tag so default stream status is actually written. My patch doesn't change default (sorry) behavior of Ffmpeg, it only enables users set a default stream tag which overrides automatic choices of Ffmpeg.

Please note that I'm an extreme beginner in all those topics. I have near no experience in multimedia, I have poor programming skills ("skilled" only with PHP and very general knowledge in true programming languages, you couldn't even state that I'm "programming !") and I never used Git nor mailing lists before, I quickly Googled those topics. I simply wanted to enable something in Ffmpeg and I don't like begging for others to work for me so I tried it by myself. Sorry if I did anything wrong.

I'll use a simple example to show you how my patch works. We'll take a file, Video.avi, with 1 video and 1 audio streams. We'll convert it to Video.mkv, with 1 video stream and 2 duplicated audio streams. We'll set the video stream and the first audio stream as default.

Original Ffmpeg behavior :
ffmpeg -i Video.avi -map 0:0 -map 0:1 -map 0:1 -metadata:s:v:0 disposition:default=1 -metadata:s:a:0 disposition:default=1 -metadata:s:a:1 disposition:default=0 Video.mkv
The disposition:default tag is not actually written in those 3 cases. Therefore any video player compliant with Matroska specs reads those 3 streams as default.

With my patch :
ffmpeg -i Video.avi -map 0:0 -map 0:1 -map 0:1 -metadata:s:v:0 disposition:default=1 -metadata:s:a:0 disposition:default=1 -metadata:s:a:1 disposition:default=0 Video.mkv
Video stream (#0) : disposition:default=1 : The video stream is set as default so it is read as default (doesn't change with the case above)
Audio stream #0 : disposition:default=1 : This audio stream is set as default so it is read as default
Audio stream #1 : disposition:default=0 : This audio stream is set as not default so it is not read as default (this changes with the case above)

Thanks for reviewing


--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -842,9 +842,13 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv,
     }
 
     // The default value for TRACKFLAGDEFAULT is 1, so add element
-    // if we need to clear it.
+    // if we need to clear it or if it is user defined.
     if (default_stream_exists && !(st->disposition & AV_DISPOSITION_DEFAULT))
+        // There is a default stream and it is not the current one
         put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, !!(st->disposition & AV_DISPOSITION_DEFAULT));
+    else if (tag = av_dict_get(st->metadata, "disposition:default", NULL, 0))
+        // User manually set a value for disposition:default
+        put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGDEFAULT, strtoul(tag->value, NULL, 10));
 
     if (st->disposition & AV_DISPOSITION_FORCED)
         put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1);
@@ -1141,6 +1145,7 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme
 
     while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX))) {
         if (av_strcasecmp(t->key, "title") &&
+            av_strcasecmp(t->key, "disposition:default") &&
             av_strcasecmp(t->key, "stereo_mode") &&
             av_strcasecmp(t->key, "encoding_tool")) {
             ret = mkv_write_simpletag(s->pb, t);
@@ -1158,7 +1163,7 @@ static int mkv_check_tag(AVDictionary *m)
     AVDictionaryEntry *t = NULL;
 
     while ((t = av_dict_get(m, "", t, AV_DICT_IGNORE_SUFFIX)))
-        if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "stereo_mode"))
+        if (av_strcasecmp(t->key, "title") && av_strcasecmp(t->key, "disposition:default") && av_strcasecmp(t->key, "stereo_mode"))
             return 1;
 
     return 0;


More information about the ffmpeg-devel mailing list