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