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 "matroska.h"
35 
36 #include "libavutil/avstring.h"
37 #include "libavutil/dict.h"
38 #include "libavutil/opt.h"
40 
41 typedef struct AdaptationSet {
42  char id[10];
43  int *streams;
44  int nb_streams;
46 
47 typedef struct WebMDashMuxContext {
48  const AVClass *class;
51  int nb_as;
53  int is_live;
60 
61 static const char *get_codec_name(int codec_id)
62 {
63  return avcodec_descriptor_get(codec_id)->name;
64 }
65 
67 {
68  int i = 0;
69  double max = 0.0;
70  for (i = 0; i < s->nb_streams; i++) {
72  DURATION, NULL, 0);
73  if (!duration || atof(duration->value) < 0) continue;
74  if (atof(duration->value) > max) max = atof(duration->value);
75  }
76  return max / 1000;
77 }
78 
80 {
82  double min_buffer_time = 1.0;
83  avio_printf(s->pb, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
84  avio_printf(s->pb, "<MPD\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");
88  avio_printf(s->pb, " type=\"%s\"\n", w->is_live ? "dynamic" : "static");
89  if (!w->is_live) {
90  avio_printf(s->pb, " mediaPresentationDuration=\"PT%gS\"\n",
91  get_duration(s));
92  }
93  avio_printf(s->pb, " minBufferTime=\"PT%gS\"\n", min_buffer_time);
94  avio_printf(s->pb, " profiles=\"%s\"%s",
95  w->is_live ? "urn:mpeg:dash:profile:isoff-live:2011" : "urn:webm:dash:profile:webm-on-demand:2012",
96  w->is_live ? "\n" : ">\n");
97  if (w->is_live) {
98  time_t local_time = time(NULL);
99  struct tm gmt_buffer;
100  struct tm *gmt = gmtime_r(&local_time, &gmt_buffer);
101  char gmt_iso[21];
102  if (!strftime(gmt_iso, 21, "%Y-%m-%dT%H:%M:%SZ", gmt)) {
103  return AVERROR_UNKNOWN;
104  }
105  if (s->flags & AVFMT_FLAG_BITEXACT) {
106  av_strlcpy(gmt_iso, "", 1);
107  }
108  avio_printf(s->pb, " availabilityStartTime=\"%s\"\n", gmt_iso);
109  avio_printf(s->pb, " timeShiftBufferDepth=\"PT%gS\"\n", w->time_shift_buffer_depth);
110  avio_printf(s->pb, " minimumUpdatePeriod=\"PT%dS\"", w->minimum_update_period);
111  avio_printf(s->pb, ">\n");
112  if (w->utc_timing_url) {
113  avio_printf(s->pb, "<UTCTiming\n");
114  avio_printf(s->pb, " schemeIdUri=\"urn:mpeg:dash:utc:http-iso:2014\"\n");
115  avio_printf(s->pb, " value=\"%s\"/>\n", w->utc_timing_url);
116  }
117  }
118  return 0;
119 }
120 
122 {
123  avio_printf(s->pb, "</MPD>\n");
124 }
125 
127  int i;
129  CUE_TIMESTAMPS, NULL, 0);
130  if (!gold) return 0;
131  for (i = 1; i < as->nb_streams; i++) {
133  CUE_TIMESTAMPS, NULL, 0);
134  if (!ts || strncmp(gold->value, ts->value, strlen(gold->value))) return 0;
135  }
136  return 1;
137 }
138 
140  int i;
141  AVDictionaryEntry *gold_track_num = av_dict_get(s->streams[as->streams[0]]->metadata,
142  TRACK_NUMBER, NULL, 0);
143  AVCodecParameters *gold_par = s->streams[as->streams[0]]->codecpar;
144  if (!gold_track_num) return 0;
145  for (i = 1; i < as->nb_streams; i++) {
146  AVDictionaryEntry *track_num = av_dict_get(s->streams[as->streams[i]]->metadata,
147  TRACK_NUMBER, NULL, 0);
149  if (!track_num ||
150  strncmp(gold_track_num->value, track_num->value, strlen(gold_track_num->value)) ||
151  gold_par->codec_id != par->codec_id ||
152  gold_par->extradata_size != par->extradata_size ||
153  memcmp(gold_par->extradata, par->extradata, par->extradata_size)) {
154  return 0;
155  }
156  }
157  return 1;
158 }
159 
160 /*
161  * Writes a Representation within an Adaptation Set. Returns 0 on success and
162  * < 0 on failure.
163  */
164 static int write_representation(AVFormatContext *s, AVStream *stream, char *id,
165  int output_width, int output_height,
166  int output_sample_rate) {
169  AVDictionaryEntry *cues_start = av_dict_get(stream->metadata, CUES_START, NULL, 0);
170  AVDictionaryEntry *cues_end = av_dict_get(stream->metadata, CUES_END, NULL, 0);
171  AVDictionaryEntry *filename = av_dict_get(stream->metadata, FILENAME, NULL, 0);
172  AVDictionaryEntry *bandwidth = av_dict_get(stream->metadata, BANDWIDTH, NULL, 0);
173  const char *bandwidth_str;
174  if ((w->is_live && (!filename)) ||
175  (!w->is_live && (!irange || !cues_start || !cues_end || !filename || !bandwidth))) {
176  return AVERROR_INVALIDDATA;
177  }
178  avio_printf(s->pb, "<Representation id=\"%s\"", id);
179  // if bandwidth for live was not provided, use a default
180  if (w->is_live && !bandwidth) {
181  bandwidth_str = (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ? "128000" : "1000000";
182  } else {
183  bandwidth_str = bandwidth->value;
184  }
185  avio_printf(s->pb, " bandwidth=\"%s\"", bandwidth_str);
186  if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_width)
187  avio_printf(s->pb, " width=\"%d\"", stream->codecpar->width);
188  if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && output_height)
189  avio_printf(s->pb, " height=\"%d\"", stream->codecpar->height);
190  if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && output_sample_rate)
191  avio_printf(s->pb, " audioSamplingRate=\"%d\"", stream->codecpar->sample_rate);
192  if (w->is_live) {
193  // For live streams, Codec and Mime Type always go in the Representation tag.
194  avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(stream->codecpar->codec_id));
195  avio_printf(s->pb, " mimeType=\"%s/webm\"",
196  stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
197  // For live streams, subsegments always start with key frames. So this
198  // is always 1.
199  avio_printf(s->pb, " startsWithSAP=\"1\"");
200  avio_printf(s->pb, ">");
201  } else {
202  avio_printf(s->pb, ">\n");
203  avio_printf(s->pb, "<BaseURL>%s</BaseURL>\n", filename->value);
204  avio_printf(s->pb, "<SegmentBase\n");
205  avio_printf(s->pb, " indexRange=\"%s-%s\">\n", cues_start->value, cues_end->value);
206  avio_printf(s->pb, "<Initialization\n");
207  avio_printf(s->pb, " range=\"0-%s\" />\n", irange->value);
208  avio_printf(s->pb, "</SegmentBase>\n");
209  }
210  avio_printf(s->pb, "</Representation>\n");
211  return 0;
212 }
213 
214 /*
215  * Checks if width of all streams are the same. Returns 1 if true, 0 otherwise.
216  */
218  int first_width, i;
219  if (as->nb_streams < 2) return 1;
220  first_width = s->streams[as->streams[0]]->codecpar->width;
221  for (i = 1; i < as->nb_streams; i++)
222  if (first_width != s->streams[as->streams[i]]->codecpar->width)
223  return 0;
224  return 1;
225 }
226 
227 /*
228  * Checks if height of all streams are the same. Returns 1 if true, 0 otherwise.
229  */
231  int first_height, i;
232  if (as->nb_streams < 2) return 1;
233  first_height = s->streams[as->streams[0]]->codecpar->height;
234  for (i = 1; i < as->nb_streams; i++)
235  if (first_height != s->streams[as->streams[i]]->codecpar->height)
236  return 0;
237  return 1;
238 }
239 
240 /*
241  * Checks if sample rate of all streams are the same. Returns 1 if true, 0 otherwise.
242  */
244  int first_sample_rate, i;
245  if (as->nb_streams < 2) return 1;
246  first_sample_rate = s->streams[as->streams[0]]->codecpar->sample_rate;
247  for (i = 1; i < as->nb_streams; i++)
248  if (first_sample_rate != s->streams[as->streams[i]]->codecpar->sample_rate)
249  return 0;
250  return 1;
251 }
252 
255  int i;
256  for (i = 0; i < w->nb_as; i++) {
257  av_freep(&w->as[i].streams);
258  }
259  av_freep(&w->as);
260  w->nb_as = 0;
261 }
262 
263 /*
264  * Parses a live header filename and computes the representation id,
265  * initialization pattern and the media pattern. Pass NULL if you don't want to
266  * compute any of those 3. Returns 0 on success and non-zero on failure.
267  *
268  * Name of the header file should conform to the following pattern:
269  * <file_description>_<representation_id>.hdr where <file_description> can be
270  * anything. The chunks should be named according to the following pattern:
271  * <file_description>_<representation_id>_<chunk_number>.chk
272  */
273 static int parse_filename(char *filename, char **representation_id,
274  char **initialization_pattern, char **media_pattern) {
275  char *underscore_pos = NULL;
276  char *period_pos = NULL;
277  char *filename_str = av_strdup(filename);
278  int ret = 0;
279 
280  if (!filename_str) {
281  ret = AVERROR(ENOMEM);
282  goto end;
283  }
284  underscore_pos = strrchr(filename_str, '_');
285  if (!underscore_pos) {
286  ret = AVERROR_INVALIDDATA;
287  goto end;
288  }
289  period_pos = strchr(++underscore_pos, '.');
290  if (!period_pos) {
291  ret = AVERROR_INVALIDDATA;
292  goto end;
293  }
294  *(underscore_pos - 1) = 0;
295  if (representation_id) {
296  *representation_id = av_malloc(period_pos - underscore_pos + 1);
297  if (!(*representation_id)) {
298  ret = AVERROR(ENOMEM);
299  goto end;
300  }
301  av_strlcpy(*representation_id, underscore_pos, period_pos - underscore_pos + 1);
302  }
303  if (initialization_pattern) {
304  *initialization_pattern = av_asprintf("%s_$RepresentationID$.hdr",
305  filename_str);
306  if (!(*initialization_pattern)) {
307  ret = AVERROR(ENOMEM);
308  goto end;
309  }
310  }
311  if (media_pattern) {
312  *media_pattern = av_asprintf("%s_$RepresentationID$_$Number$.chk",
313  filename_str);
314  if (!(*media_pattern)) {
315  ret = AVERROR(ENOMEM);
316  goto end;
317  }
318  }
319 
320 end:
321  av_freep(&filename_str);
322  return ret;
323 }
324 
325 /*
326  * Writes an Adaptation Set. Returns 0 on success and < 0 on failure.
327  */
328 static int write_adaptation_set(AVFormatContext *s, int as_index)
329 {
331  AdaptationSet *as = &w->as[as_index];
333  AVDictionaryEntry *lang;
334  int i;
335  static const char boolean[2][6] = { "false", "true" };
336  int subsegmentStartsWithSAP = 1;
337 
338  // Width, Height and Sample Rate will go in the AdaptationSet tag if they
339  // are the same for all contained Representations. otherwise, they will go
340  // on their respective Representation tag. For live streams, they always go
341  // in the Representation tag.
342  int width_in_as = 1, height_in_as = 1, sample_rate_in_as = 1;
343  if (par->codec_type == AVMEDIA_TYPE_VIDEO) {
344  width_in_as = !w->is_live && check_matching_width(s, as);
345  height_in_as = !w->is_live && check_matching_height(s, as);
346  } else {
347  sample_rate_in_as = !w->is_live && check_matching_sample_rate(s, as);
348  }
349 
350  avio_printf(s->pb, "<AdaptationSet id=\"%s\"", as->id);
351  avio_printf(s->pb, " mimeType=\"%s/webm\"",
352  par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
353  avio_printf(s->pb, " codecs=\"%s\"", get_codec_name(par->codec_id));
354 
355  lang = av_dict_get(s->streams[as->streams[0]]->metadata, "language", NULL, 0);
356  if (lang) avio_printf(s->pb, " lang=\"%s\"", lang->value);
357 
358  if (par->codec_type == AVMEDIA_TYPE_VIDEO && width_in_as)
359  avio_printf(s->pb, " width=\"%d\"", par->width);
360  if (par->codec_type == AVMEDIA_TYPE_VIDEO && height_in_as)
361  avio_printf(s->pb, " height=\"%d\"", par->height);
362  if (par->codec_type == AVMEDIA_TYPE_AUDIO && sample_rate_in_as)
363  avio_printf(s->pb, " audioSamplingRate=\"%d\"", par->sample_rate);
364 
365  avio_printf(s->pb, " bitstreamSwitching=\"%s\"",
366  boolean[bitstream_switching(s, as)]);
367  avio_printf(s->pb, " subsegmentAlignment=\"%s\"",
368  boolean[w->is_live || subsegment_alignment(s, as)]);
369 
370  for (i = 0; i < as->nb_streams; i++) {
372  CLUSTER_KEYFRAME, NULL, 0);
373  if (!w->is_live && (!kf || !strncmp(kf->value, "0", 1))) subsegmentStartsWithSAP = 0;
374  }
375  avio_printf(s->pb, " subsegmentStartsWithSAP=\"%d\"", subsegmentStartsWithSAP);
376  avio_printf(s->pb, ">\n");
377 
378  if (w->is_live) {
379  AVDictionaryEntry *filename =
380  av_dict_get(s->streams[as->streams[0]]->metadata, FILENAME, NULL, 0);
381  char *initialization_pattern = NULL;
382  char *media_pattern = NULL;
383  int ret = parse_filename(filename->value, NULL, &initialization_pattern,
384  &media_pattern);
385  if (ret) return ret;
386  avio_printf(s->pb, "<ContentComponent id=\"1\" type=\"%s\"/>\n",
387  par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio");
388  avio_printf(s->pb, "<SegmentTemplate");
389  avio_printf(s->pb, " timescale=\"1000\"");
390  avio_printf(s->pb, " duration=\"%d\"", w->chunk_duration);
391  avio_printf(s->pb, " media=\"%s\"", media_pattern);
392  avio_printf(s->pb, " startNumber=\"%d\"", w->chunk_start_index);
393  avio_printf(s->pb, " initialization=\"%s\"", initialization_pattern);
394  avio_printf(s->pb, "/>\n");
395  av_free(initialization_pattern);
396  av_free(media_pattern);
397  }
398 
399  for (i = 0; i < as->nb_streams; i++) {
400  char *representation_id = NULL;
401  int ret;
402  if (w->is_live) {
403  AVDictionaryEntry *filename =
404  av_dict_get(s->streams[as->streams[i]]->metadata, FILENAME, NULL, 0);
405  if (!filename)
406  return AVERROR(EINVAL);
407  if (ret = parse_filename(filename->value, &representation_id, NULL, NULL))
408  return ret;
409  } else {
410  representation_id = av_asprintf("%d", w->representation_id++);
411  if (!representation_id) return AVERROR(ENOMEM);
412  }
413  ret = write_representation(s, s->streams[as->streams[i]],
414  representation_id, !width_in_as,
415  !height_in_as, !sample_rate_in_as);
416  av_free(representation_id);
417  if (ret) return ret;
418  }
419  avio_printf(s->pb, "</AdaptationSet>\n");
420  return 0;
421 }
422 
424 {
426  char *p = w->adaptation_sets;
427  char *q;
428  enum { new_set, parsed_id, parsing_streams } state;
429  if (!w->adaptation_sets) {
430  av_log(s, AV_LOG_ERROR, "The 'adaptation_sets' option must be set.\n");
431  return AVERROR(EINVAL);
432  }
433  // syntax id=0,streams=0,1,2 id=1,streams=3,4 and so on
434  state = new_set;
435  while (1) {
436  if (*p == '\0') {
437  if (state == new_set)
438  break;
439  else
440  return AVERROR(EINVAL);
441  } else if (state == new_set && *p == ' ') {
442  p++;
443  continue;
444  } else if (state == new_set && !strncmp(p, "id=", 3)) {
445  void *mem = av_realloc(w->as, sizeof(*w->as) * (w->nb_as + 1));
446  const char *comma;
447  if (mem == NULL)
448  return AVERROR(ENOMEM);
449  w->as = mem;
450  ++w->nb_as;
451  w->as[w->nb_as - 1].nb_streams = 0;
452  w->as[w->nb_as - 1].streams = NULL;
453  p += 3; // consume "id="
454  q = w->as[w->nb_as - 1].id;
455  comma = strchr(p, ',');
456  if (!comma || comma - p >= sizeof(w->as[w->nb_as - 1].id)) {
457  av_log(s, AV_LOG_ERROR, "'id' in 'adaptation_sets' is malformed.\n");
458  return AVERROR(EINVAL);
459  }
460  while (*p != ',') *q++ = *p++;
461  *q = 0;
462  p++;
463  state = parsed_id;
464  } else if (state == parsed_id && !strncmp(p, "streams=", 8)) {
465  p += 8; // consume "streams="
466  state = parsing_streams;
467  } else if (state == parsing_streams) {
468  struct AdaptationSet *as = &w->as[w->nb_as - 1];
469  int64_t num;
470  int ret = av_reallocp_array(&as->streams, ++as->nb_streams,
471  sizeof(*as->streams));
472  if (ret < 0)
473  return ret;
474  num = strtoll(p, &q, 10);
475  if (!av_isdigit(*p) || (*q != ' ' && *q != '\0' && *q != ',') ||
476  num < 0 || num >= s->nb_streams) {
477  av_log(s, AV_LOG_ERROR, "Invalid value for 'streams' in adapation_sets.\n");
478  return AVERROR(EINVAL);
479  }
480  as->streams[as->nb_streams - 1] = num;
481  if (*q == '\0') break;
482  if (*q == ' ') state = new_set;
483  p = ++q;
484  } else {
485  return -1;
486  }
487  }
488  return 0;
489 }
490 
492 {
493  int i;
494  double start = 0.0;
495  int ret;
497 
498  for (unsigned i = 0; i < s->nb_streams; i++) {
500  if (codec_id != AV_CODEC_ID_VP8 && codec_id != AV_CODEC_ID_VP9 &&
501  codec_id != AV_CODEC_ID_VORBIS && codec_id != AV_CODEC_ID_OPUS)
502  return AVERROR(EINVAL);
503  }
504 
505  ret = parse_adaptation_sets(s);
506  if (ret < 0) {
507  goto fail;
508  }
509  ret = write_header(s);
510  if (ret < 0) {
511  goto fail;
512  }
513  avio_printf(s->pb, "<Period id=\"0\"");
514  avio_printf(s->pb, " start=\"PT%gS\"", start);
515  if (!w->is_live) {
516  avio_printf(s->pb, " duration=\"PT%gS\"", get_duration(s));
517  }
518  avio_printf(s->pb, " >\n");
519 
520  for (i = 0; i < w->nb_as; i++) {
521  ret = write_adaptation_set(s, i);
522  if (ret < 0) {
523  goto fail;
524  }
525  }
526 
527  avio_printf(s->pb, "</Period>\n");
528  write_footer(s);
529 fail:
531  return ret < 0 ? ret : 0;
532 }
533 
535 {
536  return AVERROR_EOF;
537 }
538 
539 #define OFFSET(x) offsetof(WebMDashMuxContext, x)
540 static const AVOption options[] = {
541  { "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 },
542  { "live", "create a live stream manifest", OFFSET(is_live), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
543  { "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 },
544  { "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 },
545  { "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 },
546  { "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 },
547  { "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 },
548  { NULL },
549 };
550 
551 static const AVClass webm_dash_class = {
552  .class_name = "WebM DASH Manifest muxer",
553  .item_name = av_default_item_name,
554  .option = options,
555  .version = LIBAVUTIL_VERSION_INT,
556 };
557 
559  .name = "webm_dash_manifest",
560  .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"),
561  .mime_type = "application/xml",
562  .extensions = "xml",
563  .priv_data_size = sizeof(WebMDashMuxContext),
566  .priv_class = &webm_dash_class,
567 };
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:701
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static av_const int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition: avstring.h:206
AVOption.
Definition: opt.h:248
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:134
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
#define INITIALIZATION_RANGE
Definition: matroska.h:370
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
static int subsegment_alignment(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:126
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: codec_par.h:52
AVOutputFormat ff_webm_dash_manifest_muxer
Definition: webmdashenc.c:558
static struct @315 state
Format I/O context.
Definition: avformat.h:1351
#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.
#define av_malloc(s)
int width
Video only.
Definition: codec_par.h:126
AVOptions.
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
#define TRACK_NUMBER
Definition: matroska.h:378
AdaptationSet * as
Definition: webmdashenc.c:50
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1419
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:1482
#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:1499
#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:278
#define FILENAME
Definition: matroska.h:373
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:46
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
static const AVOption options[]
Definition: webmdashenc.c:540
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
static int webm_dash_manifest_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: webmdashenc.c:534
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
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:123
static int check_matching_sample_rate(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:243
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:78
static int webm_dash_manifest_write_header(AVFormatContext *s)
Definition: webmdashenc.c:491
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:206
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:113
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1407
static int write_header(AVFormatContext *s)
Definition: webmdashenc.c:79
double time_shift_buffer_depth
Definition: webmdashenc.c:57
#define OFFSET(x)
Definition: webmdashenc.c:539
static void write_footer(AVFormatContext *s)
Definition: webmdashenc.c:121
uint8_t w
Definition: llviddspenc.c:38
char * adaptation_sets
Definition: webmdashenc.c:49
#define CLUSTER_KEYFRAME
Definition: matroska.h:376
const char * name
Definition: avformat.h:500
static double get_duration(AVFormatContext *s)
Definition: webmdashenc.c:66
#define DURATION
Definition: matroska.h:375
#define s(width, name)
Definition: cbs_vp9.c:257
static const char * get_codec_name(int codec_id)
Definition: webmdashenc.c:61
AVDictionary * metadata
Definition: avformat.h:940
enum AVCodecID codec_id
Definition: vaapi_decode.c:369
AVRational par
Definition: dashenc.c:95
Stream structure.
Definition: avformat.h:876
#define CUES_END
Definition: matroska.h:372
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
#define BANDWIDTH
Definition: matroska.h:374
AVIOContext * pb
I/O context.
Definition: avformat.h:1393
int nb_streams
Definition: dashenc.c:94
#define CUE_TIMESTAMPS
Definition: matroska.h:377
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:273
static int check_matching_height(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:230
const char * name
Name of the codec described by this descriptor.
Definition: codec_desc.h:46
static void free_adaptation_sets(AVFormatContext *s)
Definition: webmdashenc.c:253
int sample_rate
Audio only.
Definition: codec_par.h:170
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
void * priv_data
Format private data.
Definition: avformat.h:1379
static const AVClass webm_dash_class
Definition: webmdashenc.c:551
static int write_adaptation_set(AVFormatContext *s, int as_index)
Definition: webmdashenc.c:328
const AVCodecDescriptor * avcodec_descriptor_get(enum AVCodecID id)
Definition: codec_desc.c:3401
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:74
static int bitstream_switching(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:139
#define av_freep(p)
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1023
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:423
static int check_matching_width(AVFormatContext *s, AdaptationSet *as)
Definition: webmdashenc.c:217
#define CUES_START
Definition: matroska.h:371
This structure stores compressed data.
Definition: packet.h:332
int i
Definition: input.c:406
static int write_representation(AVFormatContext *s, AVStream *stream, char *id, int output_width, int output_height, int output_sample_rate)
Definition: webmdashenc.c:164
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.