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