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;
45  int nb_streams;
47 
48 typedef struct WebMDashMuxContext {
49  const AVClass *class;
52  int nb_as;
54  int is_live;
61 
62 static const char *get_codec_name(int codec_id)
63 {
64  switch (codec_id) {
65  case AV_CODEC_ID_VP8:
66  return "vp8";
67  case AV_CODEC_ID_VP9:
68  return "vp9";
69  case AV_CODEC_ID_VORBIS:
70  return "vorbis";
71  case AV_CODEC_ID_OPUS:
72  return "opus";
73  }
74  return NULL;
75 }
76 
78 {
79  int i = 0;
80  double max = 0.0;
81  for (i = 0; i < s->nb_streams; i++) {
83  DURATION, NULL, 0);
84  if (!duration || atof(duration->value) < 0) continue;
85  if (atof(duration->value) > max) max = atof(duration->value);
86  }
87  return max / 1000;
88 }
89 
91 {
93  double min_buffer_time = 1.0;
94  avio_printf(s->pb, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
95  avio_printf(s->pb, "<MPD\n");
96  avio_printf(s->pb, " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
97  avio_printf(s->pb, " xmlns=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
98  avio_printf(s->pb, " xsi:schemaLocation=\"urn:mpeg:DASH:schema:MPD:2011\"\n");
99  avio_printf(s->pb, " type=\"%s\"\n", w->is_live ? "dynamic" : "static");
100  if (!w->is_live) {
101  avio_printf(s->pb, " mediaPresentationDuration=\"PT%gS\"\n",
102  get_duration(s));
103  }
104  avio_printf(s->pb, " minBufferTime=\"PT%gS\"\n", min_buffer_time);
105  avio_printf(s->pb, " profiles=\"%s\"%s",
106  w->is_live ? "urn:mpeg:dash:profile:isoff-live:2011" : "urn:webm:dash:profile:webm-on-demand:2012",
107  w->is_live ? "\n" : ">\n");
108  if (w->is_live) {
109  time_t local_time = time(NULL);
110  struct tm gmt_buffer;
111  struct tm *gmt = gmtime_r(&local_time, &gmt_buffer);
112  char gmt_iso[21];
113  if (!strftime(gmt_iso, 21, "%Y-%m-%dT%H:%M:%SZ", gmt)) {
114  return AVERROR_UNKNOWN;
115  }
116  if (s->flags & AVFMT_FLAG_BITEXACT) {
117  av_strlcpy(gmt_iso, "", 1);
118  }
119  avio_printf(s->pb, " availabilityStartTime=\"%s\"\n", gmt_iso);
120  avio_printf(s->pb, " timeShiftBufferDepth=\"PT%gS\"\n", w->time_shift_buffer_depth);
121  avio_printf(s->pb, " minimumUpdatePeriod=\"PT%dS\"", w->minimum_update_period);
122  avio_printf(s->pb, ">\n");
123  if (w->utc_timing_url) {
124  avio_printf(s->pb, "<UTCTiming\n");
125  avio_printf(s->pb, " schemeIdUri=\"urn:mpeg:dash:utc:http-iso:2014\"\n");
126  avio_printf(s->pb, " value=\"%s\"/>\n", w->utc_timing_url);
127  }
128  }
129  return 0;
130 }
131 
133 {
134  avio_printf(s->pb, "</MPD>\n");
135 }
136 
138  int i;
140  CUE_TIMESTAMPS, NULL, 0);
141  if (!gold) return 0;
142  for (i = 1; i < as->nb_streams; i++) {
144  CUE_TIMESTAMPS, NULL, 0);
145  if (!ts || strncmp(gold->value, ts->value, strlen(gold->value))) return 0;
146  }
147  return 1;
148 }
149 
151  int i;
152  AVDictionaryEntry *gold_track_num = av_dict_get(s->streams[as->streams[0]]->metadata,
153  TRACK_NUMBER, NULL, 0);
154  AVCodecParameters *gold_par = s->streams[as->streams[0]]->codecpar;
155  if (!gold_track_num) return 0;
156  for (i = 1; i < as->nb_streams; i++) {
157  AVDictionaryEntry *track_num = av_dict_get(s->streams[as->streams[i]]->metadata,
158  TRACK_NUMBER, NULL, 0);
160  if (!track_num ||
161  strncmp(gold_track_num->value, track_num->value, strlen(gold_track_num->value)) ||
162  gold_par->codec_id != par->codec_id ||
163  gold_par->extradata_size != par->extradata_size ||
164  memcmp(gold_par->extradata, par->extradata, par->extradata_size)) {
165  return 0;
166  }
167  }
168  return 1;
169 }
170 
171 /*
172  * Writes a Representation within an Adaptation Set. Returns 0 on success and
173  * < 0 on failure.
174  */
175 static int write_representation(AVFormatContext *s, AVStream *stream, char *id,
176  int output_width, int output_height,
177  int output_sample_rate) {
180  AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0);
181  AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0);
182  AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0);
183  AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0);
184  const char *bandwidth_str;
185  if ((w->is_live && (!filename)) ||
186  (!w->is_live && (!irange || !cues_start || !cues_end || !filename || !bandwidth))) {
187  return AVERROR_INVALIDDATA;
188  }
189  avio_printf(s->pb, "<Representation id=\"%s\"", id);
190  // if bandwidth for live was not provided, use a default
191  if (w->is_live && !bandwidth) {
192  bandwidth_str = (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ? "128000" : "1000000";
193  } else {
194  bandwidth_str = bandwidth->value;
195  }
196  avio_printf(s->pb, " bandwidth=\"%s\"", bandwidth_str);
197  if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_width)
198  avio_printf(s->pb, " width=\"%d\"", stream->codecpar->width);
199  if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_height)
200  avio_printf(s->pb, " height=\"%d\"", stream->codecpar->height);
201  if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && output_sample_rate)
202  avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codecpar->sample_rate);
203  if (w->is_live) {
204  // For live streams, Codec and Mime Type always go in the Representation tag.
205  avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(stream->codecpar->codec_id));
206  avio_printf(s->pb, " mimeType=\"%s/webm\"",
207  stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
208  // For live streams, subsegments always start with key frames. So this
209  // is always 1.
210  avio_printf(s->pb, " startsWithSAP=\"1\"");
211  avio_printf(s->pb, ">");
212  } else {
213  avio_printf(s->pb, ">\n");
214  avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value);
215  avio_printf(s->pb, "<SegmentBase\n");
216  avio_printf(s->pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value);
217  avio_printf(s->pb, "<Initialization\n");
218  avio_printf(s->pb, " range=\"0-%s\" />\n", irange->value);
219  avio_printf(s->pb, "</SegmentBase>\n");
220  }
221  avio_printf(s->pb, "</Representation>\n");
222  return 0;
223 }
224 
225 /*
226  * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise.
227  */
229  int first_width, i;
230  if (as->nb_streams < 2) return 1;
231  first_width = s->streams[as->streams[0]]->codecpar->width;
232  for (i = 1; i < as->nb_streams; i++)
233  if (first_width != s->streams[as->streams[i]]->codecpar->width)
234  return 0;
235  return 1;
236 }
237 
238 /*
239  * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise.
240  */
242  int first_height, i;
243  if (as->nb_streams < 2) return 1;
244  first_height = s->streams[as->streams[0]]->codecpar->height;
245  for (i = 1; i < as->nb_streams; i++)
246  if (first_height != s->streams[as->streams[i]]->codecpar->height)
247  return 0;
248  return 1;
249 }
250 
251 /*
252  * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise.
253  */
255  int first_sample_rate, i;
256  if (as->nb_streams < 2) return 1;
257  first_sample_rate = s->streams[as->streams[0]]->codecpar->sample_rate;
258  for (i = 1; i < as->nb_streams; i++)
259  if (first_sample_rate != s->streams[as->streams[i]]->codecpar->sample_rate)
260  return 0;
261  return 1;
262 }
263 
266  int i;
267  for (i = 0; i < w->nb_as; i++) {
268  av_freep(&w->as[i].streams);
269  }
270  av_freep(&w->as);
271  w->nb_as = 0;
272 }
273 
274 /*
275  * Parses a live header filename and computes the representation id,
276  * initialization pattern and the media pattern. Pass NULL if you don't want to
277  * compute any of those 3. Returns 0 on success and non-zero on failure.
278  *
279  * Name of the header file should conform to the following pattern:
280  * <file_description>_<representation_id>.hdr where <file_description> can be
281  * anything. The chunks should be named according to the following pattern:
282  * <file_description>_<representation_id>_<chunk_number>.chk
283  */
284 static int parse_filename(char *filename, char **representation_id,
285  char **initialization_pattern, char **media_pattern) {
286  char *underscore_pos = NULL;
287  char *period_pos = NULL;
288  char *temp_pos = NULL;
289  char *filename_str = av_strdup(filename);
290  int ret = 0;
291 
292  if (!filename_str) {
293  ret = AVERROR(ENOMEM);
294  goto end;
295  }
296  temp_pos = av_stristr(filename_str, "_");
297  while (temp_pos) {
298  underscore_pos = temp_pos + 1;
299  temp_pos = av_stristr(temp_pos + 1, "_");
300  }
301  if (!underscore_pos) {
302  ret = AVERROR_INVALIDDATA;
303  goto end;
304  }
305  period_pos = av_stristr(underscore_pos, ".");
306  if (!period_pos) {
307  ret = AVERROR_INVALIDDATA;
308  goto end;
309  }
310  *(underscore_pos - 1) = 0;
311  if (representation_id) {
312  *representation_id = av_malloc(period_pos - underscore_pos + 1);
313  if (!(*representation_id)) {
314  ret = AVERROR(ENOMEM);
315  goto end;
316  }
317  av_strlcpy(*representation_id, underscore_pos, period_pos - underscore_pos + 1);
318  }
319  if (initialization_pattern) {
320  *initialization_pattern = av_asprintf("%s_$RepresentationID$.hdr",
321  filename_str);
322  if (!(*initialization_pattern)) {
323  ret = AVERROR(ENOMEM);
324  goto end;
325  }
326  }
327  if (media_pattern) {
328  *media_pattern = av_asprintf("%s_$RepresentationID$_$Number$.chk",
329  filename_str);
330  if (!(*media_pattern)) {
331  ret = AVERROR(ENOMEM);
332  goto end;
333  }
334  }
335 
336 end:
337  av_freep(&filename_str);
338  return ret;
339 }
340 
341 /*
342  * Writes an Adaptation Set. Returns 0 on success and < 0 on failure.
343  */
344 static int write_adaptation_set(AVFormatContext *s, int as_index)
345 {
347  AdaptationSet *as = &w->as[as_index];
349  AVDictionaryEntry *lang;
350  int i;
351  static const char boolean[2][6] = { "false", "true" };
352  int subsegmentStartsWithSAP = 1;
353 
354  // Width, Height and Sample Rate will go in the AdaptationSet tag if they
355  // are the same for all contained Representations. otherwise, they will go
356  // on their respective Representation tag. For live streams, they always go
357  // in the Representation tag.
358  int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
359  if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
360  width_in_as = !w->is_live && check_matching_width(s, as);
361  height_in_as = !w->is_live && check_matching_height(s, as);
362  } else {
363  sample_rate_in_as = !w->is_live && check_matching_sample_rate(s, as);
364  }
365 
366  avio_printf(s->pb, "<AdaptationSet id=\"%s\"", as->id);
367  avio_printf(s->pb, " mimeType=\"%s/webm\"",
368  par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
369  avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(par->codec_id));
370 
371  lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0);
372  if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value);
373 
374  if (par->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as)
375  avio_printf(s->pb, " width=\"%d\"", par->width);
376  if (par->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as)
377  avio_printf(s->pb, " height=\"%d\"", par->height);
378  if (par->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as)
379  avio_printf(s->pb, " audioSamplingRate=\"%d\"", par->sample_rate);
380 
381  avio_printf(s->pb, " bitstreamSwitching=\"%s\"",
382  boolean[bitstream_switching(s, as)]);
383  avio_printf(s->pb, " subsegmentAlignment=\"%s\"",
384  boolean[w->is_live || subsegment_alignment(s, as)]);
385 
386  for (i = 0; i < as->nb_streams; i++) {
388  CLUSTER_KEYFRAME, NULL, 0);
389  if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0;
390  }
391  avio_printf(s->pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
392  avio_printf(s->pb, ">\n");
393 
394  if (w->is_live) {
395  AVDictionaryEntry *filename =
396  av_dict_get(s->streams[as->streams[0]]->metadata, FILENAME, NULL, 0);
397  char *initialization_pattern = NULL;
398  char *media_pattern = NULL;
399  int ret = parse_filename(filename->value, NULL, &initialization_pattern,
400  &media_pattern);
401  if (ret) return ret;
402  avio_printf(s->pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n",
403  par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
404  avio_printf(s->pb, "<SegmentTemplate");
405  avio_printf(s->pb, " timescale=\"1000\"");
406  avio_printf(s->pb, " duration=\"%d\"", w->chunk_duration);
407  avio_printf(s->pb, " media=\"%s\"", media_pattern);
408  avio_printf(s->pb, " startNumber=\"%d\"", w->chunk_start_index);
409  avio_printf(s->pb, " initialization=\"%s\"", initialization_pattern);
410  avio_printf(s->pb, "/>\n");
411  av_free(initialization_pattern);
412  av_free(media_pattern);
413  }
414 
415  for (i = 0; i < as->nb_streams; i++) {
416  char *representation_id = NULL;
417  int ret;
418  if (w->is_live) {
419  AVDictionaryEntry *filename =
420  av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0);
421  if (!filename)
422  return AVERROR(EINVAL);
423  if (ret = parse_filename(filename->value, &representation_id, NULL, NULL))
424  return ret;
425  } else {
426  representation_id = av_asprintf("%d", w->representation_id++);
427  if (!representation_id) return AVERROR(ENOMEM);
428  }
429  ret = write_representation(s, s->streams[as->streams[i]],
430  representation_id, !width_in_as,
431  !height_in_as, !sample_rate_in_as);
432  av_free(representation_id);
433  if (ret) return ret;
434  }
435  avio_printf(s->pb, "</AdaptationSet>\n");
436  return 0;
437 }
438 
439 static int to_integer(char *p, int len)
440 {
441  int ret;
442  char *q = av_malloc(sizeof(char) * len);
443  if (!q)
444  return AVERROR(ENOMEM);
445  av_strlcpy(q, p, len);
446  ret = atoi(q);
447  av_free(q);
448  return ret;
449 }
450 
452 {
454  char *p = w->adaptation_sets;
455  char *q;
456  enum { new_set, parsed_id, parsing_streams } state;
457  if (!w->adaptation_sets) {
458  av_log(s, AV_LOG_ERROR, "The 'adaptation_sets' option must be set.\n");
459  return AVERROR(EINVAL);
460  }
461  // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
462  state = new_set;
463  while (p < w->adaptation_sets + strlen(w->adaptation_sets)) {
464  if (*p == ' ')
465  continue;
466  else if (state == new_set && !strncmp(p, "id=", 3)) {
467  void *mem = av_realloc(w->as, sizeof(*w->as) * (w->nb_as + 1));
468  const char *comma;
469  if (mem == NULL)
470  return AVERROR(ENOMEM);
471  w->as = mem;
472  ++w->nb_as;
473  w->as[w->nb_as - 1].nb_streams = 0;
474  w->as[w->nb_as - 1].streams = NULL;
475  p += 3; // consume "id="
476  q = w->as[w->nb_as - 1].id;
477  comma = strchr(p, ',');
478  if (!comma || comma - p >= sizeof(w->as[w->nb_as - 1].id)) {
479  av_log(s, AV_LOG_ERROR, "'id' in 'adaptation_sets' is malformed.\n");
480  return AVERROR(EINVAL);
481  }
482  while (*p != ',') *q++ = *p++;
483  *q = 0;
484  p++;
485  state = parsed_id;
486  } else if (state == parsed_id && !strncmp(p, "streams=", 8)) {
487  p += 8; // consume "streams="
488  state = parsing_streams;
489  } else if (state == parsing_streams) {
490  struct AdaptationSet *as = &w->as[w->nb_as - 1];
491  int ret = av_reallocp_array(&as->streams, ++as->nb_streams,
492  sizeof(*as->streams));
493  if (ret < 0)
494  return ret;
495  q = p;
496  while (*q != '\0' && *q != ',' && *q != ' ') q++;
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 
553 #define OFFSET(x) offsetof(WebMDashMuxContext, x)
554 static const AVOption options[] = {
555  { "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 },
556  { "live", "create a live stream manifest", OFFSET(is_live), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
557  { "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 },
558  { "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 },
559  { "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 },
560  { "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 },
561  { "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 },
562  { NULL },
563 };
564 
565 #if CONFIG_WEBM_DASH_MANIFEST_MUXER
566 static const AVClass webm_dash_class = {
567  .class_name = "WebM DASH Manifest muxer",
568  .item_name = av_default_item_name,
569  .option = options,
570  .version = LIBAVUTIL_VERSION_INT,
571 };
572 
574  .name = "webm_dash_manifest",
575  .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"),
576  .mime_type = "application/xml",
577  .extensions = "xml",
578  .priv_data_size = sizeof(WebMDashMuxContext),
581  .priv_class = &webm_dash_class,
582 };
583 #endif
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:698
#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:372
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
Specific type of the encoded data (the codec used).
Definition: avcodec.h:4036
static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:137
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
static AVPacket pkt
This struct describes the properties of an encoded stream.
Definition: avcodec.h:4028
Format I/O context.
Definition: avformat.h:1352
#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:4102
AVOptions.
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
#define TRACK_NUMBER
Definition: matroska.h:380
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:1420
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
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1483
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define max(a, b)
Definition: cuda_runtime.h:33
#define AVFMT_FLAG_BITEXACT
When muxing, try to avoid writing any random/volatile data to the output.
Definition: avformat.h:1500
#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:375
#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:554
#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:4032
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:122
static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:254
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:4054
static int webm_dash_manifest_write_header(AVFormatContext *s)
Definition: webmdashenc.c:513
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
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1408
static int write_header(AVFormatContext *s)
Definition: webmdashenc.c:90
double time_shift_buffer_depth
Definition: webmdashenc.c:58
#define OFFSET(x)
Definition: webmdashenc.c:553
static void write_footer(AVFormatContext *s)
Definition: webmdashenc.c:132
uint8_t w
Definition: llviddspenc.c:38
char * adaptation_sets
Definition: webmdashenc.c:50
#define CLUSTER_KEYFRAME
Definition: matroska.h:378
const char * name
Definition: avformat.h:500
static double get_duration(AVFormatContext *s)
Definition: webmdashenc.c:77
#define DURATION
Definition: matroska.h:377
#define s(width, name)
Definition: cbs_vp9.c:257
static const char * get_codec_name(int codec_id)
Definition: webmdashenc.c:62
AVDictionary * metadata
Definition: avformat.h:939
enum AVCodecID codec_id
Definition: vaapi_decode.c:369
AVRational par
Definition: dashenc.c:95
static int to_integer(char *p, int len)
Definition: webmdashenc.c:439
Stream structure.
Definition: avformat.h:875
#define CUES_END
Definition: matroska.h:374
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:251
#define BANDWIDTH
Definition: matroska.h:376
AVIOContext * pb
I/O context.
Definition: avformat.h:1394
int nb_streams
Definition: dashenc.c:94
#define CUE_TIMESTAMPS
Definition: matroska.h:379
static const AVClass webm_dash_class
Definition: matroskadec.c:4186
static struct @327 state
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:284
static int check_matching_height(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:241
static void free_adaptation_sets(AVFormatContext *s)
Definition: webmdashenc.c:264
int sample_rate
Audio only.
Definition: avcodec.h:4146
Main libavformat public API header.
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition: error.h:71
#define av_free(p)
char * value
Definition: dict.h:87
int len
void * priv_data
Format private data.
Definition: avformat.h:1380
static int write_adaptation_set(AVFormatContext *s, int as_index)
Definition: webmdashenc.c:344
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:4050
static int bitstream_switching(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:150
#define av_freep(p)
void INT64 start
Definition: avisynth_c.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1022
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:451
static int check_matching_width(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:228
#define CUES_START
Definition: matroska.h:373
This structure stores compressed data.
Definition: avcodec.h:1510
static int write_representation(AVFormatContext *s, AVStream *stream, char *id, int output_width, int output_height, int output_sample_rate)
Definition: webmdashenc.c:175
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.