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