FFmpeg
dashdec.c
Go to the documentation of this file.
1 /*
2  * Dynamic Adaptive Streaming over HTTP demux
3  * Copyright (c) 2017 samsamsam@o2.pl based on HLS demux
4  * Copyright (c) 2017 Steven Liu
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 #include <libxml/parser.h>
23 #include <time.h>
24 #include "libavutil/bprint.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/opt.h"
27 #include "libavutil/time.h"
28 #include "libavutil/parseutils.h"
29 #include "internal.h"
30 #include "avio_internal.h"
31 #include "dash.h"
32 #include "demux.h"
33 #include "url.h"
34 
35 #define INITIAL_BUFFER_SIZE 32768
36 
37 struct fragment {
40  char *url;
41 };
42 
43 /*
44  * reference to : ISO_IEC_23009-1-DASH-2012
45  * Section: 5.3.9.6.2
46  * Table: Table 17 — Semantics of SegmentTimeline element
47  * */
48 struct timeline {
49  /* starttime: Element or Attribute Name
50  * specifies the MPD start time, in @timescale units,
51  * the first Segment in the series starts relative to the beginning of the Period.
52  * The value of this attribute must be equal to or greater than the sum of the previous S
53  * element earliest presentation time and the sum of the contiguous Segment durations.
54  * If the value of the attribute is greater than what is expressed by the previous S element,
55  * it expresses discontinuities in the timeline.
56  * If not present then the value shall be assumed to be zero for the first S element
57  * and for the subsequent S elements, the value shall be assumed to be the sum of
58  * the previous S element's earliest presentation time and contiguous duration
59  * (i.e. previous S@starttime + @duration * (@repeat + 1)).
60  * */
62  /* repeat: Element or Attribute Name
63  * specifies the repeat count of the number of following contiguous Segments with
64  * the same duration expressed by the value of @duration. This value is zero-based
65  * (e.g. a value of three means four Segments in the contiguous series).
66  * */
68  /* duration: Element or Attribute Name
69  * specifies the Segment duration, in units of the value of the @timescale.
70  * */
72 };
73 
74 /*
75  * Each playlist has its own demuxer. If it is currently active,
76  * it has an opened AVIOContext too, and potentially an AVPacket
77  * containing the next packet from this stream.
78  */
80  char *url_template;
86 
87  char *id;
88  char *lang;
89  int bandwidth;
91  AVStream *assoc_stream; /* demuxer stream associated with this representation */
92 
94  struct fragment **fragments; /* VOD list of fragment for profile */
95 
97  struct timeline **timelines;
98 
101  int64_t start_number; /* used in case when we have dynamic list of segment to know which segments are new one*/
102 
105 
107 
111  struct fragment *cur_seg;
112 
113  /* Currently active Media Initialization Section */
115  uint8_t *init_sec_buf;
121 };
122 
123 typedef struct DASHContext {
124  const AVClass *class;
125  char *base_url;
126 
127  int n_videos;
129  int n_audios;
133 
134  /* MediaPresentationDescription Attribute */
139  uint64_t publish_time;
142  uint64_t min_buffer_time;
143 
144  /* Period Attribute */
145  uint64_t period_duration;
146  uint64_t period_start;
147 
148  /* AdaptationSet Attribute */
150 
151  int is_live;
158 
159  /* Flags for init section*/
163 
164 } DASHContext;
165 
166 static int ishttp(char *url)
167 {
168  const char *proto_name = avio_find_protocol_name(url);
169  return proto_name && av_strstart(proto_name, "http", NULL);
170 }
171 
172 static int aligned(int val)
173 {
174  return ((val + 0x3F) >> 6) << 6;
175 }
176 
177 static uint64_t get_current_time_in_sec(void)
178 {
179  return av_gettime() / 1000000;
180 }
181 
182 static uint64_t get_utc_date_time_insec(AVFormatContext *s, const char *datetime)
183 {
184  struct tm timeinfo;
185  int year = 0;
186  int month = 0;
187  int day = 0;
188  int hour = 0;
189  int minute = 0;
190  int ret = 0;
191  float second = 0.0;
192 
193  /* ISO-8601 date parser */
194  if (!datetime)
195  return 0;
196 
197  ret = sscanf(datetime, "%d-%d-%dT%d:%d:%fZ", &year, &month, &day, &hour, &minute, &second);
198  /* year, month, day, hour, minute, second 6 arguments */
199  if (ret != 6) {
200  av_log(s, AV_LOG_WARNING, "get_utc_date_time_insec get a wrong time format\n");
201  }
202  timeinfo.tm_year = year - 1900;
203  timeinfo.tm_mon = month - 1;
204  timeinfo.tm_mday = day;
205  timeinfo.tm_hour = hour;
206  timeinfo.tm_min = minute;
207  timeinfo.tm_sec = (int)second;
208 
209  return av_timegm(&timeinfo);
210 }
211 
212 static uint32_t get_duration_insec(AVFormatContext *s, const char *duration)
213 {
214  /* ISO-8601 duration parser */
215  uint32_t days = 0;
216  uint32_t hours = 0;
217  uint32_t mins = 0;
218  uint32_t secs = 0;
219  int size = 0;
220  float value = 0;
221  char type = '\0';
222  const char *ptr = duration;
223 
224  while (*ptr) {
225  if (*ptr == 'P' || *ptr == 'T') {
226  ptr++;
227  continue;
228  }
229 
230  if (sscanf(ptr, "%f%c%n", &value, &type, &size) != 2) {
231  av_log(s, AV_LOG_WARNING, "get_duration_insec get a wrong time format\n");
232  return 0; /* parser error */
233  }
234  switch (type) {
235  case 'D':
236  days = (uint32_t)value;
237  break;
238  case 'H':
239  hours = (uint32_t)value;
240  break;
241  case 'M':
242  mins = (uint32_t)value;
243  break;
244  case 'S':
245  secs = (uint32_t)value;
246  break;
247  default:
248  // handle invalid type
249  break;
250  }
251  ptr += size;
252  }
253  return ((days * 24 + hours) * 60 + mins) * 60 + secs;
254 }
255 
257 {
258  int64_t start_time = 0;
259  int64_t i = 0;
260  int64_t j = 0;
261  int64_t num = 0;
262 
263  if (pls->n_timelines) {
264  for (i = 0; i < pls->n_timelines; i++) {
265  if (pls->timelines[i]->starttime > 0) {
266  start_time = pls->timelines[i]->starttime;
267  }
268  if (num == cur_seq_no)
269  goto finish;
270 
271  start_time += pls->timelines[i]->duration;
272 
273  if (pls->timelines[i]->repeat == -1) {
274  start_time = pls->timelines[i]->duration * cur_seq_no;
275  goto finish;
276  }
277 
278  for (j = 0; j < pls->timelines[i]->repeat; j++) {
279  num++;
280  if (num == cur_seq_no)
281  goto finish;
282  start_time += pls->timelines[i]->duration;
283  }
284  num++;
285  }
286  }
287 finish:
288  return start_time;
289 }
290 
292 {
293  int64_t i = 0;
294  int64_t j = 0;
295  int64_t num = 0;
296  int64_t start_time = 0;
297 
298  for (i = 0; i < pls->n_timelines; i++) {
299  if (pls->timelines[i]->starttime > 0) {
300  start_time = pls->timelines[i]->starttime;
301  }
302  if (start_time > cur_time)
303  goto finish;
304 
305  start_time += pls->timelines[i]->duration;
306  for (j = 0; j < pls->timelines[i]->repeat; j++) {
307  num++;
308  if (start_time > cur_time)
309  goto finish;
310  start_time += pls->timelines[i]->duration;
311  }
312  num++;
313  }
314 
315  return -1;
316 
317 finish:
318  return num;
319 }
320 
321 static void free_fragment(struct fragment **seg)
322 {
323  if (!(*seg)) {
324  return;
325  }
326  av_freep(&(*seg)->url);
327  av_freep(seg);
328 }
329 
330 static void free_fragment_list(struct representation *pls)
331 {
332  int i;
333 
334  for (i = 0; i < pls->n_fragments; i++) {
335  free_fragment(&pls->fragments[i]);
336  }
337  av_freep(&pls->fragments);
338  pls->n_fragments = 0;
339 }
340 
341 static void free_timelines_list(struct representation *pls)
342 {
343  int i;
344 
345  for (i = 0; i < pls->n_timelines; i++) {
346  av_freep(&pls->timelines[i]);
347  }
348  av_freep(&pls->timelines);
349  pls->n_timelines = 0;
350 }
351 
352 static void free_representation(struct representation *pls)
353 {
354  free_fragment_list(pls);
355  free_timelines_list(pls);
356  free_fragment(&pls->cur_seg);
358  av_freep(&pls->init_sec_buf);
359  av_freep(&pls->pb.pub.buffer);
360  ff_format_io_close(pls->parent, &pls->input);
361  if (pls->ctx) {
362  pls->ctx->pb = NULL;
363  avformat_close_input(&pls->ctx);
364  }
365 
366  av_freep(&pls->url_template);
367  av_freep(&pls->lang);
368  av_freep(&pls->id);
369  av_freep(&pls);
370 }
371 
373 {
374  int i;
375  for (i = 0; i < c->n_videos; i++) {
376  struct representation *pls = c->videos[i];
377  free_representation(pls);
378  }
379  av_freep(&c->videos);
380  c->n_videos = 0;
381 }
382 
384 {
385  int i;
386  for (i = 0; i < c->n_audios; i++) {
387  struct representation *pls = c->audios[i];
388  free_representation(pls);
389  }
390  av_freep(&c->audios);
391  c->n_audios = 0;
392 }
393 
395 {
396  int i;
397  for (i = 0; i < c->n_subtitles; i++) {
398  struct representation *pls = c->subtitles[i];
399  free_representation(pls);
400  }
401  av_freep(&c->subtitles);
402  c->n_subtitles = 0;
403 }
404 
405 static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
406  AVDictionary **opts, AVDictionary *opts2, int *is_http)
407 {
408  DASHContext *c = s->priv_data;
409  AVDictionary *tmp = NULL;
410  const char *proto_name = NULL;
411  int proto_name_len;
412  int ret;
413 
414  if (av_strstart(url, "crypto", NULL)) {
415  if (url[6] == '+' || url[6] == ':')
416  proto_name = avio_find_protocol_name(url + 7);
417  }
418 
419  if (!proto_name)
420  proto_name = avio_find_protocol_name(url);
421 
422  if (!proto_name)
423  return AVERROR_INVALIDDATA;
424 
425  proto_name_len = strlen(proto_name);
426  // only http(s) & file are allowed
427  if (av_strstart(proto_name, "file", NULL)) {
428  if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(url, c->allowed_extensions)) {
430  "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n"
431  "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n",
432  url);
433  return AVERROR_INVALIDDATA;
434  }
435  } else if (av_strstart(proto_name, "http", NULL)) {
436  ;
437  } else
438  return AVERROR_INVALIDDATA;
439 
440  if (!strncmp(proto_name, url, proto_name_len) && url[proto_name_len] == ':')
441  ;
442  else if (av_strstart(url, "crypto", NULL) && !strncmp(proto_name, url + 7, proto_name_len) && url[7 + proto_name_len] == ':')
443  ;
444  else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5))
445  return AVERROR_INVALIDDATA;
446 
447  av_freep(pb);
448  av_dict_copy(&tmp, *opts, 0);
449  av_dict_copy(&tmp, opts2, 0);
450  ret = ffio_open_whitelist(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp, s->protocol_whitelist, s->protocol_blacklist);
451  if (ret >= 0) {
452  // update cookies on http response with setcookies.
453  char *new_cookies = NULL;
454 
455  if (!(s->flags & AVFMT_FLAG_CUSTOM_IO))
456  av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies);
457 
458  if (new_cookies) {
459  av_dict_set(opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL);
460  }
461 
462  }
463 
464  av_dict_free(&tmp);
465 
466  if (is_http)
467  *is_http = av_strstart(proto_name, "http", NULL);
468 
469  return ret;
470 }
471 
472 static char *get_content_url(xmlNodePtr *baseurl_nodes,
473  int n_baseurl_nodes,
474  int max_url_size,
475  char *rep_id_val,
476  char *rep_bandwidth_val,
477  char *val)
478 {
479  int i;
480  char *text;
481  char *url = NULL;
482  char *tmp_str = av_mallocz(max_url_size);
483 
484  if (!tmp_str)
485  return NULL;
486 
487  for (i = 0; i < n_baseurl_nodes; ++i) {
488  if (baseurl_nodes[i] &&
489  baseurl_nodes[i]->children &&
490  baseurl_nodes[i]->children->type == XML_TEXT_NODE) {
491  text = xmlNodeGetContent(baseurl_nodes[i]->children);
492  if (text) {
493  memset(tmp_str, 0, max_url_size);
494  ff_make_absolute_url(tmp_str, max_url_size, "", text);
495  xmlFree(text);
496  }
497  }
498  }
499 
500  if (val)
501  ff_make_absolute_url(tmp_str, max_url_size, tmp_str, val);
502 
503  if (rep_id_val) {
504  url = av_strireplace(tmp_str, "$RepresentationID$", rep_id_val);
505  if (!url) {
506  goto end;
507  }
508  av_strlcpy(tmp_str, url, max_url_size);
509  }
510  if (rep_bandwidth_val && tmp_str[0] != '\0') {
511  // free any previously assigned url before reassigning
512  av_free(url);
513  url = av_strireplace(tmp_str, "$Bandwidth$", rep_bandwidth_val);
514  if (!url) {
515  goto end;
516  }
517  }
518 end:
519  av_free(tmp_str);
520  return url;
521 }
522 
523 static char *get_val_from_nodes_tab(xmlNodePtr *nodes, const int n_nodes, const char *attrname)
524 {
525  int i;
526  char *val;
527 
528  for (i = 0; i < n_nodes; ++i) {
529  if (nodes[i]) {
530  val = xmlGetProp(nodes[i], attrname);
531  if (val)
532  return val;
533  }
534  }
535 
536  return NULL;
537 }
538 
539 static xmlNodePtr find_child_node_by_name(xmlNodePtr rootnode, const char *nodename)
540 {
541  xmlNodePtr node = rootnode;
542  if (!node) {
543  return NULL;
544  }
545 
546  node = xmlFirstElementChild(node);
547  while (node) {
548  if (!av_strcasecmp(node->name, nodename)) {
549  return node;
550  }
551  node = xmlNextElementSibling(node);
552  }
553  return NULL;
554 }
555 
556 static enum AVMediaType get_content_type(xmlNodePtr node)
557 {
559  int i = 0;
560  const char *attr;
561  char *val = NULL;
562 
563  if (node) {
564  for (i = 0; i < 2; i++) {
565  attr = i ? "mimeType" : "contentType";
566  val = xmlGetProp(node, attr);
567  if (val) {
568  if (av_stristr(val, "video")) {
570  } else if (av_stristr(val, "audio")) {
572  } else if (av_stristr(val, "text")) {
574  }
575  xmlFree(val);
576  }
577  }
578  }
579  return type;
580 }
581 
582 static struct fragment *get_fragment(char *range)
583 {
584  struct fragment *seg = av_mallocz(sizeof(struct fragment));
585 
586  if (!seg)
587  return NULL;
588 
589  seg->size = -1;
590  if (range) {
591  char *str_end_offset;
592  char *str_offset = av_strtok(range, "-", &str_end_offset);
593  seg->url_offset = strtoll(str_offset, NULL, 10);
594  seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset + 1;
595  }
596 
597  return seg;
598 }
599 
601  xmlNodePtr fragmenturl_node,
602  xmlNodePtr *baseurl_nodes,
603  char *rep_id_val,
604  char *rep_bandwidth_val)
605 {
606  DASHContext *c = s->priv_data;
607  char *initialization_val = NULL;
608  char *media_val = NULL;
609  char *range_val = NULL;
610  int max_url_size = c ? c->max_url_size: MAX_URL_SIZE;
611  int err;
612 
613  if (!av_strcasecmp(fragmenturl_node->name, "Initialization")) {
614  initialization_val = xmlGetProp(fragmenturl_node, "sourceURL");
615  range_val = xmlGetProp(fragmenturl_node, "range");
616  if (initialization_val || range_val) {
618  rep->init_section = get_fragment(range_val);
619  xmlFree(range_val);
620  if (!rep->init_section) {
621  xmlFree(initialization_val);
622  return AVERROR(ENOMEM);
623  }
624  rep->init_section->url = get_content_url(baseurl_nodes, 4,
625  max_url_size,
626  rep_id_val,
627  rep_bandwidth_val,
628  initialization_val);
629  xmlFree(initialization_val);
630  if (!rep->init_section->url) {
631  av_freep(&rep->init_section);
632  return AVERROR(ENOMEM);
633  }
634  }
635  } else if (!av_strcasecmp(fragmenturl_node->name, "SegmentURL")) {
636  media_val = xmlGetProp(fragmenturl_node, "media");
637  range_val = xmlGetProp(fragmenturl_node, "mediaRange");
638  if (media_val || range_val) {
639  struct fragment *seg = get_fragment(range_val);
640  xmlFree(range_val);
641  if (!seg) {
642  xmlFree(media_val);
643  return AVERROR(ENOMEM);
644  }
645  seg->url = get_content_url(baseurl_nodes, 4,
646  max_url_size,
647  rep_id_val,
648  rep_bandwidth_val,
649  media_val);
650  xmlFree(media_val);
651  if (!seg->url) {
652  av_free(seg);
653  return AVERROR(ENOMEM);
654  }
655  err = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg);
656  if (err < 0) {
657  free_fragment(&seg);
658  return err;
659  }
660  }
661  }
662 
663  return 0;
664 }
665 
667  xmlNodePtr fragment_timeline_node)
668 {
669  xmlAttrPtr attr = NULL;
670  char *val = NULL;
671  int err;
672 
673  if (!av_strcasecmp(fragment_timeline_node->name, "S")) {
674  struct timeline *tml = av_mallocz(sizeof(struct timeline));
675  if (!tml) {
676  return AVERROR(ENOMEM);
677  }
678  attr = fragment_timeline_node->properties;
679  while (attr) {
680  val = xmlGetProp(fragment_timeline_node, attr->name);
681 
682  if (!val) {
683  av_log(s, AV_LOG_WARNING, "parse_manifest_segmenttimeline attr->name = %s val is NULL\n", attr->name);
684  continue;
685  }
686 
687  if (!av_strcasecmp(attr->name, "t")) {
688  tml->starttime = (int64_t)strtoll(val, NULL, 10);
689  } else if (!av_strcasecmp(attr->name, "r")) {
690  tml->repeat =(int64_t) strtoll(val, NULL, 10);
691  } else if (!av_strcasecmp(attr->name, "d")) {
692  tml->duration = (int64_t)strtoll(val, NULL, 10);
693  }
694  attr = attr->next;
695  xmlFree(val);
696  }
697  err = av_dynarray_add_nofree(&rep->timelines, &rep->n_timelines, tml);
698  if (err < 0) {
699  av_free(tml);
700  return err;
701  }
702  }
703 
704  return 0;
705 }
706 
707 static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes)
708 {
709  char *tmp_str = NULL;
710  char *path = NULL;
711  char *mpdName = NULL;
712  xmlNodePtr node = NULL;
713  char *baseurl = NULL;
714  char *root_url = NULL;
715  char *text = NULL;
716  char *tmp = NULL;
717  int isRootHttp = 0;
718  char token ='/';
719  int start = 0;
720  int rootId = 0;
721  int updated = 0;
722  int size = 0;
723  int i;
724  int tmp_max_url_size = strlen(url);
725 
726  for (i = n_baseurl_nodes-1; i >= 0 ; i--) {
727  text = xmlNodeGetContent(baseurl_nodes[i]);
728  if (!text)
729  continue;
730  tmp_max_url_size += strlen(text);
731  if (ishttp(text)) {
732  xmlFree(text);
733  break;
734  }
735  xmlFree(text);
736  }
737 
738  tmp_max_url_size = aligned(tmp_max_url_size);
739  text = av_mallocz(tmp_max_url_size + 1);
740  if (!text) {
741  updated = AVERROR(ENOMEM);
742  goto end;
743  }
744  av_strlcpy(text, url, strlen(url)+1);
745  tmp = text;
746  while (mpdName = av_strtok(tmp, "/", &tmp)) {
747  size = strlen(mpdName);
748  }
749  av_free(text);
750 
751  path = av_mallocz(tmp_max_url_size + 2);
752  tmp_str = av_mallocz(tmp_max_url_size);
753  if (!tmp_str || !path) {
754  updated = AVERROR(ENOMEM);
755  goto end;
756  }
757 
758  av_strlcpy (path, url, strlen(url) - size + 1);
759  for (rootId = n_baseurl_nodes - 1; rootId > 0; rootId --) {
760  if (!(node = baseurl_nodes[rootId])) {
761  continue;
762  }
763  text = xmlNodeGetContent(node);
764  if (ishttp(text)) {
765  xmlFree(text);
766  break;
767  }
768  xmlFree(text);
769  }
770 
771  node = baseurl_nodes[rootId];
772  baseurl = xmlNodeGetContent(node);
773  if (baseurl) {
774  size_t len = xmlStrlen(baseurl)+2;
775  char *tmp = xmlRealloc(baseurl, len);
776  if (!tmp) {
777  updated = AVERROR(ENOMEM);
778  goto end;
779  }
780  baseurl = tmp;
781  }
782  root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path;
783  if (node) {
784  xmlChar *escaped = xmlEncodeSpecialChars(NULL, root_url);
785  if (!escaped) {
786  updated = AVERROR(ENOMEM);
787  goto end;
788  }
789  xmlNodeSetContent(node, escaped);
790  xmlFree(escaped);
791  updated = 1;
792  }
793 
794  size = strlen(root_url);
795  isRootHttp = ishttp(root_url);
796 
797  if (size > 0 && root_url[size - 1] != token) {
798  av_strlcat(root_url, "/", size + 2);
799  size += 2;
800  }
801 
802  for (i = 0; i < n_baseurl_nodes; ++i) {
803  if (i == rootId) {
804  continue;
805  }
806  text = xmlNodeGetContent(baseurl_nodes[i]);
807  if (text && !av_strstart(text, "/", NULL)) {
808  memset(tmp_str, 0, strlen(tmp_str));
809  if (!ishttp(text) && isRootHttp) {
810  av_strlcpy(tmp_str, root_url, size + 1);
811  }
812  start = (text[0] == token);
813  if (start && av_stristr(tmp_str, text)) {
814  char *p = tmp_str;
815  if (!av_strncasecmp(tmp_str, "http://", 7)) {
816  p += 7;
817  } else if (!av_strncasecmp(tmp_str, "https://", 8)) {
818  p += 8;
819  }
820  p = strchr(p, '/');
821  memset(p + 1, 0, strlen(p));
822  }
823  av_strlcat(tmp_str, text + start, tmp_max_url_size);
824  xmlFree(text);
825  xmlChar* escaped = xmlEncodeSpecialChars(NULL, tmp_str);
826  if (!escaped) {
827  updated = AVERROR(ENOMEM);
828  goto end;
829  }
830  xmlNodeSetContent(baseurl_nodes[i], escaped);
831  updated = 1;
832  xmlFree(escaped);
833  }
834  }
835 
836 end:
837  if (tmp_max_url_size > *max_url_size) {
838  *max_url_size = tmp_max_url_size;
839  }
840  av_free(path);
841  av_free(tmp_str);
842  xmlFree(baseurl);
843  return updated;
844 
845 }
846 
847 #define SET_REPRESENTATION_SEQUENCE_BASE_INFO(arg, cnt) { \
848  val = get_val_from_nodes_tab((arg), (cnt), "duration"); \
849  if (val) { \
850  int64_t fragment_duration = (int64_t) strtoll(val, NULL, 10); \
851  if (fragment_duration < 0) { \
852  av_log(s, AV_LOG_WARNING, "duration invalid, autochanged to 0.\n"); \
853  fragment_duration = 0; \
854  } \
855  rep->fragment_duration = fragment_duration; \
856  av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); \
857  xmlFree(val); \
858  } \
859  val = get_val_from_nodes_tab((arg), (cnt), "timescale"); \
860  if (val) { \
861  int64_t fragment_timescale = (int64_t) strtoll(val, NULL, 10); \
862  if (fragment_timescale < 0) { \
863  av_log(s, AV_LOG_WARNING, "timescale invalid, autochanged to 0.\n"); \
864  fragment_timescale = 0; \
865  } \
866  rep->fragment_timescale = fragment_timescale; \
867  av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); \
868  xmlFree(val); \
869  } \
870  val = get_val_from_nodes_tab((arg), (cnt), "startNumber"); \
871  if (val) { \
872  int64_t start_number = (int64_t) strtoll(val, NULL, 10); \
873  if (start_number < 0) { \
874  av_log(s, AV_LOG_WARNING, "startNumber invalid, autochanged to 0.\n"); \
875  start_number = 0; \
876  } \
877  rep->start_number = rep->first_seq_no = start_number; \
878  av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); \
879  xmlFree(val); \
880  } \
881  }
882 
883 
884 static int parse_manifest_representation(AVFormatContext *s, const char *url,
885  xmlNodePtr node,
886  xmlNodePtr adaptionset_node,
887  xmlNodePtr mpd_baseurl_node,
888  xmlNodePtr period_baseurl_node,
889  xmlNodePtr period_segmenttemplate_node,
890  xmlNodePtr period_segmentlist_node,
891  xmlNodePtr fragment_template_node,
892  xmlNodePtr content_component_node,
893  xmlNodePtr adaptionset_baseurl_node,
894  xmlNodePtr adaptionset_segmentlist_node,
895  xmlNodePtr adaptionset_supplementalproperty_node)
896 {
897  int32_t ret = 0;
898  DASHContext *c = s->priv_data;
899  struct representation *rep = NULL;
900  struct fragment *seg = NULL;
901  xmlNodePtr representation_segmenttemplate_node = NULL;
902  xmlNodePtr representation_baseurl_node = NULL;
903  xmlNodePtr representation_segmentlist_node = NULL;
904  xmlNodePtr segmentlists_tab[3];
905  xmlNodePtr fragment_timeline_node = NULL;
906  xmlNodePtr fragment_templates_tab[5];
907  char *val = NULL;
908  xmlNodePtr baseurl_nodes[4];
909  xmlNodePtr representation_node = node;
910  char *rep_bandwidth_val;
912 
913  // try get information from representation
914  if (type == AVMEDIA_TYPE_UNKNOWN)
915  type = get_content_type(representation_node);
916  // try get information from contentComponen
917  if (type == AVMEDIA_TYPE_UNKNOWN)
918  type = get_content_type(content_component_node);
919  // try get information from adaption set
920  if (type == AVMEDIA_TYPE_UNKNOWN)
921  type = get_content_type(adaptionset_node);
924  av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skip not supported representation type\n", url);
925  return 0;
926  }
927 
928  // convert selected representation to our internal struct
929  rep = av_mallocz(sizeof(struct representation));
930  if (!rep)
931  return AVERROR(ENOMEM);
932  if (c->adaptionset_lang) {
933  rep->lang = av_strdup(c->adaptionset_lang);
934  if (!rep->lang) {
935  av_log(s, AV_LOG_ERROR, "alloc language memory failure\n");
936  av_freep(&rep);
937  return AVERROR(ENOMEM);
938  }
939  }
940  rep->parent = s;
941  representation_segmenttemplate_node = find_child_node_by_name(representation_node, "SegmentTemplate");
942  representation_baseurl_node = find_child_node_by_name(representation_node, "BaseURL");
943  representation_segmentlist_node = find_child_node_by_name(representation_node, "SegmentList");
944  rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth");
945  val = xmlGetProp(representation_node, "id");
946  if (val) {
947  rep->id = av_strdup(val);
948  xmlFree(val);
949  if (!rep->id)
950  goto enomem;
951  }
952 
953  baseurl_nodes[0] = mpd_baseurl_node;
954  baseurl_nodes[1] = period_baseurl_node;
955  baseurl_nodes[2] = adaptionset_baseurl_node;
956  baseurl_nodes[3] = representation_baseurl_node;
957 
958  ret = resolve_content_path(s, url, &c->max_url_size, baseurl_nodes, 4);
959  c->max_url_size = aligned(c->max_url_size
960  + (rep->id ? strlen(rep->id) : 0)
961  + (rep_bandwidth_val ? strlen(rep_bandwidth_val) : 0));
962  if (ret == AVERROR(ENOMEM) || ret == 0)
963  goto free;
964  if (representation_segmenttemplate_node || fragment_template_node || period_segmenttemplate_node) {
965  fragment_timeline_node = NULL;
966  fragment_templates_tab[0] = representation_segmenttemplate_node;
967  fragment_templates_tab[1] = adaptionset_segmentlist_node;
968  fragment_templates_tab[2] = fragment_template_node;
969  fragment_templates_tab[3] = period_segmenttemplate_node;
970  fragment_templates_tab[4] = period_segmentlist_node;
971 
972  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "initialization");
973  if (val) {
974  rep->init_section = av_mallocz(sizeof(struct fragment));
975  if (!rep->init_section) {
976  xmlFree(val);
977  goto enomem;
978  }
979  c->max_url_size = aligned(c->max_url_size + strlen(val));
980  rep->init_section->url = get_content_url(baseurl_nodes, 4,
981  c->max_url_size, rep->id,
982  rep_bandwidth_val, val);
983  xmlFree(val);
984  if (!rep->init_section->url)
985  goto enomem;
986  rep->init_section->size = -1;
987  }
988  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "media");
989  if (val) {
990  c->max_url_size = aligned(c->max_url_size + strlen(val));
991  rep->url_template = get_content_url(baseurl_nodes, 4,
992  c->max_url_size, rep->id,
993  rep_bandwidth_val, val);
994  xmlFree(val);
995  }
996  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "presentationTimeOffset");
997  if (val) {
998  int64_t presentation_timeoffset = (int64_t) strtoll(val, NULL, 10);
999  if (presentation_timeoffset < 0) {
1000  av_log(s, AV_LOG_WARNING, "presentationTimeOffset invalid, autochanged to 0.\n");
1001  presentation_timeoffset = 0;
1002  }
1003  rep->presentation_timeoffset = presentation_timeoffset;
1004  av_log(s, AV_LOG_TRACE, "rep->presentation_timeoffset = [%"PRId64"]\n", rep->presentation_timeoffset);
1005  xmlFree(val);
1006  }
1007 
1008  SET_REPRESENTATION_SEQUENCE_BASE_INFO(fragment_templates_tab, 4);
1009  if (adaptionset_supplementalproperty_node) {
1010  char *scheme_id_uri = xmlGetProp(adaptionset_supplementalproperty_node, "schemeIdUri");
1011  if (scheme_id_uri) {
1012  int is_last_segment_number = !av_strcasecmp(scheme_id_uri, "http://dashif.org/guidelines/last-segment-number");
1013  xmlFree(scheme_id_uri);
1014  if (is_last_segment_number) {
1015  val = xmlGetProp(adaptionset_supplementalproperty_node, "value");
1016  if (!val) {
1017  av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n");
1018  } else {
1019  rep->last_seq_no = (int64_t)strtoll(val, NULL, 10) - 1;
1020  xmlFree(val);
1021  }
1022  }
1023  }
1024  }
1025 
1026  fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline");
1027 
1028  if (!fragment_timeline_node)
1029  fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline");
1030  if (!fragment_timeline_node)
1031  fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline");
1032  if (!fragment_timeline_node)
1033  fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline");
1034  if (fragment_timeline_node) {
1035  fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node);
1036  while (fragment_timeline_node) {
1037  ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node);
1038  if (ret < 0)
1039  goto free;
1040  fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node);
1041  }
1042  }
1043  } else if (representation_baseurl_node && !representation_segmentlist_node) {
1044  seg = av_mallocz(sizeof(struct fragment));
1045  if (!seg)
1046  goto enomem;
1047  ret = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg);
1048  if (ret < 0) {
1049  av_free(seg);
1050  goto free;
1051  }
1052  seg->url = get_content_url(baseurl_nodes, 4, c->max_url_size,
1053  rep->id, rep_bandwidth_val, NULL);
1054  if (!seg->url)
1055  goto enomem;
1056  seg->size = -1;
1057  } else if (representation_segmentlist_node) {
1058  // TODO: https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html
1059  // http://www-itec.uni-klu.ac.at/dash/ddash/mpdGenerator.php?fragmentlength=15&type=full
1060  xmlNodePtr fragmenturl_node = NULL;
1061  segmentlists_tab[0] = representation_segmentlist_node;
1062  segmentlists_tab[1] = adaptionset_segmentlist_node;
1063  segmentlists_tab[2] = period_segmentlist_node;
1064 
1065  SET_REPRESENTATION_SEQUENCE_BASE_INFO(segmentlists_tab, 3)
1066  fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node);
1067  while (fragmenturl_node) {
1068  ret = parse_manifest_segmenturlnode(s, rep, fragmenturl_node,
1069  baseurl_nodes, rep->id,
1070  rep_bandwidth_val);
1071  if (ret < 0)
1072  goto free;
1073  fragmenturl_node = xmlNextElementSibling(fragmenturl_node);
1074  }
1075 
1076  fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline");
1077  if (!fragment_timeline_node)
1078  fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline");
1079  if (fragment_timeline_node) {
1080  fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node);
1081  while (fragment_timeline_node) {
1082  ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node);
1083  if (ret < 0)
1084  goto free;
1085  fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node);
1086  }
1087  }
1088  } else {
1089  av_log(s, AV_LOG_ERROR, "Unknown format of Representation node id '%s' \n",
1090  rep->id ? rep->id : "");
1091  goto free;
1092  }
1093 
1094  if (rep->fragment_duration > 0 && !rep->fragment_timescale)
1095  rep->fragment_timescale = 1;
1096  rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0;
1097  rep->framerate = av_make_q(0, 0);
1098  if (type == AVMEDIA_TYPE_VIDEO) {
1099  char *rep_framerate_val = xmlGetProp(representation_node, "frameRate");
1100  if (rep_framerate_val) {
1101  ret = av_parse_video_rate(&rep->framerate, rep_framerate_val);
1102  if (ret < 0)
1103  av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val);
1104  xmlFree(rep_framerate_val);
1105  }
1106  }
1107 
1108  switch (type) {
1109  case AVMEDIA_TYPE_VIDEO:
1110  ret = av_dynarray_add_nofree(&c->videos, &c->n_videos, rep);
1111  break;
1112  case AVMEDIA_TYPE_AUDIO:
1113  ret = av_dynarray_add_nofree(&c->audios, &c->n_audios, rep);
1114  break;
1115  case AVMEDIA_TYPE_SUBTITLE:
1116  ret = av_dynarray_add_nofree(&c->subtitles, &c->n_subtitles, rep);
1117  break;
1118  }
1119  if (ret < 0)
1120  goto free;
1121 
1122 end:
1123  if (rep_bandwidth_val)
1124  xmlFree(rep_bandwidth_val);
1125 
1126  return ret;
1127 enomem:
1128  ret = AVERROR(ENOMEM);
1129 free:
1130  free_representation(rep);
1131  goto end;
1132 }
1133 
1134 static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node)
1135 {
1136  DASHContext *c = s->priv_data;
1137 
1138  if (!adaptionset_node) {
1139  av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n");
1140  return AVERROR(EINVAL);
1141  }
1142  c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang");
1143 
1144  return 0;
1145 }
1146 
1148  xmlNodePtr adaptionset_node,
1149  xmlNodePtr mpd_baseurl_node,
1150  xmlNodePtr period_baseurl_node,
1151  xmlNodePtr period_segmenttemplate_node,
1152  xmlNodePtr period_segmentlist_node)
1153 {
1154  int ret = 0;
1155  DASHContext *c = s->priv_data;
1156  xmlNodePtr fragment_template_node = NULL;
1157  xmlNodePtr content_component_node = NULL;
1158  xmlNodePtr adaptionset_baseurl_node = NULL;
1159  xmlNodePtr adaptionset_segmentlist_node = NULL;
1160  xmlNodePtr adaptionset_supplementalproperty_node = NULL;
1161  xmlNodePtr node = NULL;
1162 
1163  ret = parse_manifest_adaptationset_attr(s, adaptionset_node);
1164  if (ret < 0)
1165  return ret;
1166 
1167  node = xmlFirstElementChild(adaptionset_node);
1168  while (node) {
1169  if (!av_strcasecmp(node->name, "SegmentTemplate")) {
1170  fragment_template_node = node;
1171  } else if (!av_strcasecmp(node->name, "ContentComponent")) {
1172  content_component_node = node;
1173  } else if (!av_strcasecmp(node->name, "BaseURL")) {
1174  adaptionset_baseurl_node = node;
1175  } else if (!av_strcasecmp(node->name, "SegmentList")) {
1176  adaptionset_segmentlist_node = node;
1177  } else if (!av_strcasecmp(node->name, "SupplementalProperty")) {
1178  adaptionset_supplementalproperty_node = node;
1179  } else if (!av_strcasecmp(node->name, "Representation")) {
1181  adaptionset_node,
1182  mpd_baseurl_node,
1183  period_baseurl_node,
1184  period_segmenttemplate_node,
1185  period_segmentlist_node,
1186  fragment_template_node,
1187  content_component_node,
1188  adaptionset_baseurl_node,
1189  adaptionset_segmentlist_node,
1190  adaptionset_supplementalproperty_node);
1191  if (ret < 0)
1192  goto err;
1193  }
1194  node = xmlNextElementSibling(node);
1195  }
1196 
1197 err:
1198  xmlFree(c->adaptionset_lang);
1199  c->adaptionset_lang = NULL;
1200  return ret;
1201 }
1202 
1203 static int parse_programinformation(AVFormatContext *s, xmlNodePtr node)
1204 {
1205  xmlChar *val = NULL;
1206 
1207  node = xmlFirstElementChild(node);
1208  while (node) {
1209  if (!av_strcasecmp(node->name, "Title")) {
1210  val = xmlNodeGetContent(node);
1211  if (val) {
1212  av_dict_set(&s->metadata, "Title", val, 0);
1213  }
1214  } else if (!av_strcasecmp(node->name, "Source")) {
1215  val = xmlNodeGetContent(node);
1216  if (val) {
1217  av_dict_set(&s->metadata, "Source", val, 0);
1218  }
1219  } else if (!av_strcasecmp(node->name, "Copyright")) {
1220  val = xmlNodeGetContent(node);
1221  if (val) {
1222  av_dict_set(&s->metadata, "Copyright", val, 0);
1223  }
1224  }
1225  node = xmlNextElementSibling(node);
1226  xmlFree(val);
1227  val = NULL;
1228  }
1229  return 0;
1230 }
1231 
1232 static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
1233 {
1234  DASHContext *c = s->priv_data;
1235  int ret = 0;
1236  int close_in = 0;
1237  AVBPrint buf;
1238  AVDictionary *opts = NULL;
1239  xmlDoc *doc = NULL;
1240  xmlNodePtr root_element = NULL;
1241  xmlNodePtr node = NULL;
1242  xmlNodePtr period_node = NULL;
1243  xmlNodePtr tmp_node = NULL;
1244  xmlNodePtr mpd_baseurl_node = NULL;
1245  xmlNodePtr period_baseurl_node = NULL;
1246  xmlNodePtr period_segmenttemplate_node = NULL;
1247  xmlNodePtr period_segmentlist_node = NULL;
1248  xmlNodePtr adaptionset_node = NULL;
1249  xmlAttrPtr attr = NULL;
1250  char *val = NULL;
1251  uint32_t period_duration_sec = 0;
1252  uint32_t period_start_sec = 0;
1253 
1254  if (!in) {
1255  close_in = 1;
1256 
1257  av_dict_copy(&opts, c->avio_opts, 0);
1258  ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist);
1259  av_dict_free(&opts);
1260  if (ret < 0)
1261  return ret;
1262  }
1263 
1264  if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&c->base_url) < 0)
1265  c->base_url = av_strdup(url);
1266 
1267  av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer bufsize
1268 
1269  if ((ret = avio_read_to_bprint(in, &buf, SIZE_MAX)) < 0 ||
1270  !avio_feof(in)) {
1271  av_log(s, AV_LOG_ERROR, "Unable to read to manifest '%s'\n", url);
1272  if (ret == 0)
1274  } else {
1275  LIBXML_TEST_VERSION
1276 
1277  doc = xmlReadMemory(buf.str, buf.len, c->base_url, NULL, 0);
1278  root_element = xmlDocGetRootElement(doc);
1279  node = root_element;
1280 
1281  if (!node) {
1283  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing root node\n", url);
1284  goto cleanup;
1285  }
1286 
1287  if (node->type != XML_ELEMENT_NODE ||
1288  av_strcasecmp(node->name, "MPD")) {
1290  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - wrong root node name[%s] type[%d]\n", url, node->name, (int)node->type);
1291  goto cleanup;
1292  }
1293 
1294  val = xmlGetProp(node, "type");
1295  if (!val) {
1296  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing type attrib\n", url);
1298  goto cleanup;
1299  }
1300  if (!av_strcasecmp(val, "dynamic"))
1301  c->is_live = 1;
1302  xmlFree(val);
1303 
1304  attr = node->properties;
1305  while (attr) {
1306  val = xmlGetProp(node, attr->name);
1307 
1308  if (!av_strcasecmp(attr->name, "availabilityStartTime")) {
1309  c->availability_start_time = get_utc_date_time_insec(s, val);
1310  av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time);
1311  } else if (!av_strcasecmp(attr->name, "availabilityEndTime")) {
1312  c->availability_end_time = get_utc_date_time_insec(s, val);
1313  av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time);
1314  } else if (!av_strcasecmp(attr->name, "publishTime")) {
1315  c->publish_time = get_utc_date_time_insec(s, val);
1316  av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time);
1317  } else if (!av_strcasecmp(attr->name, "minimumUpdatePeriod")) {
1318  c->minimum_update_period = get_duration_insec(s, val);
1319  av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period);
1320  } else if (!av_strcasecmp(attr->name, "timeShiftBufferDepth")) {
1321  c->time_shift_buffer_depth = get_duration_insec(s, val);
1322  av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth);
1323  } else if (!av_strcasecmp(attr->name, "minBufferTime")) {
1324  c->min_buffer_time = get_duration_insec(s, val);
1325  av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time);
1326  } else if (!av_strcasecmp(attr->name, "suggestedPresentationDelay")) {
1327  c->suggested_presentation_delay = get_duration_insec(s, val);
1328  av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay);
1329  } else if (!av_strcasecmp(attr->name, "mediaPresentationDuration")) {
1330  c->media_presentation_duration = get_duration_insec(s, val);
1331  av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration);
1332  }
1333  attr = attr->next;
1334  xmlFree(val);
1335  }
1336 
1337  tmp_node = find_child_node_by_name(node, "BaseURL");
1338  if (tmp_node) {
1339  mpd_baseurl_node = xmlCopyNode(tmp_node,1);
1340  } else {
1341  mpd_baseurl_node = xmlNewNode(NULL, "BaseURL");
1342  }
1343 
1344  // at now we can handle only one period, with the longest duration
1345  node = xmlFirstElementChild(node);
1346  while (node) {
1347  if (!av_strcasecmp(node->name, "Period")) {
1348  period_duration_sec = 0;
1349  period_start_sec = 0;
1350  attr = node->properties;
1351  while (attr) {
1352  val = xmlGetProp(node, attr->name);
1353  if (!av_strcasecmp(attr->name, "duration")) {
1354  period_duration_sec = get_duration_insec(s, val);
1355  } else if (!av_strcasecmp(attr->name, "start")) {
1356  period_start_sec = get_duration_insec(s, val);
1357  }
1358  attr = attr->next;
1359  xmlFree(val);
1360  }
1361  if ((period_duration_sec) >= (c->period_duration)) {
1362  period_node = node;
1363  c->period_duration = period_duration_sec;
1364  c->period_start = period_start_sec;
1365  if (c->period_start > 0)
1366  c->media_presentation_duration = c->period_duration;
1367  }
1368  } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
1369  parse_programinformation(s, node);
1370  }
1371  node = xmlNextElementSibling(node);
1372  }
1373  if (!period_node) {
1374  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing Period node\n", url);
1376  goto cleanup;
1377  }
1378 
1379  adaptionset_node = xmlFirstElementChild(period_node);
1380  while (adaptionset_node) {
1381  if (!av_strcasecmp(adaptionset_node->name, "BaseURL")) {
1382  period_baseurl_node = adaptionset_node;
1383  } else if (!av_strcasecmp(adaptionset_node->name, "SegmentTemplate")) {
1384  period_segmenttemplate_node = adaptionset_node;
1385  } else if (!av_strcasecmp(adaptionset_node->name, "SegmentList")) {
1386  period_segmentlist_node = adaptionset_node;
1387  } else if (!av_strcasecmp(adaptionset_node->name, "AdaptationSet")) {
1388  parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node, period_segmenttemplate_node, period_segmentlist_node);
1389  }
1390  adaptionset_node = xmlNextElementSibling(adaptionset_node);
1391  }
1392 cleanup:
1393  /*free the document */
1394  xmlFreeDoc(doc);
1395  xmlCleanupParser();
1396  xmlFreeNode(mpd_baseurl_node);
1397  }
1398 
1399  av_bprint_finalize(&buf, NULL);
1400  if (close_in) {
1401  avio_close(in);
1402  }
1403  return ret;
1404 }
1405 
1407 {
1408  DASHContext *c = s->priv_data;
1409  int64_t num = 0;
1410  int64_t start_time_offset = 0;
1411 
1412  if (c->is_live) {
1413  if (pls->n_fragments) {
1414  av_log(s, AV_LOG_TRACE, "in n_fragments mode\n");
1415  num = pls->first_seq_no;
1416  } else if (pls->n_timelines) {
1417  av_log(s, AV_LOG_TRACE, "in n_timelines mode\n");
1418  start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - 60 * pls->fragment_timescale; // 60 seconds before end
1419  num = calc_next_seg_no_from_timelines(pls, start_time_offset);
1420  if (num == -1)
1421  num = pls->first_seq_no;
1422  else
1423  num += pls->first_seq_no;
1424  } else if (pls->fragment_duration){
1425  av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset);
1426  if (pls->presentation_timeoffset) {
1427  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time;
1428  } else if (c->publish_time > 0 && !c->availability_start_time) {
1429  if (c->min_buffer_time) {
1430  num = pls->first_seq_no + (((c->publish_time + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time;
1431  } else {
1432  num = pls->first_seq_no + (((c->publish_time - c->time_shift_buffer_depth + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
1433  }
1434  } else {
1435  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
1436  }
1437  }
1438  } else {
1439  num = pls->first_seq_no;
1440  }
1441  return num;
1442 }
1443 
1445 {
1446  DASHContext *c = s->priv_data;
1447  int64_t num = 0;
1448 
1449  if (c->is_live && pls->fragment_duration) {
1450  av_log(s, AV_LOG_TRACE, "in live mode\n");
1451  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->time_shift_buffer_depth) * pls->fragment_timescale) / pls->fragment_duration;
1452  } else {
1453  num = pls->first_seq_no;
1454  }
1455  return num;
1456 }
1457 
1459 {
1460  int64_t num = 0;
1461 
1462  if (pls->n_fragments) {
1463  num = pls->first_seq_no + pls->n_fragments - 1;
1464  } else if (pls->n_timelines) {
1465  int i = 0;
1466  num = pls->first_seq_no + pls->n_timelines - 1;
1467  for (i = 0; i < pls->n_timelines; i++) {
1468  if (pls->timelines[i]->repeat == -1) {
1469  int length_of_each_segment = pls->timelines[i]->duration / pls->fragment_timescale;
1470  num = c->period_duration / length_of_each_segment;
1471  } else {
1472  num += pls->timelines[i]->repeat;
1473  }
1474  }
1475  } else if (c->is_live && pls->fragment_duration) {
1476  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale) / pls->fragment_duration;
1477  } else if (pls->fragment_duration) {
1478  num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
1479  }
1480 
1481  return num;
1482 }
1483 
1484 static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
1485 {
1486  if (rep_dest && rep_src ) {
1487  free_timelines_list(rep_dest);
1488  rep_dest->timelines = rep_src->timelines;
1489  rep_dest->n_timelines = rep_src->n_timelines;
1490  rep_dest->first_seq_no = rep_src->first_seq_no;
1491  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1492  rep_src->timelines = NULL;
1493  rep_src->n_timelines = 0;
1494  rep_dest->cur_seq_no = rep_src->cur_seq_no;
1495  }
1496 }
1497 
1498 static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
1499 {
1500  if (rep_dest && rep_src ) {
1501  free_fragment_list(rep_dest);
1502  if (rep_src->start_number > (rep_dest->start_number + rep_dest->n_fragments))
1503  rep_dest->cur_seq_no = 0;
1504  else
1505  rep_dest->cur_seq_no += rep_src->start_number - rep_dest->start_number;
1506  rep_dest->fragments = rep_src->fragments;
1507  rep_dest->n_fragments = rep_src->n_fragments;
1508  rep_dest->parent = rep_src->parent;
1509  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1510  rep_src->fragments = NULL;
1511  rep_src->n_fragments = 0;
1512  }
1513 }
1514 
1515 
1517 {
1518  int ret = 0, i;
1519  DASHContext *c = s->priv_data;
1520  // save current context
1521  int n_videos = c->n_videos;
1522  struct representation **videos = c->videos;
1523  int n_audios = c->n_audios;
1524  struct representation **audios = c->audios;
1525  int n_subtitles = c->n_subtitles;
1526  struct representation **subtitles = c->subtitles;
1527  char *base_url = c->base_url;
1528 
1529  c->base_url = NULL;
1530  c->n_videos = 0;
1531  c->videos = NULL;
1532  c->n_audios = 0;
1533  c->audios = NULL;
1534  c->n_subtitles = 0;
1535  c->subtitles = NULL;
1536  ret = parse_manifest(s, s->url, NULL);
1537  if (ret)
1538  goto finish;
1539 
1540  if (c->n_videos != n_videos) {
1542  "new manifest has mismatched no. of video representations, %d -> %d\n",
1543  n_videos, c->n_videos);
1544  return AVERROR_INVALIDDATA;
1545  }
1546  if (c->n_audios != n_audios) {
1548  "new manifest has mismatched no. of audio representations, %d -> %d\n",
1549  n_audios, c->n_audios);
1550  return AVERROR_INVALIDDATA;
1551  }
1552  if (c->n_subtitles != n_subtitles) {
1554  "new manifest has mismatched no. of subtitles representations, %d -> %d\n",
1555  n_subtitles, c->n_subtitles);
1556  return AVERROR_INVALIDDATA;
1557  }
1558 
1559  for (i = 0; i < n_videos; i++) {
1560  struct representation *cur_video = videos[i];
1561  struct representation *ccur_video = c->videos[i];
1562  if (cur_video->timelines) {
1563  // calc current time
1564  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale;
1565  // update segments
1566  ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1);
1567  if (ccur_video->cur_seq_no >= 0) {
1568  move_timelines(ccur_video, cur_video, c);
1569  }
1570  }
1571  if (cur_video->fragments) {
1572  move_segments(ccur_video, cur_video, c);
1573  }
1574  }
1575  for (i = 0; i < n_audios; i++) {
1576  struct representation *cur_audio = audios[i];
1577  struct representation *ccur_audio = c->audios[i];
1578  if (cur_audio->timelines) {
1579  // calc current time
1580  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale;
1581  // update segments
1582  ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1);
1583  if (ccur_audio->cur_seq_no >= 0) {
1584  move_timelines(ccur_audio, cur_audio, c);
1585  }
1586  }
1587  if (cur_audio->fragments) {
1588  move_segments(ccur_audio, cur_audio, c);
1589  }
1590  }
1591 
1592 finish:
1593  // restore context
1594  if (c->base_url)
1595  av_free(base_url);
1596  else
1597  c->base_url = base_url;
1598 
1599  if (c->subtitles)
1601  if (c->audios)
1602  free_audio_list(c);
1603  if (c->videos)
1604  free_video_list(c);
1605 
1606  c->n_subtitles = n_subtitles;
1607  c->subtitles = subtitles;
1608  c->n_audios = n_audios;
1609  c->audios = audios;
1610  c->n_videos = n_videos;
1611  c->videos = videos;
1612  return ret;
1613 }
1614 
1615 static struct fragment *get_current_fragment(struct representation *pls)
1616 {
1617  int64_t min_seq_no = 0;
1618  int64_t max_seq_no = 0;
1619  struct fragment *seg = NULL;
1620  struct fragment *seg_ptr = NULL;
1621  DASHContext *c = pls->parent->priv_data;
1622 
1623  while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) {
1624  if (pls->cur_seq_no < pls->n_fragments) {
1625  seg_ptr = pls->fragments[pls->cur_seq_no];
1626  seg = av_mallocz(sizeof(struct fragment));
1627  if (!seg) {
1628  return NULL;
1629  }
1630  seg->url = av_strdup(seg_ptr->url);
1631  if (!seg->url) {
1632  av_free(seg);
1633  return NULL;
1634  }
1635  seg->size = seg_ptr->size;
1636  seg->url_offset = seg_ptr->url_offset;
1637  return seg;
1638  } else if (c->is_live) {
1639  refresh_manifest(pls->parent);
1640  } else {
1641  break;
1642  }
1643  }
1644  if (c->is_live) {
1645  min_seq_no = calc_min_seg_no(pls->parent, pls);
1646  max_seq_no = calc_max_seg_no(pls, c);
1647 
1648  if (pls->timelines || pls->fragments) {
1649  refresh_manifest(pls->parent);
1650  }
1651  if (pls->cur_seq_no <= min_seq_no) {
1652  av_log(pls->parent, AV_LOG_VERBOSE, "old fragment: cur[%"PRId64"] min[%"PRId64"] max[%"PRId64"]\n", (int64_t)pls->cur_seq_no, min_seq_no, max_seq_no);
1653  pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls);
1654  } else if (pls->cur_seq_no > max_seq_no) {
1655  av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] max[%"PRId64"]\n", min_seq_no, max_seq_no);
1656  }
1657  seg = av_mallocz(sizeof(struct fragment));
1658  if (!seg) {
1659  return NULL;
1660  }
1661  } else if (pls->cur_seq_no <= pls->last_seq_no) {
1662  seg = av_mallocz(sizeof(struct fragment));
1663  if (!seg) {
1664  return NULL;
1665  }
1666  }
1667  if (seg) {
1668  char *tmpfilename;
1669  if (!pls->url_template) {
1670  av_log(pls->parent, AV_LOG_ERROR, "Cannot get fragment, missing template URL\n");
1671  av_free(seg);
1672  return NULL;
1673  }
1674  tmpfilename = av_mallocz(c->max_url_size);
1675  if (!tmpfilename) {
1676  av_free(seg);
1677  return NULL;
1678  }
1679  ff_dash_fill_tmpl_params(tmpfilename, c->max_url_size, pls->url_template, 0, pls->cur_seq_no, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no));
1680  seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename);
1681  if (!seg->url) {
1682  av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template);
1683  seg->url = av_strdup(pls->url_template);
1684  if (!seg->url) {
1685  av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template);
1686  av_free(tmpfilename);
1687  av_free(seg);
1688  return NULL;
1689  }
1690  }
1691  av_free(tmpfilename);
1692  seg->size = -1;
1693  }
1694 
1695  return seg;
1696 }
1697 
1698 static int read_from_url(struct representation *pls, struct fragment *seg,
1699  uint8_t *buf, int buf_size)
1700 {
1701  int ret;
1702 
1703  /* limit read if the fragment was only a part of a file */
1704  if (seg->size >= 0)
1705  buf_size = FFMIN(buf_size, pls->cur_seg_size - pls->cur_seg_offset);
1706 
1707  ret = avio_read(pls->input, buf, buf_size);
1708  if (ret > 0)
1709  pls->cur_seg_offset += ret;
1710 
1711  return ret;
1712 }
1713 
1714 static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
1715 {
1716  AVDictionary *opts = NULL;
1717  char *url = NULL;
1718  int ret = 0;
1719 
1720  url = av_mallocz(c->max_url_size);
1721  if (!url) {
1722  ret = AVERROR(ENOMEM);
1723  goto cleanup;
1724  }
1725 
1726  if (seg->size >= 0) {
1727  /* try to restrict the HTTP request to the part we want
1728  * (if this is in fact a HTTP request) */
1729  av_dict_set_int(&opts, "offset", seg->url_offset, 0);
1730  av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
1731  }
1732 
1733  ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url);
1734  av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64"\n",
1735  url, seg->url_offset);
1736  ret = open_url(pls->parent, &pls->input, url, &c->avio_opts, opts, NULL);
1737 
1738 cleanup:
1739  av_free(url);
1740  av_dict_free(&opts);
1741  pls->cur_seg_offset = 0;
1742  pls->cur_seg_size = seg->size;
1743  return ret;
1744 }
1745 
1746 static int update_init_section(struct representation *pls)
1747 {
1748  static const int max_init_section_size = 1024 * 1024;
1749  DASHContext *c = pls->parent->priv_data;
1750  int64_t sec_size;
1751  int64_t urlsize;
1752  int ret;
1753 
1754  if (!pls->init_section || pls->init_sec_buf)
1755  return 0;
1756 
1757  ret = open_input(c, pls, pls->init_section);
1758  if (ret < 0) {
1760  "Failed to open an initialization section\n");
1761  return ret;
1762  }
1763 
1764  if (pls->init_section->size >= 0)
1765  sec_size = pls->init_section->size;
1766  else if ((urlsize = avio_size(pls->input)) >= 0)
1767  sec_size = urlsize;
1768  else
1769  sec_size = max_init_section_size;
1770 
1771  av_log(pls->parent, AV_LOG_DEBUG,
1772  "Downloading an initialization section of size %"PRId64"\n",
1773  sec_size);
1774 
1775  sec_size = FFMIN(sec_size, max_init_section_size);
1776 
1777  av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size);
1778 
1779  ret = read_from_url(pls, pls->init_section, pls->init_sec_buf,
1780  pls->init_sec_buf_size);
1781  ff_format_io_close(pls->parent, &pls->input);
1782 
1783  if (ret < 0)
1784  return ret;
1785 
1786  pls->init_sec_data_len = ret;
1787  pls->init_sec_buf_read_offset = 0;
1788 
1789  return 0;
1790 }
1791 
1792 static int64_t seek_data(void *opaque, int64_t offset, int whence)
1793 {
1794  struct representation *v = opaque;
1795  if (v->n_fragments && !v->init_sec_data_len) {
1796  return avio_seek(v->input, offset, whence);
1797  }
1798 
1799  return AVERROR(ENOSYS);
1800 }
1801 
1802 static int read_data(void *opaque, uint8_t *buf, int buf_size)
1803 {
1804  int ret = 0;
1805  struct representation *v = opaque;
1806  DASHContext *c = v->parent->priv_data;
1807 
1808 restart:
1809  if (!v->input) {
1810  free_fragment(&v->cur_seg);
1811  v->cur_seg = get_current_fragment(v);
1812  if (!v->cur_seg) {
1813  ret = AVERROR_EOF;
1814  goto end;
1815  }
1816 
1817  /* load/update Media Initialization Section, if any */
1818  ret = update_init_section(v);
1819  if (ret)
1820  goto end;
1821 
1822  ret = open_input(c, v, v->cur_seg);
1823  if (ret < 0) {
1824  if (ff_check_interrupt(c->interrupt_callback)) {
1825  ret = AVERROR_EXIT;
1826  goto end;
1827  }
1828  av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist\n");
1829  v->cur_seq_no++;
1830  goto restart;
1831  }
1832  }
1833 
1835  /* Push init section out first before first actual fragment */
1836  int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size);
1837  memcpy(buf, v->init_sec_buf, copy_size);
1838  v->init_sec_buf_read_offset += copy_size;
1839  ret = copy_size;
1840  goto end;
1841  }
1842 
1843  /* check the v->cur_seg, if it is null, get current and double check if the new v->cur_seg*/
1844  if (!v->cur_seg) {
1845  v->cur_seg = get_current_fragment(v);
1846  }
1847  if (!v->cur_seg) {
1848  ret = AVERROR_EOF;
1849  goto end;
1850  }
1851  ret = read_from_url(v, v->cur_seg, buf, buf_size);
1852  if (ret > 0)
1853  goto end;
1854 
1855  if (c->is_live || v->cur_seq_no < v->last_seq_no) {
1856  if (!v->is_restart_needed)
1857  v->cur_seq_no++;
1858  v->is_restart_needed = 1;
1859  }
1860 
1861 end:
1862  return ret;
1863 }
1864 
1865 static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url,
1866  int flags, AVDictionary **opts)
1867 {
1869  "A DASH playlist item '%s' referred to an external file '%s'. "
1870  "Opening this file was forbidden for security reasons\n",
1871  s->url, url);
1872  return AVERROR(EPERM);
1873 }
1874 
1876 {
1877  /* note: the internal buffer could have changed */
1878  av_freep(&pls->pb.pub.buffer);
1879  memset(&pls->pb, 0x00, sizeof(pls->pb));
1880  pls->ctx->pb = NULL;
1881  avformat_close_input(&pls->ctx);
1882 }
1883 
1885 {
1886  DASHContext *c = s->priv_data;
1887  const AVInputFormat *in_fmt = NULL;
1888  AVDictionary *in_fmt_opts = NULL;
1889  uint8_t *avio_ctx_buffer = NULL;
1890  int ret = 0, i;
1891 
1892  if (pls->ctx) {
1894  }
1895 
1896  if (ff_check_interrupt(&s->interrupt_callback)) {
1897  ret = AVERROR_EXIT;
1898  goto fail;
1899  }
1900 
1901  if (!(pls->ctx = avformat_alloc_context())) {
1902  ret = AVERROR(ENOMEM);
1903  goto fail;
1904  }
1905 
1906  avio_ctx_buffer = av_malloc(INITIAL_BUFFER_SIZE);
1907  if (!avio_ctx_buffer ) {
1908  ret = AVERROR(ENOMEM);
1909  avformat_free_context(pls->ctx);
1910  pls->ctx = NULL;
1911  goto fail;
1912  }
1913  ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0,
1914  pls, read_data, NULL, c->is_live ? NULL : seek_data);
1915  pls->pb.pub.seekable = 0;
1916 
1917  if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
1918  goto fail;
1919 
1920  pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO;
1921  pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
1922  pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE;
1923  pls->ctx->interrupt_callback = s->interrupt_callback;
1924  ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, "", NULL, 0, 0);
1925  if (ret < 0) {
1926  av_log(s, AV_LOG_ERROR, "Error when loading first fragment of playlist\n");
1927  avformat_free_context(pls->ctx);
1928  pls->ctx = NULL;
1929  goto fail;
1930  }
1931 
1932  pls->ctx->pb = &pls->pb.pub;
1933  pls->ctx->io_open = nested_io_open;
1934 
1935  if (c->cenc_decryption_key)
1936  av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
1937  if (c->cenc_decryption_keys)
1938  av_dict_set(&in_fmt_opts, "decryption_keys", c->cenc_decryption_keys, 0);
1939 
1940  // provide additional information from mpd if available
1941  ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url
1942  av_dict_free(&in_fmt_opts);
1943  if (ret < 0)
1944  goto fail;
1945  if (pls->n_fragments) {
1946 #if FF_API_R_FRAME_RATE
1947  if (pls->framerate.den) {
1948  for (i = 0; i < pls->ctx->nb_streams; i++)
1949  pls->ctx->streams[i]->r_frame_rate = pls->framerate;
1950  }
1951 #endif
1953  if (ret < 0)
1954  goto fail;
1955  }
1956 
1957 fail:
1958  return ret;
1959 }
1960 
1962 {
1963  int ret = 0;
1964  int i;
1965 
1966  pls->parent = s;
1967  pls->cur_seq_no = calc_cur_seg_no(s, pls);
1968 
1969  if (!pls->last_seq_no)
1970  pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
1971 
1973  if (ret < 0)
1974  return ret;
1975 
1976  for (i = 0; i < pls->ctx->nb_streams; i++) {
1978  AVStream *ist = pls->ctx->streams[i];
1979  if (!st)
1980  return AVERROR(ENOMEM);
1981 
1982  st->id = i;
1983 
1985  if (ret < 0)
1986  return ret;
1987 
1989 
1990  // copy disposition
1991  st->disposition = ist->disposition;
1992  }
1993 
1994  return 0;
1995 }
1996 
1997 static int is_common_init_section_exist(struct representation **pls, int n_pls)
1998 {
1999  struct fragment *first_init_section = pls[0]->init_section;
2000  char *url =NULL;
2001  int64_t url_offset = -1;
2002  int64_t size = -1;
2003  int i = 0;
2004 
2005  if (first_init_section == NULL || n_pls == 0)
2006  return 0;
2007 
2008  url = first_init_section->url;
2009  url_offset = first_init_section->url_offset;
2010  size = pls[0]->init_section->size;
2011  for (i=0;i<n_pls;i++) {
2012  if (!pls[i]->init_section)
2013  continue;
2014 
2015  if (av_strcasecmp(pls[i]->init_section->url, url) ||
2016  pls[i]->init_section->url_offset != url_offset ||
2017  pls[i]->init_section->size != size) {
2018  return 0;
2019  }
2020  }
2021  return 1;
2022 }
2023 
2024 static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
2025 {
2026  rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
2027  if (!rep_dest->init_sec_buf) {
2028  av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n");
2029  return AVERROR(ENOMEM);
2030  }
2031  memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
2032  rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
2033  rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
2034  rep_dest->cur_timestamp = rep_src->cur_timestamp;
2035 
2036  return 0;
2037 }
2038 
2039 static void move_metadata(AVStream *st, const char *key, char **value)
2040 {
2041  if (*value) {
2043  *value = NULL;
2044  }
2045 }
2046 
2048 {
2049  DASHContext *c = s->priv_data;
2050  struct representation *rep;
2051  AVProgram *program;
2052  int ret = 0;
2053  int stream_index = 0;
2054  int i;
2055 
2056  c->interrupt_callback = &s->interrupt_callback;
2057 
2058  if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0)
2059  return ret;
2060 
2061  if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
2062  return ret;
2063 
2064  /* If this isn't a live stream, fill the total duration of the
2065  * stream. */
2066  if (!c->is_live) {
2067  s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
2068  } else {
2069  av_dict_set(&c->avio_opts, "seekable", "0", 0);
2070  }
2071 
2072  if(c->n_videos)
2073  c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
2074 
2075  /* Open the demuxer for video and audio components if available */
2076  for (i = 0; i < c->n_videos; i++) {
2077  rep = c->videos[i];
2078  if (i > 0 && c->is_init_section_common_video) {
2079  ret = copy_init_section(rep, c->videos[0]);
2080  if (ret < 0)
2081  return ret;
2082  }
2083  ret = open_demux_for_component(s, rep);
2084 
2085  if (ret)
2086  return ret;
2087  rep->stream_index = stream_index;
2088  ++stream_index;
2089  }
2090 
2091  if(c->n_audios)
2092  c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
2093 
2094  for (i = 0; i < c->n_audios; i++) {
2095  rep = c->audios[i];
2096  if (i > 0 && c->is_init_section_common_audio) {
2097  ret = copy_init_section(rep, c->audios[0]);
2098  if (ret < 0)
2099  return ret;
2100  }
2101  ret = open_demux_for_component(s, rep);
2102 
2103  if (ret)
2104  return ret;
2105  rep->stream_index = stream_index;
2106  ++stream_index;
2107  }
2108 
2109  if (c->n_subtitles)
2110  c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles);
2111 
2112  for (i = 0; i < c->n_subtitles; i++) {
2113  rep = c->subtitles[i];
2114  if (i > 0 && c->is_init_section_common_subtitle) {
2115  ret = copy_init_section(rep, c->subtitles[0]);
2116  if (ret < 0)
2117  return ret;
2118  }
2119  ret = open_demux_for_component(s, rep);
2120 
2121  if (ret)
2122  return ret;
2123  rep->stream_index = stream_index;
2124  ++stream_index;
2125  }
2126 
2127  if (!stream_index)
2128  return AVERROR_INVALIDDATA;
2129 
2130  /* Create a program */
2131  program = av_new_program(s, 0);
2132  if (!program)
2133  return AVERROR(ENOMEM);
2134 
2135  for (i = 0; i < c->n_videos; i++) {
2136  rep = c->videos[i];
2138  rep->assoc_stream = s->streams[rep->stream_index];
2139  if (rep->bandwidth > 0)
2140  av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0);
2141  move_metadata(rep->assoc_stream, "id", &rep->id);
2142  }
2143  for (i = 0; i < c->n_audios; i++) {
2144  rep = c->audios[i];
2146  rep->assoc_stream = s->streams[rep->stream_index];
2147  if (rep->bandwidth > 0)
2148  av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0);
2149  move_metadata(rep->assoc_stream, "id", &rep->id);
2150  move_metadata(rep->assoc_stream, "language", &rep->lang);
2151  }
2152  for (i = 0; i < c->n_subtitles; i++) {
2153  rep = c->subtitles[i];
2155  rep->assoc_stream = s->streams[rep->stream_index];
2156  move_metadata(rep->assoc_stream, "id", &rep->id);
2157  move_metadata(rep->assoc_stream, "language", &rep->lang);
2158  }
2159 
2160  return 0;
2161 }
2162 
2164 {
2165  int i, j;
2166 
2167  for (i = 0; i < n; i++) {
2168  struct representation *pls = p[i];
2169  int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL;
2170 
2171  if (needed && !pls->ctx) {
2172  pls->cur_seg_offset = 0;
2173  pls->init_sec_buf_read_offset = 0;
2174  /* Catch up */
2175  for (j = 0; j < n; j++) {
2176  pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no);
2177  }
2179  av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index);
2180  } else if (!needed && pls->ctx) {
2182  ff_format_io_close(pls->parent, &pls->input);
2183  av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index);
2184  }
2185  }
2186 }
2187 
2189 {
2190  DASHContext *c = s->priv_data;
2191  int ret = 0, i;
2192  int64_t mints = 0;
2193  struct representation *cur = NULL;
2194  struct representation *rep = NULL;
2195 
2196  recheck_discard_flags(s, c->videos, c->n_videos);
2197  recheck_discard_flags(s, c->audios, c->n_audios);
2198  recheck_discard_flags(s, c->subtitles, c->n_subtitles);
2199 
2200  for (i = 0; i < c->n_videos; i++) {
2201  rep = c->videos[i];
2202  if (!rep->ctx)
2203  continue;
2204  if (!cur || rep->cur_timestamp < mints) {
2205  cur = rep;
2206  mints = rep->cur_timestamp;
2207  }
2208  }
2209  for (i = 0; i < c->n_audios; i++) {
2210  rep = c->audios[i];
2211  if (!rep->ctx)
2212  continue;
2213  if (!cur || rep->cur_timestamp < mints) {
2214  cur = rep;
2215  mints = rep->cur_timestamp;
2216  }
2217  }
2218 
2219  for (i = 0; i < c->n_subtitles; i++) {
2220  rep = c->subtitles[i];
2221  if (!rep->ctx)
2222  continue;
2223  if (!cur || rep->cur_timestamp < mints) {
2224  cur = rep;
2225  mints = rep->cur_timestamp;
2226  }
2227  }
2228 
2229  if (!cur) {
2230  return AVERROR_INVALIDDATA;
2231  }
2232  while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
2233  ret = av_read_frame(cur->ctx, pkt);
2234  if (ret >= 0) {
2235  /* If we got a packet, return it */
2236  cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
2237  pkt->stream_index = cur->stream_index;
2238  return 0;
2239  }
2240  if (cur->is_restart_needed) {
2241  cur->cur_seg_offset = 0;
2242  cur->init_sec_buf_read_offset = 0;
2243  cur->is_restart_needed = 0;
2244  ff_format_io_close(cur->parent, &cur->input);
2246  }
2247  }
2248  return AVERROR_EOF;
2249 }
2250 
2252 {
2253  DASHContext *c = s->priv_data;
2254  free_audio_list(c);
2255  free_video_list(c);
2257  av_dict_free(&c->avio_opts);
2258  av_freep(&c->base_url);
2259  return 0;
2260 }
2261 
2262 static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
2263 {
2264  int ret = 0;
2265  int i = 0;
2266  int j = 0;
2267  int64_t duration = 0;
2268 
2269  av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms] %s\n",
2270  seek_pos_msec, dry_run ? " (dry)" : "");
2271 
2272  // single fragment mode
2273  if (pls->n_fragments == 1) {
2274  pls->cur_timestamp = 0;
2275  pls->cur_seg_offset = 0;
2276  if (dry_run)
2277  return 0;
2278  ff_read_frame_flush(pls->ctx);
2279  return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags);
2280  }
2281 
2282  ff_format_io_close(pls->parent, &pls->input);
2283 
2284  // find the nearest fragment
2285  if (pls->n_timelines > 0 && pls->fragment_timescale > 0) {
2286  int64_t num = pls->first_seq_no;
2287  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] "
2288  "last_seq_no[%"PRId64"].\n",
2289  (int)pls->n_timelines, (int64_t)pls->last_seq_no);
2290  for (i = 0; i < pls->n_timelines; i++) {
2291  if (pls->timelines[i]->starttime > 0) {
2292  duration = pls->timelines[i]->starttime;
2293  }
2294  duration += pls->timelines[i]->duration;
2295  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2296  goto set_seq_num;
2297  }
2298  for (j = 0; j < pls->timelines[i]->repeat; j++) {
2299  duration += pls->timelines[i]->duration;
2300  num++;
2301  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2302  goto set_seq_num;
2303  }
2304  }
2305  num++;
2306  }
2307 
2308 set_seq_num:
2309  pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num;
2310  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"].\n",
2311  (int64_t)pls->cur_seq_no);
2312  } else if (pls->fragment_duration > 0) {
2313  pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000;
2314  } else {
2315  av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n");
2316  pls->cur_seq_no = pls->first_seq_no;
2317  }
2318  pls->cur_timestamp = 0;
2319  pls->cur_seg_offset = 0;
2320  pls->init_sec_buf_read_offset = 0;
2321  ret = dry_run ? 0 : reopen_demux_for_component(s, pls);
2322 
2323  return ret;
2324 }
2325 
2326 static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
2327 {
2328  int ret = 0, i;
2329  DASHContext *c = s->priv_data;
2330  int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000,
2331  s->streams[stream_index]->time_base.den,
2334  if ((flags & AVSEEK_FLAG_BYTE) || c->is_live)
2335  return AVERROR(ENOSYS);
2336 
2337  /* Seek in discarded streams with dry_run=1 to avoid reopening them */
2338  for (i = 0; i < c->n_videos; i++) {
2339  if (!ret)
2340  ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx);
2341  }
2342  for (i = 0; i < c->n_audios; i++) {
2343  if (!ret)
2344  ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
2345  }
2346  for (i = 0; i < c->n_subtitles; i++) {
2347  if (!ret)
2348  ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
2349  }
2350 
2351  return ret;
2352 }
2353 
2354 static int dash_probe(const AVProbeData *p)
2355 {
2356  if (!av_stristr(p->buf, "<MPD"))
2357  return 0;
2358 
2359  if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") ||
2360  av_stristr(p->buf, "dash:profile:isoff-live:2011") ||
2361  av_stristr(p->buf, "dash:profile:isoff-live:2012") ||
2362  av_stristr(p->buf, "dash:profile:isoff-main:2011") ||
2363  av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) {
2364  return AVPROBE_SCORE_MAX;
2365  }
2366  if (av_stristr(p->buf, "dash:profile")) {
2367  return AVPROBE_SCORE_MAX;
2368  }
2369 
2370  return 0;
2371 }
2372 
2373 #define OFFSET(x) offsetof(DASHContext, x)
2374 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
2375 static const AVOption dash_options[] = {
2376  {"allowed_extensions", "List of file extensions that dash is allowed to access",
2377  OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
2378  {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"},
2379  INT_MIN, INT_MAX, FLAGS},
2380  { "cenc_decryption_key", "Media default decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
2381  { "cenc_decryption_keys", "Media decryption keys by KID (hex)", OFFSET(cenc_decryption_keys), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
2382  {NULL}
2383 };
2384 
2385 static const AVClass dash_class = {
2386  .class_name = "dash",
2387  .item_name = av_default_item_name,
2388  .option = dash_options,
2389  .version = LIBAVUTIL_VERSION_INT,
2390 };
2391 
2393  .p.name = "dash",
2394  .p.long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"),
2395  .p.priv_class = &dash_class,
2396  .p.flags = AVFMT_NO_BYTE_SEEK,
2397  .priv_data_size = sizeof(DASHContext),
2398  .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
2404 };
AV_OPT_SEARCH_CHILDREN
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:605
flags
const SwsFlags flags[]
Definition: swscale.c:61
reopen_demux_for_component
static int reopen_demux_for_component(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1884
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:134
close_demux_for_component
static void close_demux_for_component(struct representation *pls)
Definition: dashdec.c:1875
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:203
ffio_open_whitelist
int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist)
Definition: avio.c:472
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
calc_next_seg_no_from_timelines
static int64_t calc_next_seg_no_from_timelines(struct representation *pls, int64_t cur_time)
Definition: dashdec.c:291
AVFMT_NO_BYTE_SEEK
#define AVFMT_NO_BYTE_SEEK
Format does not allow seeking by bytes.
Definition: avformat.h:486
program
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C program
Definition: undefined.txt:6
open_demux_for_component
static int open_demux_for_component(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1961
read_data
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition: dashdec.c:1802
ffio_init_context
void ffio_init_context(FFIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, const uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition: aviobuf.c:50
ffio_copy_url_options
int ffio_copy_url_options(AVIOContext *pb, AVDictionary **avio_opts)
Read url related dictionary options from the AVIOContext and write to the given dictionary.
Definition: aviobuf.c:994
representation::start_number
int64_t start_number
Definition: dashdec.c:101
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
get_current_time_in_sec
static uint64_t get_current_time_in_sec(void)
Definition: dashdec.c:177
ishttp
static int ishttp(char *url)
Definition: dashdec.c:166
calc_min_seg_no
static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1444
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
FLAGS
#define FLAGS
Definition: dashdec.c:2374
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:58
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
representation::assoc_stream
AVStream * assoc_stream
Definition: dashdec.c:91
free_video_list
static void free_video_list(DASHContext *c)
Definition: dashdec.c:372
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
AVStream::discard
enum AVDiscard discard
Selects which packets can be discarded at will and do not need to be demuxed.
Definition: avformat.h:815
representation::init_sec_buf_read_offset
uint32_t init_sec_buf_read_offset
Definition: dashdec.c:118
representation::cur_seq_no
int64_t cur_seq_no
Definition: dashdec.c:108
get_current_fragment
static struct fragment * get_current_fragment(struct representation *pls)
Definition: dashdec.c:1615
int64_t
long long int64_t
Definition: coverity.c:34
DASHContext::n_subtitles
int n_subtitles
Definition: dashdec.c:131
DASHContext::is_init_section_common_subtitle
int is_init_section_common_subtitle
Definition: dashdec.c:162
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:208
representation::cur_seg_offset
int64_t cur_seg_offset
Definition: dashdec.c:109
dash_close
static int dash_close(AVFormatContext *s)
Definition: dashdec.c:2251
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:130
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1332
AVOption
AVOption.
Definition: opt.h:429
DASHContext::interrupt_callback
AVIOInterruptCB * interrupt_callback
Definition: dashdec.c:152
parse_manifest_segmenturlnode
static int parse_manifest_segmenturlnode(AVFormatContext *s, struct representation *rep, xmlNodePtr fragmenturl_node, xmlNodePtr *baseurl_nodes, char *rep_id_val, char *rep_bandwidth_val)
Definition: dashdec.c:600
AVFMT_FLAG_CUSTOM_IO
#define AVFMT_FLAG_CUSTOM_IO
The caller has supplied a custom AVIOContext, don't avio_close() it.
Definition: avformat.h:1423
AVSEEK_FLAG_BYTE
#define AVSEEK_FLAG_BYTE
seeking based on position in bytes
Definition: avformat.h:2475
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
representation::id
char * id
Definition: dashdec.c:87
DASHContext::n_audios
int n_audios
Definition: dashdec.c:129
AVDictionary
Definition: dict.c:32
representation::last_seq_no
int64_t last_seq_no
Definition: dashdec.c:100
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
AVFormatContext::probesize
int64_t probesize
Maximum number of bytes read from input in order to determine stream properties.
Definition: avformat.h:1448
av_read_frame
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
Return the next frame of a stream.
Definition: demux.c:1588
ff_read_frame_flush
void ff_read_frame_flush(AVFormatContext *s)
Flush the frame reader.
Definition: seek.c:716
read_from_url
static int read_from_url(struct representation *pls, struct fragment *seg, uint8_t *buf, int buf_size)
Definition: dashdec.c:1698
avio_size
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:326
representation::n_fragments
int n_fragments
Definition: dashdec.c:93
FFIOContext
Definition: avio_internal.h:28
DASHContext::availability_end_time
uint64_t availability_end_time
Definition: dashdec.c:138
find_child_node_by_name
static xmlNodePtr find_child_node_by_name(xmlNodePtr rootnode, const char *nodename)
Definition: dashdec.c:539
representation::first_seq_no
int64_t first_seq_no
Definition: dashdec.c:99
AVIOInterruptCB
Callback for checking whether to abort blocking functions.
Definition: avio.h:59
fragment
Definition: dashdec.c:37
DASHContext::n_videos
int n_videos
Definition: dashdec.c:127
DASHContext
Definition: dashdec.c:123
get_segment_start_time_based_on_timeline
static int64_t get_segment_start_time_based_on_timeline(struct representation *pls, int64_t cur_seq_no)
Definition: dashdec.c:256
DASHContext::subtitles
struct representation ** subtitles
Definition: dashdec.c:132
AVPROBE_SCORE_MAX
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:463
avformat_close_input
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: demux.c:377
AVFormatContext::interrupt_callback
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1534
avpriv_set_pts_info
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: avformat.c:780
representation::init_section
struct fragment * init_section
Definition: dashdec.c:114
finish
static void finish(void)
Definition: movenc.c:374
DASHContext::publish_time
uint64_t publish_time
Definition: dashdec.c:139
free_timelines_list
static void free_timelines_list(struct representation *pls)
Definition: dashdec.c:341
calc_max_seg_no
static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c)
Definition: dashdec.c:1458
free_fragment
static void free_fragment(struct fragment **seg)
Definition: dashdec.c:321
fail
#define fail()
Definition: checkasm.h:219
calc_cur_seg_no
static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1406
read_seek
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition: libcdio.c:151
read_close
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:143
val
static double val(void *priv, double ch)
Definition: aeval.c:77
recheck_discard_flags
static void recheck_discard_flags(AVFormatContext *s, struct representation **p, int n)
Definition: dashdec.c:2163
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
av_timegm
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:573
av_new_program
AVProgram * av_new_program(AVFormatContext *ac, int id)
Definition: avformat.c:270
get_utc_date_time_insec
static uint64_t get_utc_date_time_insec(AVFormatContext *s, const char *datetime)
Definition: dashdec.c:182
get_content_type
static enum AVMediaType get_content_type(xmlNodePtr node)
Definition: dashdec.c:556
ff_check_interrupt
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition: avio.c:855
AVRational::num
int num
Numerator.
Definition: rational.h:59
dash_options
static const AVOption dash_options[]
Definition: dashdec.c:2375
DASHContext::avio_opts
AVDictionary * avio_opts
Definition: dashdec.c:154
AV_DICT_DONT_STRDUP_VAL
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition: dict.h:79
DASHContext::suggested_presentation_delay
uint64_t suggested_presentation_delay
Definition: dashdec.c:136
seek_data
static int64_t seek_data(void *opaque, int64_t offset, int whence)
Definition: dashdec.c:1792
aligned
static int aligned(int val)
Definition: dashdec.c:172
representation::n_timelines
int n_timelines
Definition: dashdec.c:96
representation::pb
FFIOContext pb
Definition: dashdec.c:81
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AVInputFormat
Definition: avformat.h:544
free_representation
static void free_representation(struct representation *pls)
Definition: dashdec.c:352
avformat_open_input
int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: demux.c:231
read_packet
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_read_callback.c:42
move_metadata
static void move_metadata(AVStream *st, const char *key, char **value)
Definition: dashdec.c:2039
DASHContext::max_url_size
int max_url_size
Definition: dashdec.c:155
DASHContext::allowed_extensions
char * allowed_extensions
Definition: dashdec.c:153
move_segments
static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
Definition: dashdec.c:1498
s
#define s(width, name)
Definition: cbs_vp9.c:198
fragment::url_offset
int64_t url_offset
Definition: dashdec.c:38
DASHContext::adaptionset_lang
char * adaptionset_lang
Definition: dashdec.c:149
avio_read_to_bprint
int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size)
Read contents of h into print buffer, up to max_size bytes, or up to EOF.
Definition: aviobuf.c:1254
av_seek_frame
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Seek to the keyframe at timestamp.
Definition: seek.c:641
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1415
AVInputFormat::name
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:549
free_fragment_list
static void free_fragment_list(struct representation *pls)
Definition: dashdec.c:330
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:201
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:179
av_match_ext
int av_match_ext(const char *filename, const char *extensions)
Return a positive value if the given filename has one of the given extensions, 0 otherwise.
Definition: format.c:41
representation::is_restart_needed
int is_restart_needed
Definition: dashdec.c:120
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
parse_programinformation
static int parse_programinformation(AVFormatContext *s, xmlNodePtr node)
Definition: dashdec.c:1203
get_duration_insec
static uint32_t get_duration_insec(AVFormatContext *s, const char *duration)
Definition: dashdec.c:212
DASHContext::videos
struct representation ** videos
Definition: dashdec.c:128
INITIAL_BUFFER_SIZE
#define INITIAL_BUFFER_SIZE
Definition: dashdec.c:35
key
const char * key
Definition: hwcontext_opencl.c:189
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
representation::cur_timestamp
int64_t cur_timestamp
Definition: dashdec.c:119
timeline::duration
int64_t duration
Definition: dashdec.c:71
representation::init_sec_buf_size
uint32_t init_sec_buf_size
Definition: dashdec.c:116
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
representation::stream_index
int stream_index
Definition: dashdec.c:85
AVFormatContext::max_analyze_duration
int64_t max_analyze_duration
Maximum duration (in AV_TIME_BASE units) of the data read from input in avformat_find_stream_info().
Definition: avformat.h:1456
representation::ctx
AVFormatContext * ctx
Definition: dashdec.c:84
FF_INFMT_FLAG_INIT_CLEANUP
#define FF_INFMT_FLAG_INIT_CLEANUP
For an FFInputFormat with this flag set read_close() needs to be called by the caller upon read_heade...
Definition: demux.h:35
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: defs.h:232
AVFormatContext
Format I/O context.
Definition: avformat.h:1264
representation::lang
char * lang
Definition: dashdec.c:88
internal.h
opts
static AVDictionary * opts
Definition: movenc.c:51
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:767
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVSEEK_FLAG_BACKWARD
#define AVSEEK_FLAG_BACKWARD
Definition: avformat.h:2474
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:783
NULL
#define NULL
Definition: coverity.c:32
av_program_add_stream_index
void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx)
Definition: avformat.c:301
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_strireplace
char * av_strireplace(const char *str, const char *from, const char *to)
Locale-independent strings replace.
Definition: avstring.c:230
is_common_init_section_exist
static int is_common_init_section_exist(struct representation **pls, int n_pls)
Definition: dashdec.c:1997
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:825
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
dash_read_seek
static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: dashdec.c:2326
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1306
parseutils.h
AVProbeData
This structure contains the data a format has to probe a file.
Definition: avformat.h:451
move_timelines
static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
Definition: dashdec.c:1484
representation::timelines
struct timeline ** timelines
Definition: dashdec.c:97
AVStream::metadata
AVDictionary * metadata
Definition: avformat.h:824
DASHContext::minimum_update_period
uint64_t minimum_update_period
Definition: dashdec.c:140
time.h
ff_dash_demuxer
const FFInputFormat ff_dash_demuxer
Definition: dashdec.c:2392
timeline::starttime
int64_t starttime
Definition: dashdec.c:61
DASHContext::period_start
uint64_t period_start
Definition: dashdec.c:146
parse_manifest
static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
Definition: dashdec.c:1232
representation::url_template
char * url_template
Definition: dashdec.c:80
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1320
get_val_from_nodes_tab
static char * get_val_from_nodes_tab(xmlNodePtr *nodes, const int n_nodes, const char *attrname)
Definition: dashdec.c:523
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:133
av_strncasecmp
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:218
av_rescale_rnd
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
Rescale a 64-bit integer with specified rounding.
Definition: mathematics.c:58
DASHContext::time_shift_buffer_depth
uint64_t time_shift_buffer_depth
Definition: dashdec.c:141
avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
Read packets of a media file to get stream information.
Definition: demux.c:2607
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
resolve_content_path
static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes)
Definition: dashdec.c:707
AVMediaType
AVMediaType
Definition: avutil.h:198
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:94
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:163
DASHContext::media_presentation_duration
uint64_t media_presentation_duration
Definition: dashdec.c:135
AVIOContext::seekable
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:261
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
SET_REPRESENTATION_SEQUENCE_BASE_INFO
#define SET_REPRESENTATION_SEQUENCE_BASE_INFO(arg, cnt)
Definition: dashdec.c:847
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
FFIOContext::pub
AVIOContext pub
Definition: avio_internal.h:29
start_time
static int64_t start_time
Definition: ffplay.c:328
size
int size
Definition: twinvq_data.h:10344
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
representation::bandwidth
int bandwidth
Definition: dashdec.c:89
representation::parent
AVFormatContext * parent
Definition: dashdec.c:83
ff_format_io_close
int ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: avformat.c:871
AVMEDIA_TYPE_UNKNOWN
@ AVMEDIA_TYPE_UNKNOWN
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:199
OFFSET
#define OFFSET(x)
Definition: dashdec.c:2373
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
FFInputFormat::p
AVInputFormat p
The public AVInputFormat.
Definition: demux.h:70
copy_init_section
static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
Definition: dashdec.c:2024
DASHContext::availability_start_time
uint64_t availability_start_time
Definition: dashdec.c:137
representation::init_sec_data_len
uint32_t init_sec_data_len
Definition: dashdec.c:117
dash_read_header
static int dash_read_header(AVFormatContext *s)
Definition: dashdec.c:2047
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
free_audio_list
static void free_audio_list(DASHContext *c)
Definition: dashdec.c:383
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:233
read_header
static int read_header(FFV1Context *f, RangeCoder *c)
Definition: ffv1dec.c:498
representation::framerate
AVRational framerate
Definition: dashdec.c:90
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:36
av_probe_input_buffer
int av_probe_input_buffer(AVIOContext *pb, const AVInputFormat **fmt, const char *url, void *logctx, unsigned int offset, unsigned int max_probe_size)
Like av_probe_input_buffer2() but returns 0 on success.
Definition: format.c:348
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
DASHContext::cenc_decryption_key
char * cenc_decryption_key
Definition: dashdec.c:156
av_parse_video_rate
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
Definition: parseutils.c:181
open_url
static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, AVDictionary **opts, AVDictionary *opts2, int *is_http)
Definition: dashdec.c:405
bprint.h
free_subtitle_list
static void free_subtitle_list(DASHContext *c)
Definition: dashdec.c:394
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:581
avio_internal.h
dash_probe
static int dash_probe(const AVProbeData *p)
Definition: dashdec.c:2354
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:253
DASHContext::audios
struct representation ** audios
Definition: dashdec.c:130
representation::fragment_timescale
int64_t fragment_timescale
Definition: dashdec.c:104
needed
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is needed
Definition: filter_design.txt:212
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
DASHContext::is_init_section_common_audio
int is_init_section_common_audio
Definition: dashdec.c:161
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
parse_manifest_adaptationset
static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, xmlNodePtr period_baseurl_node, xmlNodePtr period_segmenttemplate_node, xmlNodePtr period_segmentlist_node)
Definition: dashdec.c:1147
url.h
fragment::url
char * url
Definition: dashdec.c:40
AVProgram
New fields can be added to the end with minor version bumps.
Definition: avformat.h:1188
demux.h
len
int len
Definition: vorbis_enc_data.h:426
av_rescale
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
DASHContext::min_buffer_time
uint64_t min_buffer_time
Definition: dashdec.c:142
DASHContext::cenc_decryption_keys
char * cenc_decryption_keys
Definition: dashdec.c:157
nested_io_open
static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **opts)
Definition: dashdec.c:1865
DASHContext::is_live
int is_live
Definition: dashdec.c:151
AVStream::disposition
int disposition
Stream disposition - a combination of AV_DISPOSITION_* flags.
Definition: avformat.h:813
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:756
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:744
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:236
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:81
av_strlcat
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes,...
Definition: avstring.c:95
representation::input
AVIOContext * input
Definition: dashdec.c:82
av_malloc
void * av_malloc(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:98
parse_manifest_segmenttimeline
static int parse_manifest_segmenttimeline(AVFormatContext *s, struct representation *rep, xmlNodePtr fragment_timeline_node)
Definition: dashdec.c:666
representation
Definition: dashdec.c:79
representation::init_sec_buf
uint8_t * init_sec_buf
Definition: dashdec.c:115
av_dynarray_add_nofree
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition: mem.c:315
MAX_URL_SIZE
#define MAX_URL_SIZE
Definition: internal.h:30
parse_manifest_adaptationset_attr
static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node)
Definition: dashdec.c:1134
AVRational::den
int den
Denominator.
Definition: rational.h:60
representation::cur_seg
struct fragment * cur_seg
Definition: dashdec.c:111
get_content_url
static char * get_content_url(xmlNodePtr *baseurl_nodes, int n_baseurl_nodes, int max_url_size, char *rep_id_val, char *rep_bandwidth_val, char *val)
Definition: dashdec.c:472
DASHContext::is_init_section_common_video
int is_init_section_common_video
Definition: dashdec.c:160
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: avformat.c:143
avio_read
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:615
AVStream::r_frame_rate
AVRational r_frame_rate
Real base framerate of the stream.
Definition: avformat.h:878
refresh_manifest
static int refresh_manifest(AVFormatContext *s)
Definition: dashdec.c:1516
AVFormatContext::io_open
int(* io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
A callback for opening new IO streams.
Definition: avformat.h:1864
update_init_section
static int update_init_section(struct representation *pls)
Definition: dashdec.c:1746
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
parse_manifest_representation
static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr node, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, xmlNodePtr period_baseurl_node, xmlNodePtr period_segmenttemplate_node, xmlNodePtr period_segmentlist_node, xmlNodePtr fragment_template_node, xmlNodePtr content_component_node, xmlNodePtr adaptionset_baseurl_node, xmlNodePtr adaptionset_segmentlist_node, xmlNodePtr adaptionset_supplementalproperty_node)
Definition: dashdec.c:884
AVPacket::stream_index
int stream_index
Definition: packet.h:590
dash_read_packet
static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dashdec.c:2188
open_input
static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
Definition: dashdec.c:1714
timeline
Definition: dashdec.c:48
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
av_dict_set_int
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition: dict.c:177
representation::cur_seg_size
int64_t cur_seg_size
Definition: dashdec.c:110
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:200
read_probe
static int read_probe(const AVProbeData *p)
Definition: cdg.c:30
mem.h
AVIOContext::buffer
unsigned char * buffer
Start of the buffer.
Definition: avio.h:225
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
ff_make_absolute_url
int ff_make_absolute_url(char *buf, int size, const char *base, const char *rel)
Convert a relative url into an absolute url, given a base url.
Definition: url.c:321
AVPacket
This structure stores compressed data.
Definition: packet.h:565
ff_dash_fill_tmpl_params
void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size, const char *template, int rep_id, int number, int bit_rate, int64_t time)
Definition: dash.c:95
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
av_fast_malloc
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
Allocate a buffer, reusing the given one if large enough.
Definition: mem.c:557
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:247
FFInputFormat
Definition: demux.h:66
representation::fragment_duration
int64_t fragment_duration
Definition: dashdec.c:103
avio_find_protocol_name
const char * avio_find_protocol_name(const char *url)
Return the name of the protocol that will handle the passed URL.
Definition: avio.c:658
int32_t
int32_t
Definition: audioconvert.c:56
get_fragment
static struct fragment * get_fragment(char *range)
Definition: dashdec.c:582
avio_close
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: avio.c:617
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:85
av_opt_get
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:1215
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
dash_seek
static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
Definition: dashdec.c:2262
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
timeline::repeat
int64_t repeat
Definition: dashdec.c:67
dash.h
pkt
static AVPacket * pkt
Definition: demux_decode.c:55
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:276
DASHContext::base_url
char * base_url
Definition: dashdec.c:125
AVStream::pts_wrap_bits
int pts_wrap_bits
Number of bits in timestamps.
Definition: avformat.h:887
representation::fragments
struct fragment ** fragments
Definition: dashdec.c:94
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1292
dash_class
static const AVClass dash_class
Definition: dashdec.c:2385
DASHContext::period_duration
uint64_t period_duration
Definition: dashdec.c:145
representation::presentation_timeoffset
int64_t presentation_timeoffset
Definition: dashdec.c:106
duration
static int64_t duration
Definition: ffplay.c:329
avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: codec_par.c:107
fragment::size
int64_t size
Definition: dashdec.c:39
avio_feof
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:349