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