FFmpeg
webmdashenc.c
Go to the documentation of this file.
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  * ISO DASH Specification:
26  * http://standards.iso.org/ittf/PubliclyAvailableStandards/c065274_ISO_IEC_23009-1_2014.zip
27  */
28 
29 #include <float.h>
30 #include <stdint.h>
31 #include <string.h>
32 
33 #include "avformat.h"
34 #include "avio_internal.h"
35 #include "matroska.h"
36 
37 #include "libavutil/avstring.h"
38 #include "libavutil/dict.h"
39 #include "libavutil/opt.h"
41 
42 typedef struct AdaptationSet {
43  char id[10];
44  int *streams;
47 
48 typedef struct WebMDashMuxContext {
49  const AVClass *class;
52  int nb_as;
54  int is_live;
62 
63 static const char *get_codec_name(int codec_id)
64 {
65  switch (codec_id) {
66  case AV_CODEC_ID_VP8:
67  return "vp8";
68  case AV_CODEC_ID_VP9:
69  return "vp9";
70  case AV_CODEC_ID_VORBIS:
71  return "vorbis";
72  case AV_CODEC_ID_OPUS:
73  return "opus";
74  }
75  return NULL;
76 }
77 
79 {
80  int i = 0;
81  double max = 0.0;
82  for (i = 0; i < s->nb_streams; i++) {
84  DURATION, NULL, 0);
85  if (!duration || atof(duration->value) < 0) continue;
86  if (atof(duration->value) > max) max = atof(duration->value);
87  }
88  return max / 1000;
89 }
90 
92 {
94  double min_buffer_time = 1.0;
95  avio_printf(s->pb, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
96  avio_printf(s->pb, "<MPD\n");
97  avio_printf(s->pb, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
98  avio_printf(s->pb, " xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
99  avio_printf(s->pb, " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
100  avio_printf(s->pb, " type=\"%s\"\n", w->is_live ? "dynamic" : "static");
101  if (!w->is_live) {
102  avio_printf(s->pb, " mediaPresentationDuration=\"PT%gS\"\n",
103  get_duration(s));
104  }
105  avio_printf(s->pb, " minBufferTime=\"PT%gS\"\n", min_buffer_time);
106  avio_printf(s->pb, " profiles=\"%s\"%s",
107  w->is_live ? "urn:mpeg:dash:profile:isoff-live:2011" : "urn:webm:dash:profile:webm-on-demand:2012",
108  w->is_live ? "\n" : ">\n");
109  if (w->is_live) {
110  time_t local_time = time(NULL);
111  struct tm gmt_buffer;
112  struct tm *gmt = gmtime_r(&local_time, &gmt_buffer);
113  char gmt_iso[21];
114  if (!strftime(gmt_iso, 21, "%Y-%m-%dT%H:%M:%SZ", gmt)) {
115  return AVERROR_UNKNOWN;
116  }
117  if (w->debug_mode) {
118  av_strlcpy(gmt_iso, "", 1);
119  }
120  avio_printf(s->pb, " availabilityStartTime=\"%s\"\n", gmt_iso);
121  avio_printf(s->pb, " timeShiftBufferDepth=\"PT%gS\"\n", w->time_shift_buffer_depth);
122  avio_printf(s->pb, " minimumUpdatePeriod=\"PT%dS\"", w->minimum_update_period);
123  avio_printf(s->pb, ">\n");
124  if (w->utc_timing_url) {
125  avio_printf(s->pb, "<UTCTiming\n");
126  avio_printf(s->pb, " schemeIdUri=\"urn:mpeg:dash:utc:http-iso:2014\"\n");
127  avio_printf(s->pb, " value=\"%s\"/>\n", w->utc_timing_url);
128  }
129  }
130  return 0;
131 }
132 
134 {
135  avio_printf(s->pb, "</MPD>\n");
136 }
137 
139  int i;
141  CUE_TIMESTAMPS, NULL, 0);
142  if (!gold) return 0;
143  for (i = 1; i < as->nb_streams; i++) {
145  CUE_TIMESTAMPS, NULL, 0);
146  if (!ts || strncmp(gold->value, ts->value, strlen(gold->value))) return 0;
147  }
148  return 1;
149 }
150 
152  int i;
153  AVDictionaryEntry *gold_track_num = av_dict_get(s->streams[as->streams[0]]->metadata,
154  TRACK_NUMBER, NULL, 0);
155  AVCodecParameters *gold_par = s->streams[as->streams[0]]->codecpar;
156  if (!gold_track_num) return 0;
157  for (i = 1; i < as->nb_streams; i++) {
158  AVDictionaryEntry *track_num = av_dict_get(s->streams[as->streams[i]]->metadata,
159  TRACK_NUMBER, NULL, 0);
160  AVCodecParameters *par = s->streams[as->streams[i]]->codecpar;
161  if (!track_num ||
162  strncmp(gold_track_num->value, track_num->value, strlen(gold_track_num->value)) ||
163  gold_par->codec_id != par->codec_id ||
164  gold_par->extradata_size != par->extradata_size ||
165  memcmp(gold_par->extradata, par->extradata, par->extradata_size)) {
166  return 0;
167  }
168  }
169  return 1;
170 }
171 
172 /*
173  * Writes a Representation within an Adaptation Set. Returns 0 on success and
174  * < 0 on failure.
175  */
176 static int write_representation(AVFormatContext *s, AVStream *stream, char *id,
177  int output_width, int output_height,
178  int output_sample_rate) {
181  AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0);
182  AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0);
183  AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0);
184  AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0);
185  const char *bandwidth_str;
186  if ((w->is_live && (!filename)) ||
187  (!w->is_live && (!irange || !cues_start || !cues_end || !filename || !bandwidth))) {
188  return AVERROR_INVALIDDATA;
189  }
190  avio_printf(s->pb, "<Representation id=\"%s\"", id);
191  // if bandwidth for live was not provided, use a default
192  if (w->is_live && !bandwidth) {
193  bandwidth_str = (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ? "128000" : "1000000";
194  } else {
195  bandwidth_str = bandwidth->value;
196  }
197  avio_printf(s->pb, " bandwidth=\"%s\"", bandwidth_str);
198  if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_width)
199  avio_printf(s->pb, " width=\"%d\"", stream->codecpar->width);
200  if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_height)
201  avio_printf(s->pb, " height=\"%d\"", stream->codecpar->height);
202  if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && output_sample_rate)
203  avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codecpar->sample_rate);
204  if (w->is_live) {
205  // For live streams, Codec and Mime Type always go in the Representation tag.
206  avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(stream->codecpar->codec_id));
207  avio_printf(s->pb, " mimeType=\"%s/webm\"",
208  stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
209  // For live streams, subsegments always start with key frames. So this
210  // is always 1.
211  avio_printf(s->pb, " startsWithSAP=\"1\"");
212  avio_printf(s->pb, ">");
213  } else {
214  avio_printf(s->pb, ">\n");
215  avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value);
216  avio_printf(s->pb, "<SegmentBase\n");
217  avio_printf(s->pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value);
218  avio_printf(s->pb, "<Initialization\n");
219  avio_printf(s->pb, " range=\"0-%s\" />\n", irange->value);
220  avio_printf(s->pb, "</SegmentBase>\n");
221  }
222  avio_printf(s->pb, "</Representation>\n");
223  return 0;
224 }
225 
226 /*
227  * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise.
228  */
230  int first_width, i;
231  if (as->nb_streams < 2) return 1;
232  first_width = s->streams[as->streams[0]]->codecpar->width;
233  for (i = 1; i < as->nb_streams; i++)
234  if (first_width != s->streams[as->streams[i]]->codecpar->width)
235  return 0;
236  return 1;
237 }
238 
239 /*
240  * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise.
241  */
243  int first_height, i;
244  if (as->nb_streams < 2) return 1;
245  first_height = s->streams[as->streams[0]]->codecpar->height;
246  for (i = 1; i < as->nb_streams; i++)
247  if (first_height != s->streams[as->streams[i]]->codecpar->height)
248  return 0;
249  return 1;
250 }
251 
252 /*
253  * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise.
254  */
256  int first_sample_rate, i;
257  if (as->nb_streams < 2) return 1;
258  first_sample_rate = s->streams[as->streams[0]]->codecpar->sample_rate;
259  for (i = 1; i < as->nb_streams; i++)
260  if (first_sample_rate != s->streams[as->streams[i]]->codecpar->sample_rate)
261  return 0;
262  return 1;
263 }
264 
267  int i;
268  for (i = 0; i < w->nb_as; i++) {
269  av_freep(&w->as[i].streams);
270  }
271  av_freep(&w->as);
272  w->nb_as = 0;
273 }
274 
275 /*
276  * Parses a live header filename and computes the representation id,
277  * initialization pattern and the media pattern. Pass NULL if you don't want to
278  * compute any of those 3. Returns 0 on success and non-zero on failure.
279  *
280  * Name of the header file should conform to the following pattern:
281  * <file_description>_<representation_id>.hdr where <file_description> can be
282  * anything. The chunks should be named according to the following pattern:
283  * <file_description>_<representation_id>_<chunk_number>.chk
284  */
285 static int parse_filename(char *filename, char **representation_id,
286  char **initialization_pattern, char **media_pattern) {
287  char *underscore_pos = NULL;
288  char *period_pos = NULL;
289  char *temp_pos = NULL;
290  char *filename_str = av_strdup(filename);
291  int ret = 0;
292 
293  if (!filename_str) {
294  ret = AVERROR(ENOMEM);
295  goto end;
296  }
297  temp_pos = av_stristr(filename_str, "_");
298  while (temp_pos) {
299  underscore_pos = temp_pos + 1;
300  temp_pos = av_stristr(temp_pos + 1, "_");
301  }
302  if (!underscore_pos) {
303  ret = AVERROR_INVALIDDATA;
304  goto end;
305  }
306  period_pos = av_stristr(underscore_pos, ".");
307  if (!period_pos) {
308  ret = AVERROR_INVALIDDATA;
309  goto end;
310  }
311  *(underscore_pos - 1) = 0;
312  if (representation_id) {
313  *representation_id = av_malloc(period_pos - underscore_pos + 1);
314  if (!(*representation_id)) {
315  ret = AVERROR(ENOMEM);
316  goto end;
317  }
318  av_strlcpy(*representation_id, underscore_pos, period_pos - underscore_pos + 1);
319  }
320  if (initialization_pattern) {
321  *initialization_pattern = av_asprintf("%s_$RepresentationID$.hdr",
322  filename_str);
323  if (!(*initialization_pattern)) {
324  ret = AVERROR(ENOMEM);
325  goto end;
326  }
327  }
328  if (media_pattern) {
329  *media_pattern = av_asprintf("%s_$RepresentationID$_$Number$.chk",
330  filename_str);
331  if (!(*media_pattern)) {
332  ret = AVERROR(ENOMEM);
333  goto end;
334  }
335  }
336 
337 end:
338  av_freep(&filename_str);
339  return ret;
340 }
341 
342 /*
343  * Writes an Adaptation Set. Returns 0 on success and < 0 on failure.
344  */
345 static int write_adaptation_set(AVFormatContext *s, int as_index)
346 {
348  AdaptationSet *as = &w->as[as_index];
349  AVCodecParameters *par = s->streams[as->streams[0]]->codecpar;
350  AVDictionaryEntry *lang;
351  int i;
352  static const char boolean[2][6] = { "false", "true" };
353  int subsegmentStartsWithSAP = 1;
354 
355  // Width, Height and Sample Rate will go in the AdaptationSet tag if they
356  // are the same for all contained Representations. otherwise, they will go
357  // on their respective Representation tag. For live streams, they always go
358  // in the Representation tag.
359  int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
360  if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
361  width_in_as = !w->is_live && check_matching_width(s, as);
362  height_in_as = !w->is_live && check_matching_height(s, as);
363  } else {
364  sample_rate_in_as = !w->is_live && check_matching_sample_rate(s, as);
365  }
366 
367  avio_printf(s->pb, "<AdaptationSet id=\"%s\"", as->id);
368  avio_printf(s->pb, " mimeType=\"%s/webm\"",
369  par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
370  avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(par->codec_id));
371 
372  lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0);
373  if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value);
374 
375  if (par->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as)
376  avio_printf(s->pb, " width=\"%d\"", par->width);
377  if (par->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as)
378  avio_printf(s->pb, " height=\"%d\"", par->height);
379  if (par->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as)
380  avio_printf(s->pb, " audioSamplingRate=\"%d\"", par->sample_rate);
381 
382  avio_printf(s->pb, " bitstreamSwitching=\"%s\"",
383  boolean[bitstream_switching(s, as)]);
384  avio_printf(s->pb, " subsegmentAlignment=\"%s\"",
385  boolean[w->is_live || subsegment_alignment(s, as)]);
386 
387  for (i = 0; i < as->nb_streams; i++) {
389  CLUSTER_KEYFRAME, NULL, 0);
390  if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0;
391  }
392  avio_printf(s->pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
393  avio_printf(s->pb, ">\n");
394 
395  if (w->is_live) {
396  AVDictionaryEntry *filename =
397  av_dict_get(s->streams[as->streams[0]]->metadata, FILENAME, NULL, 0);
398  char *initialization_pattern = NULL;
399  char *media_pattern = NULL;
400  int ret = parse_filename(filename->value, NULL, &initialization_pattern,
401  &media_pattern);
402  if (ret) return ret;
403  avio_printf(s->pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n",
404  par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
405  avio_printf(s->pb, "<SegmentTemplate");
406  avio_printf(s->pb, " timescale=\"1000\"");
407  avio_printf(s->pb, " duration=\"%d\"", w->chunk_duration);
408  avio_printf(s->pb, " media=\"%s\"", media_pattern);
409  avio_printf(s->pb, " startNumber=\"%d\"", w->chunk_start_index);
410  avio_printf(s->pb, " initialization=\"%s\"", initialization_pattern);
411  avio_printf(s->pb, "/>\n");
412  av_free(initialization_pattern);
413  av_free(media_pattern);
414  }
415 
416  for (i = 0; i < as->nb_streams; i++) {
417  char *representation_id = NULL;
418  int ret;
419  if (w->is_live) {
420  AVDictionaryEntry *filename =
421  av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0);
422  if (!filename)
423  return AVERROR(EINVAL);
424  if (ret = parse_filename(filename->value, &representation_id, NULL, NULL))
425  return ret;
426  } else {
427  representation_id = av_asprintf("%d", w->representation_id++);
428  if (!representation_id) return AVERROR(ENOMEM);
429  }
430  ret = write_representation(s, s->streams[as->streams[i]],
431  representation_id, !width_in_as,
432  !height_in_as, !sample_rate_in_as);
433  av_free(representation_id);
434  if (ret) return ret;
435  }
436  avio_printf(s->pb, "</AdaptationSet>\n");
437  return 0;
438 }
439 
440 static int to_integer(char *p, int len)
441 {
442  int ret;
443  char *q = av_malloc(sizeof(char) * len);
444  if (!q)
445  return AVERROR(ENOMEM);
446  av_strlcpy(q, p, len);
447  ret = atoi(q);
448  av_free(q);
449  return ret;
450 }
451 
453 {
455  char *p = w->adaptation_sets;
456  char *q;
457  enum { new_set, parsed_id, parsing_streams } state;
458  if (!w->adaptation_sets) {
459  av_log(s, AV_LOG_ERROR, "The 'adaptation_sets' option must be set.\n");
460  return AVERROR(EINVAL);
461  }
462  // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
463  state = new_set;
464  while (p < w->adaptation_sets + strlen(w->adaptation_sets)) {
465  if (*p == ' ')
466  continue;
467  else if (state == new_set && !strncmp(p, "id=", 3)) {
468  void *mem = av_realloc(w->as, sizeof(*w->as) * (w->nb_as + 1));
469  const char *comma;
470  if (mem == NULL)
471  return AVERROR(ENOMEM);
472  w->as = mem;
473  ++w->nb_as;
474  w->as[w->nb_as - 1].nb_streams = 0;
475  w->as[w->nb_as - 1].streams = NULL;
476  p += 3; // consume "id="
477  q = w->as[w->nb_as - 1].id;
478  comma = strchr(p, ',');
479  if (!comma || comma - p >= sizeof(w->as[w->nb_as - 1].id)) {
480  av_log(s, AV_LOG_ERROR, "'id' in 'adaptation_sets' is malformed.\n");
481  return AVERROR(EINVAL);
482  }
483  while (*p != ',') *q++ = *p++;
484  *q = 0;
485  p++;
486  state = parsed_id;
487  } else if (state == parsed_id && !strncmp(p, "streams=", 8)) {
488  p += 8; // consume "streams="
489  state = parsing_streams;
490  } else if (state == parsing_streams) {
491  struct AdaptationSet *as = &w->as[w->nb_as - 1];
492  q = p;
493  while (*q != '\0' && *q != ',' && *q != ' ') q++;
494  as->streams = av_realloc(as->streams, sizeof(*as->streams) * ++as->nb_streams);
495  if (as->streams == NULL)
496  return AVERROR(ENOMEM);
497  as->streams[as->nb_streams - 1] = to_integer(p, q - p + 1);
498  if (as->streams[as->nb_streams - 1] < 0 ||
499  as->streams[as->nb_streams - 1] >= s->nb_streams) {
500  av_log(s, AV_LOG_ERROR, "Invalid value for 'streams' in adapation_sets.\n");
501  return AVERROR(EINVAL);
502  }
503  if (*q == '\0') break;
504  if (*q == ' ') state = new_set;
505  p = ++q;
506  } else {
507  return -1;
508  }
509  }
510  return 0;
511 }
512 
514 {
515  int i;
516  double start = 0.0;
517  int ret;
519  ret = parse_adaptation_sets(s);
520  if (ret < 0) {
521  goto fail;
522  }
523  ret = write_header(s);
524  if (ret < 0) {
525  goto fail;
526  }
527  avio_printf(s->pb, "<Period id=\"0\"");
528  avio_printf(s->pb, " start=\"PT%gS\"", start);
529  if (!w->is_live) {
530  avio_printf(s->pb, " duration=\"PT%gS\"", get_duration(s));
531  }
532  avio_printf(s->pb, " >\n");
533 
534  for (i = 0; i < w->nb_as; i++) {
535  ret = write_adaptation_set(s, i);
536  if (ret < 0) {
537  goto fail;
538  }
539  }
540 
541  avio_printf(s->pb, "</Period>\n");
542  write_footer(s);
543 fail:
545  return ret < 0 ? ret : 0;
546 }
547 
549 {
550  return AVERROR_EOF;
551 }
552 
554 {
556  return 0;
557 }
558 
559 #define OFFSET(x) offsetof(WebMDashMuxContext, x)
560 static const AVOption options[] = {
561  { "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 },
562  { "debug_mode", "[private option - users should never set this]. Create deterministic output", OFFSET(debug_mode), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
563  { "live", "create a live stream manifest", OFFSET(is_live), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
564  { "chunk_start_index", "start index of the chunk", OFFSET(chunk_start_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
565  { "chunk_duration_ms", "duration of each chunk (in milliseconds)", OFFSET(chunk_duration), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
566  { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
567  { "time_shift_buffer_depth", "Smallest time (in seconds) shifting buffer for which any Representation is guaranteed to be available.", OFFSET(time_shift_buffer_depth), AV_OPT_TYPE_DOUBLE, { .dbl = 60.0 }, 1.0, DBL_MAX, AV_OPT_FLAG_ENCODING_PARAM },
568  { "minimum_update_period", "Minimum Update Period (in seconds) of the manifest.", OFFSET(minimum_update_period), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
569  { NULL },
570 };
571 
572 #if CONFIG_WEBM_DASH_MANIFEST_MUXER
573 static const AVClass webm_dash_class = {
574  .class_name = "WebM DASH Manifest muxer",
575  .item_name = av_default_item_name,
576  .option = options,
577  .version = LIBAVUTIL_VERSION_INT,
578 };
579 
581  .name = "webm_dash_manifest",
582  .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"),
583  .mime_type = "application/xml",
584  .extensions = "xml",
585  .priv_data_size = sizeof(WebMDashMuxContext),
589  .priv_class = &webm_dash_class,
590 };
591 #endif
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:689
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
AVOption.
Definition: opt.h:246
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:135
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
#define INITIALIZATION_RANGE
Definition: matroska.h:371
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle...
Definition: avstring.c:56
enum AVCodecID codec_id
Definition: qsv.c:77
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3957
static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:138
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
static AVPacket pkt
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3949
static struct @315 state
Format I/O context.
Definition: avformat.h:1358
#define gmtime_r
Definition: time_internal.h:34
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
Public dictionary API.
int mem
Definition: avisynth_c.h:916
#define av_malloc(s)
int width
Video only.
Definition: avcodec.h:4023
AVOptions.
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
#define TRACK_NUMBER
Definition: matroska.h:379
AdaptationSet * as
Definition: webmdashenc.c:51
AVOutputFormat ff_webm_dash_manifest_muxer
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1426
int64_t duration
Definition: movenc.c:63
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:40
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define max(a, b)
Definition: cuda_runtime.h:33
#define av_log(a,...)
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:276
#define FILENAME
Definition: matroska.h:374
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
static const AVOption options[]
Definition: webmdashenc.c:560
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
static int webm_dash_manifest_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: webmdashenc.c:548
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3953
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:83
#define fail()
Definition: checkasm.h:120
static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:255
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:3975
static int webm_dash_manifest_write_header(AVFormatContext *s)
Definition: webmdashenc.c:513
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1414
static int write_header(AVFormatContext *s)
Definition: webmdashenc.c:91
static int webm_dash_manifest_write_trailer(AVFormatContext *s)
Definition: webmdashenc.c:553
double time_shift_buffer_depth
Definition: webmdashenc.c:58
#define OFFSET(x)
Definition: webmdashenc.c:559
static void write_footer(AVFormatContext *s)
Definition: webmdashenc.c:133
uint8_t w
Definition: llviddspenc.c:38
char * adaptation_sets
Definition: webmdashenc.c:50
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
#define CLUSTER_KEYFRAME
Definition: matroska.h:377
const char * name
Definition: avformat.h:505
static double get_duration(AVFormatContext *s)
Definition: webmdashenc.c:78
#define DURATION
Definition: matroska.h:376
#define s(width, name)
Definition: cbs_vp9.c:257
static const char * get_codec_name(int codec_id)
Definition: webmdashenc.c:63
AVDictionary * metadata
Definition: avformat.h:945
static int to_integer(char *p, int len)
Definition: webmdashenc.c:440
Stream structure.
Definition: avformat.h:881
#define CUES_END
Definition: matroska.h:373
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:251
#define BANDWIDTH
Definition: matroska.h:375
AVIOContext * pb
I/O context.
Definition: avformat.h:1400
#define CUE_TIMESTAMPS
Definition: matroska.h:378
static const AVClass webm_dash_class
Definition: matroskadec.c:4222
Describe the class of an AVClass context structure.
Definition: log.h:67
static int parse_filename(char *filename, char **representation_id, char **initialization_pattern, char **media_pattern)
Definition: webmdashenc.c:285
static int check_matching_height(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:242
static void free_adaptation_sets(AVFormatContext *s)
Definition: webmdashenc.c:265
int sample_rate
Audio only.
Definition: avcodec.h:4067
Main libavformat public API header.
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
char id[10]
Definition: dashenc.c:71
#define av_free(p)
char * value
Definition: dict.h:87
int len
void * priv_data
Format private data.
Definition: avformat.h:1386
static int write_adaptation_set(AVFormatContext *s, int as_index)
Definition: webmdashenc.c:345
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3971
static int bitstream_switching(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:151
#define av_freep(p)
void INT64 start
Definition: avisynth_c.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1028
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
static int parse_adaptation_sets(AVFormatContext *s)
Definition: webmdashenc.c:452
static int check_matching_width(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:229
#define CUES_START
Definition: matroska.h:372
This structure stores compressed data.
Definition: avcodec.h:1454
static int write_representation(AVFormatContext *s, AVStream *stream, char *id, int output_width, int output_height, int output_sample_rate)
Definition: webmdashenc.c:176
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.