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