Imported Debian version 2.5.0~trusty1.1
[deb_ffmpeg.git] / ffmpeg / libavformat / webmdashenc.c
index 77f6170a26ab2e3d60cf34a55e0831646fb2d4aa..4536b7d5a8ecb13e1fcae0211f02edf0c9d1f4dc 100644 (file)
@@ -46,6 +46,7 @@ typedef struct WebMDashMuxContext {
     char *adaptation_sets;
     AdaptationSet *as;
     int nb_as;
+    int representation_id;
 } WebMDashMuxContext;
 
 static const char *get_codec_name(int codec_id)
@@ -95,7 +96,7 @@ static void write_header(AVFormatContext *s)
 
 static void write_footer(AVFormatContext *s)
 {
-    avio_printf(s->pb, "</MPD>");
+    avio_printf(s->pb, "</MPD>\n");
 }
 
 static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as) {
@@ -132,6 +133,80 @@ static int bitstream_switching(AVFormatContext *s, AdaptationSet *as) {
     return 1;
 }
 
+/*
+ * Writes a Representation within an Adaptation Set. Returns 0 on success and
+ * < 0 on failure.
+ */
+static int write_representation(AVFormatContext *s, AVStream *stream, int id,
+                                int output_width, int output_height,
+                                int output_sample_rate) {
+    AVDictionaryEntry *irange = av_dict_get(stream->metadata, INITIALIZATION_RANGE, NULL, 0);
+    AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0);
+    AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0);
+    AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0);
+    AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0);
+    if (!irange || cues_start == NULL || cues_end == NULL || filename == NULL ||
+        !bandwidth) {
+        return -1;
+    }
+    avio_printf(s->pb, "<Representation id=\"%d\"", id);
+    avio_printf(s->pb, " bandwidth=\"%s\"", bandwidth->value);
+    if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && output_width)
+        avio_printf(s->pb, " width=\"%d\"", stream->codec->width);
+    if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO && output_height)
+        avio_printf(s->pb, " height=\"%d\"", stream->codec->height);
+    if (stream->codec->codec_type = AVMEDIA_TYPE_AUDIO && output_sample_rate)
+        avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codec->sample_rate);
+    avio_printf(s->pb, ">\n");
+    avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value);
+    avio_printf(s->pb, "<SegmentBase\n");
+    avio_printf(s->pb, "  indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value);
+    avio_printf(s->pb, "<Initialization\n");
+    avio_printf(s->pb, "  range=\"0-%s\" />\n", irange->value);
+    avio_printf(s->pb, "</SegmentBase>\n");
+    avio_printf(s->pb, "</Representation>\n");
+    return 0;
+}
+
+/*
+ * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise.
+ */
+static int check_matching_width(AVFormatContext *s, AdaptationSet *as) {
+    int first_width, i;
+    if (as->nb_streams < 2) return 1;
+    first_width = s->streams[as->streams[0]]->codec->width;
+    for (i = 1; i < as->nb_streams; i++)
+        if (first_width != s->streams[as->streams[i]]->codec->width)
+          return 0;
+    return 1;
+}
+
+/*
+ * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise.
+ */
+static int check_matching_height(AVFormatContext *s, AdaptationSet *as) {
+    int first_height, i;
+    if (as->nb_streams < 2) return 1;
+    first_height = s->streams[as->streams[0]]->codec->height;
+    for (i = 1; i < as->nb_streams; i++)
+        if (first_height != s->streams[as->streams[i]]->codec->height)
+          return 0;
+    return 1;
+}
+
+/*
+ * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise.
+ */
+static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as) {
+    int first_sample_rate, i;
+    if (as->nb_streams < 2) return 1;
+    first_sample_rate = s->streams[as->streams[0]]->codec->sample_rate;
+    for (i = 1; i < as->nb_streams; i++)
+        if (first_sample_rate != s->streams[as->streams[i]]->codec->sample_rate)
+          return 0;
+    return 1;
+}
+
 /*
  * Writes an Adaptation Set. Returns 0 on success and < 0 on failure.
  */
@@ -140,10 +215,22 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
     WebMDashMuxContext *w = s->priv_data;
     AdaptationSet *as = &w->as[as_index];
     AVCodecContext *codec = s->streams[as->streams[0]]->codec;
+    AVDictionaryEntry *lang;
     int i;
     static const char boolean[2][6] = { "false", "true" };
     int subsegmentStartsWithSAP = 1;
-    AVDictionaryEntry *lang;
+
+    // Width, Height and Sample Rate will go in the AdaptationSet tag if they
+    // are the same for all contained Representations. otherwise, they will go
+    // on their respective Representation tag.
+    int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
+    if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+      width_in_as = check_matching_width(s, as);
+      height_in_as = check_matching_height(s, as);
+    } else {
+      sample_rate_in_as = check_matching_sample_rate(s, as);
+    }
+
     avio_printf(s->pb, "<AdaptationSet id=\"%s\"", as->id);
     avio_printf(s->pb, " mimeType=\"%s/webm\"",
                 codec->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
@@ -152,12 +239,12 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
     lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0);
     if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value);
 
-    if (codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+    if (codec->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as)
         avio_printf(s->pb, " width=\"%d\"", codec->width);
+    if (codec->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as)
         avio_printf(s->pb, " height=\"%d\"", codec->height);
-    } else {
+    if (codec->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as)
         avio_printf(s->pb, " audioSamplingRate=\"%d\"", codec->sample_rate);
-    }
 
     avio_printf(s->pb, " bitstreamSwitching=\"%s\"",
                 boolean[bitstream_switching(s, as)]);
@@ -173,26 +260,8 @@ static int write_adaptation_set(AVFormatContext *s, int as_index)
     avio_printf(s->pb, ">\n");
 
     for (i = 0; i < as->nb_streams; i++) {
-        AVStream *stream = s->streams[as->streams[i]];
-        AVDictionaryEntry *irange = av_dict_get(stream->metadata, INITIALIZATION_RANGE, NULL, 0);
-        AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0);
-        AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0);
-        AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0);
-        AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0);
-        if (!irange || cues_start == NULL || cues_end == NULL || filename == NULL ||
-            !bandwidth) {
-            return -1;
-        }
-        avio_printf(s->pb, "<Representation id=\"%d\"", i);
-        avio_printf(s->pb, " bandwidth=\"%s\"", bandwidth->value);
-        avio_printf(s->pb, ">\n");
-        avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value);
-        avio_printf(s->pb, "<SegmentBase\n");
-        avio_printf(s->pb, "  indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value);
-        avio_printf(s->pb, "<Initialization\n");
-        avio_printf(s->pb, "  range=\"0-%s\" />\n", irange->value);
-        avio_printf(s->pb, "</SegmentBase>\n");
-        avio_printf(s->pb, "</Representation>\n");
+        write_representation(s, s->streams[as->streams[i]], w->representation_id++,
+                             !width_in_as, !height_in_as, !sample_rate_in_as);
     }
     avio_printf(s->pb, "</AdaptationSet>\n");
     return 0;