summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavformat/webmdashenc.c116
-rw-r--r--tests/fate/vpx.mak3
-rw-r--r--tests/ref/fate/webm-dash-manifest-representations30
3 files changed, 125 insertions, 24 deletions
diff --git a/libavformat/webmdashenc.c b/libavformat/webmdashenc.c
index 849b241e52..768b5d2383 100644
--- a/libavformat/webmdashenc.c
+++ b/libavformat/webmdashenc.c
@@ -133,6 +133,80 @@ static int bitstream_switching(AVFormatContext *s, AdaptationSet *as) {
}
/*
+ * 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.
*/
static int write_adaptation_set(AVFormatContext *s, int as_index)
@@ -140,10 +214,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 +238,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 +259,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]], i,
+ !width_in_as, !height_in_as, !sample_rate_in_as);
}
avio_printf(s->pb, "</AdaptationSet>\n");
return 0;
diff --git a/tests/fate/vpx.mak b/tests/fate/vpx.mak
index 0f84ef5ac3..be3e95672b 100644
--- a/tests/fate/vpx.mak
+++ b/tests/fate/vpx.mak
@@ -37,6 +37,9 @@ fate-webm-dash-manifest-unaligned-video-streams: CMD = run ffmpeg -f webm_dash_m
FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest-unaligned-audio-streams
fate-webm-dash-manifest-unaligned-audio-streams: CMD = run ffmpeg -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_audio3.webm -c copy -map 0 -map 1 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1" -
+FATE_VP8-$(call DEMDEC, WEBM_DASH_MANIFEST, VP8) += fate-webm-dash-manifest-representations
+fate-webm-dash-manifest-representations: CMD = run ffmpeg -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video1.webm -f webm_dash_manifest -i $(TARGET_SAMPLES)/vp8/dash_video4.webm -c copy -map 0 -map 1 -f webm_dash_manifest -adaptation_sets "id=0,streams=0,1" -
+
FATE_SAMPLES_AVCONV += $(FATE_VP6-yes)
fate-vp6: $(FATE_VP6-yes)
diff --git a/tests/ref/fate/webm-dash-manifest-representations b/tests/ref/fate/webm-dash-manifest-representations
new file mode 100644
index 0000000000..8556ecebee
--- /dev/null
+++ b/tests/ref/fate/webm-dash-manifest-representations
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<MPD
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="urn:mpeg:DASH:schema:MPD:2011"
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011"
+ type="static"
+ mediaPresentationDuration="PT32.48S"
+ minBufferTime="PT1S"
+ profiles="urn:webm:dash:profile:webm-on-demand:2012">
+<Period id="0" start="PT0S" duration="PT32.48S" >
+<AdaptationSet id="0" mimeType="video/webm" codecs="vp8" lang="eng" bitstreamSwitching="true" subsegmentAlignment="false" subsegmentStartsWithSAP="1">
+<Representation id="0" bandwidth="302355" width="640" height="360">
+<BaseURL>dash_video1.webm</BaseURL>
+<SegmentBase
+ indexRange="1115974-1116097">
+<Initialization
+ range="0-441" />
+</SegmentBase>
+</Representation>
+<Representation id="1" bandwidth="243938" width="320" height="240">
+<BaseURL>dash_video4.webm</BaseURL>
+<SegmentBase
+ indexRange="871124-871645">
+<Initialization
+ range="0-437" />
+</SegmentBase>
+</Representation>
+</AdaptationSet>
+</Period>
+</MPD>