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++) {
83  AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata,
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 {
93  WebMDashMuxContext *w = s->priv_data;
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:mpeg: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;
140  AVDictionaryEntry *gold = av_dict_get(s->streams[as->streams[0]]->metadata,
141  CUE_TIMESTAMPS, NULL, 0);
142  if (!gold) return 0;
143  for (i = 1; i < as->nb_streams; i++) {
144  AVDictionaryEntry *ts = av_dict_get(s->streams[as->streams[i]]->metadata,
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) {
179  WebMDashMuxContext *w = s->priv_data;
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 
266  WebMDashMuxContext *w = s->priv_data;
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) {
304  goto end;
305  }
306  period_pos = av_stristr(underscore_pos, ".");
307  if (!period_pos) {
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 {
347  WebMDashMuxContext *w = s->priv_data;
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++) {
388  AVDictionaryEntry *kf = av_dict_get(s->streams[as->streams[i]]->metadata,
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 {
454  WebMDashMuxContext *w = s->priv_data;
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  int ret = av_reallocp_array(&as->streams, ++as->nb_streams,
493  sizeof(*as->streams));
494  if (ret < 0)
495  return ret;
496  q = p;
497  while (*q != '\0' && *q != ',' && *q != ' ') q++;
498  as->streams[as->nb_streams - 1] = to_integer(p, q - p + 1);
499  if (as->streams[as->nb_streams - 1] < 0 ||
500  as->streams[as->nb_streams - 1] >= s->nb_streams) {
501  av_log(s, AV_LOG_ERROR, "Invalid value for 'streams' in adapation_sets.\n");
502  return AVERROR(EINVAL);
503  }
504  if (*q == '\0') break;
505  if (*q == ' ') state = new_set;
506  p = ++q;
507  } else {
508  return -1;
509  }
510  }
511  return 0;
512 }
513 
515 {
516  int i;
517  double start = 0.0;
518  int ret;
519  WebMDashMuxContext *w = s->priv_data;
520 
521  for (unsigned i = 0; i < s->nb_streams; i++) {
522  enum AVCodecID codec_id = s->streams[i]->codecpar->codec_id;
525  return AVERROR(EINVAL);
526  }
527 
529  if (ret < 0) {
530  goto fail;
531  }
532  ret = write_header(s);
533  if (ret < 0) {
534  goto fail;
535  }
536  avio_printf(s->pb, "<Period id=\"0\"");
537  avio_printf(s->pb, " start=\"PT%gS\"", start);
538  if (!w->is_live) {
539  avio_printf(s->pb, " duration=\"PT%gS\"", get_duration(s));
540  }
541  avio_printf(s->pb, " >\n");
542 
543  for (i = 0; i < w->nb_as; i++) {
545  if (ret < 0) {
546  goto fail;
547  }
548  }
549 
550  avio_printf(s->pb, "</Period>\n");
551  write_footer(s);
552 fail:
554  return ret < 0 ? ret : 0;
555 }
556 
558 {
559  return AVERROR_EOF;
560 }
561 
563 {
565  return 0;
566 }
567 
568 #define OFFSET(x) offsetof(WebMDashMuxContext, x)
569 static const AVOption options[] = {
570  { "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 },
571  { "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 },
572  { "live", "create a live stream manifest", OFFSET(is_live), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
573  { "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 },
574  { "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 },
575  { "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 },
576  { "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 },
577  { "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 },
578  { NULL },
579 };
580 
581 #if CONFIG_WEBM_DASH_MANIFEST_MUXER
582 static const AVClass webm_dash_class = {
583  .class_name = "WebM DASH Manifest muxer",
584  .item_name = av_default_item_name,
585  .option = options,
586  .version = LIBAVUTIL_VERSION_INT,
587 };
588 
590  .name = "webm_dash_manifest",
591  .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"),
592  .mime_type = "application/xml",
593  .extensions = "xml",
594  .priv_data_size = sizeof(WebMDashMuxContext),
598  .priv_class = &webm_dash_class,
599 };
600 #endif
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3971
AVOutputFormat::name
const char * name
Definition: avformat.h:496
AVERROR
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
opt.h
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3953
codec_id
enum AVCodecID codec_id
Definition: qsv.c:72
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3949
av_stristr
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
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:55
write_representation
static int write_representation(AVFormatContext *s, AVStream *stream, char *id, int output_width, int output_height, int output_sample_rate)
Definition: webmdashenc.c:176
free_adaptation_sets
static void free_adaptation_sets(AVFormatContext *s)
Definition: webmdashenc.c:265
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
check_matching_width
static int check_matching_width(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:229
CUES_START
#define CUES_START
Definition: matroska.h:372
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
w
uint8_t w
Definition: llviddspenc.c:38
ff_webm_dash_manifest_muxer
AVOutputFormat ff_webm_dash_manifest_muxer
AVOption
AVOption.
Definition: opt.h:246
WebMDashMuxContext::debug_mode
int debug_mode
Definition: webmdashenc.c:60
write_footer
static void write_footer(AVFormatContext *s)
Definition: webmdashenc.c:133
matroska.h
float.h
AdaptationSet::id
char id[10]
Definition: dashenc.c:71
max
#define max(a, b)
Definition: cuda_runtime.h:33
AVERROR_UNKNOWN
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
mem
int mem
Definition: avisynth_c.h:916
AdaptationSet::nb_streams
int nb_streams
Definition: webmdashenc.c:45
fail
#define fail()
Definition: checkasm.h:120
start
void INT64 start
Definition: avisynth_c.h:767
webm_dash_class
static const AVClass webm_dash_class
Definition: matroskadec.c:4267
gmtime_r
#define gmtime_r
Definition: time_internal.h:34
AdaptationSet::streams
int * streams
Definition: webmdashenc.c:44
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
state
static struct @313 state
duration
int64_t duration
Definition: movenc.c:63
av_dict_get
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
webm_dash_manifest_write_packet
static int webm_dash_manifest_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: webmdashenc.c:557
s
#define s(width, name)
Definition: cbs_vp9.c:257
AV_OPT_FLAG_ENCODING_PARAM
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:276
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:225
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AV_CODEC_ID_VP9
@ AV_CODEC_ID_VP9
Definition: avcodec.h:386
AVCodecParameters::width
int width
Video only.
Definition: avcodec.h:4023
TRACK_NUMBER
#define TRACK_NUMBER
Definition: matroska.h:379
WebMDashMuxContext::representation_id
int representation_id
Definition: webmdashenc.c:53
get_duration
static double get_duration(AVFormatContext *s)
Definition: webmdashenc.c:78
CLUSTER_KEYFRAME
#define CLUSTER_KEYFRAME
Definition: matroska.h:377
write_header
static int write_header(AVFormatContext *s)
Definition: webmdashenc.c:91
get_codec_name
static const char * get_codec_name(int codec_id)
Definition: webmdashenc.c:63
time_internal.h
WebMDashMuxContext::is_live
int is_live
Definition: webmdashenc.c:54
AVFormatContext
Format I/O context.
Definition: avformat.h:1342
parse_adaptation_sets
static int parse_adaptation_sets(AVFormatContext *s)
Definition: webmdashenc.c:452
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1017
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
WebMDashMuxContext::chunk_duration
int chunk_duration
Definition: webmdashenc.c:56
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
NULL
#define NULL
Definition: coverity.c:32
subsegment_alignment
static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:138
write_trailer
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
WebMDashMuxContext::adaptation_sets
char * adaptation_sets
Definition: webmdashenc.c:50
AVStream::metadata
AVDictionary * metadata
Definition: avformat.h:934
WebMDashMuxContext
Definition: webmdashenc.c:48
CUES_END
#define CUES_END
Definition: matroska.h:373
AVCodecParameters::sample_rate
int sample_rate
Audio only.
Definition: avcodec.h:4067
webm_dash_manifest_write_header
static int webm_dash_manifest_write_header(AVFormatContext *s)
Definition: webmdashenc.c:514
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:215
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:3975
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
WebMDashMuxContext::nb_as
int nb_as
Definition: webmdashenc.c:52
webm_dash_manifest_write_trailer
static int webm_dash_manifest_write_trailer(AVFormatContext *s)
Definition: webmdashenc.c:562
AV_CODEC_ID_OPUS
@ AV_CODEC_ID_OPUS
Definition: avcodec.h:624
INITIALIZATION_RANGE
#define INITIALIZATION_RANGE
Definition: matroska.h:371
av_reallocp_array
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate, or free an array through a pointer to a pointer.
Definition: mem.c:205
OFFSET
#define OFFSET(x)
Definition: webmdashenc.c:568
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:135
write_packet
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:690
FILENAME
#define FILENAME
Definition: matroska.h:374
WebMDashMuxContext::chunk_start_index
int chunk_start_index
Definition: webmdashenc.c:55
AVOutputFormat
Definition: avformat.h:495
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
avio_internal.h
BANDWIDTH
#define BANDWIDTH
Definition: matroska.h:375
AVCodecParameters::height
int height
Definition: avcodec.h:4024
DURATION
#define DURATION
Definition: matroska.h:376
AdaptationSet
Definition: dashenc.c:70
CUE_TIMESTAMPS
#define CUE_TIMESTAMPS
Definition: matroska.h:378
len
int len
Definition: vorbis_enc_data.h:452
write_adaptation_set
static int write_adaptation_set(AVFormatContext *s, int as_index)
Definition: webmdashenc.c:345
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:870
parse_filename
static int parse_filename(char *filename, char **representation_id, char **initialization_pattern, char **media_pattern)
Definition: webmdashenc.c:285
AVClass::class_name
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
options
static const AVOption options[]
Definition: webmdashenc.c:569
WebMDashMuxContext::minimum_update_period
int minimum_update_period
Definition: webmdashenc.c:59
avformat.h
dict.h
avio_printf
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
pkt
static AVPacket pkt
Definition: demuxing_decoding.c:54
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:223
WebMDashMuxContext::time_shift_buffer_depth
double time_shift_buffer_depth
Definition: webmdashenc.c:58
bitstream_switching
static int bitstream_switching(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:151
check_matching_sample_rate
static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:255
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:251
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
check_matching_height
static int check_matching_height(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:242
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:81
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3957
AVPacket
This structure stores compressed data.
Definition: avcodec.h:1454
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:240
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AV_CODEC_ID_VP8
@ AV_CODEC_ID_VP8
Definition: avcodec.h:358
av_strlcpy
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
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
to_integer
static int to_integer(char *p, int len)
Definition: webmdashenc.c:440
AV_CODEC_ID_VORBIS
@ AV_CODEC_ID_VORBIS
Definition: avcodec.h:569
AVDictionaryEntry::value
char * value
Definition: dict.h:83
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:227
WebMDashMuxContext::as
AdaptationSet * as
Definition: webmdashenc.c:51
WebMDashMuxContext::utc_timing_url
char * utc_timing_url
Definition: webmdashenc.c:57