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