1 /*
2 * WebM DASH Manifest XML muxer
3 * Copyright (c) 2014 Vignesh Venkatasubramanian
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /*
23 * WebM DASH Specification:
24 * https://sites.google.com/a/webmproject.org/wiki/adaptive-streaming/webm-dash-specification
25 */
26
27 #include <stdint.h>
28 #include <string.h>
29
33
37
43
51
53 {
54 switch (codec_id) {
56 return "vp8";
58 return "vp9";
60 return "vorbis";
62 return "opus";
63 }
65 }
66
68 {
69 int i = 0;
70 double max = 0.0;
74 if (!duration || atof(duration->
value) < 0)
continue;
75 if (atof(duration->
value) > max) max = atof(duration->
value);
76 }
77 return max / 1000;
78 }
79
81 {
82 double min_buffer_time = 1.0;
83 avio_printf(s->
pb,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
85 avio_printf(s->
pb,
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
86 avio_printf(s->
pb,
" xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
87 avio_printf(s->
pb,
" xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
92 min_buffer_time);
93 avio_printf(s->
pb,
" profiles=\"urn:webm:dash:profile:webm-on-demand:2012\"");
95 }
96
98 {
100 }
101
103 int i;
106 if (!gold) return 0;
110 if (!ts || strncmp(gold->
value, ts->
value, strlen(gold->
value)))
return 0;
111 }
112 return 1;
113 }
114
116 int i;
120 if (!gold_track_num) return 0;
125 if (!track_num ||
126 strncmp(gold_track_num->
value, track_num->
value, strlen(gold_track_num->
value)) ||
130 return 0;
131 }
132 }
133 return 1;
134 }
135
136 /*
137 * Writes a Representation within an Adaptation Set. Returns 0 on success and
138 * < 0 on failure.
139 */
141 int output_width, int output_height,
142 int output_sample_rate) {
148 if (!irange || cues_start ==
NULL || cues_end ==
NULL || filename ==
NULL ||
149 !bandwidth) {
150 return -1;
151 }
168 return 0;
169 }
170
171 /*
172 * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise.
173 */
175 int first_width, i;
180 return 0;
181 return 1;
182 }
183
184 /*
185 * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise.
186 */
188 int first_height, i;
193 return 0;
194 return 1;
195 }
196
197 /*
198 * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise.
199 */
201 int first_sample_rate, i;
206 return 0;
207 return 1;
208 }
209
210 /*
211 * Writes an Adaptation Set. Returns 0 on success and < 0 on failure.
212 */
214 {
219 int i;
220 static const char boolean[2][6] = { "false", "true" };
221 int subsegmentStartsWithSAP = 1;
222
223 // Width, Height and Sample Rate will go in the AdaptationSet tag if they
224 // are the same for all contained Representations. otherwise, they will go
225 // on their respective Representation tag.
226 int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
230 } else {
232 }
233
238
241
248
253
257 if (!kf || !strncmp(kf->
value,
"0", 1)) subsegmentStartsWithSAP = 0;
258 }
259 avio_printf(s->
pb,
" subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
261
264 !width_in_as, !height_in_as, !sample_rate_in_as);
265 }
267 return 0;
268 }
269
271 {
274 if (!q) return -1;
276 ret = atoi(q);
279 }
280
282 {
285 char *q;
286 enum { new_set, parsed_id, parsing_streams }
state;
287 // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
290 if (*p == ' ')
291 continue;
292 else if (
state == new_set && !strncmp(p,
"id=", 3)) {
294 if (w->
as ==
NULL)
return -1;
297 p += 3; // consume "id="
299 while (*p != ',') *q++ = *p++;
300 *q = 0;
301 p++;
303 }
else if (
state == parsed_id && !strncmp(p,
"streams=", 8)) {
304 p += 8; // consume "streams="
305 state = parsing_streams;
306 }
else if (
state == parsing_streams) {
308 q = p;
309 while (*q != '0円' && *q != ',' && *q != ' ') q++;
314 if (*q == '0円') break;
315 if (*q ==
' ')
state = new_set;
316 p = ++q;
317 } else {
318 return -1;
319 }
320 }
321 return 0;
322 }
323
325 {
326 int i;
335
336 for (i = 0; i < w->
nb_as; i++) {
338 }
339
342 return 0;
343 }
344
346 {
348 }
349
351 {
353 int i;
354 for (i = 0; i < w->
nb_as; i++) {
356 }
358 return 0;
359 }
360
361 #define OFFSET(x) offsetof(WebMDashMuxContext, x)
363 {
"adaptation_sets",
"Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on",
OFFSET(adaptation_sets),
AV_OPT_TYPE_STRING, { 0 }, 0, 0,
AV_OPT_FLAG_ENCODING_PARAM },
365 };
366
367 #if CONFIG_WEBM_DASH_MANIFEST_MUXER
368 static const AVClass webm_dash_class = {
373 };
374
376 .
name =
"webm_dash_manifest",
378 .mime_type = "application/xml",
379 .extensions = "xml",
384 .priv_class = &webm_dash_class,
385 };
386 #endif