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 */
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 
184 {
185  return av_gettime() / 1000000;
186 }
187 
188 static int64_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(AVFormatContext *s, 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  if (!str_offset || !str_end_offset) {
604  av_log(s, AV_LOG_WARNING, "%s will get invalid range\n", range);
605  av_freep(&seg);
606  return NULL;
607  }
608  seg->url_offset = strtoll(str_offset, NULL, 10);
609  seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset + 1;
610  }
611 
612  return seg;
613 }
614 
616  xmlNodePtr fragmenturl_node,
617  xmlNodePtr *baseurl_nodes,
618  char *rep_id_val,
619  char *rep_bandwidth_val)
620 {
621  DASHContext *c = s->priv_data;
622  char *initialization_val = NULL;
623  char *media_val = NULL;
624  char *range_val = NULL;
625  int max_url_size = c ? c->max_url_size: MAX_URL_SIZE;
626  int err;
627 
628  if (!av_strcasecmp(fragmenturl_node->name, "Initialization")) {
629  initialization_val = xmlGetProp(fragmenturl_node, "sourceURL");
630  range_val = xmlGetProp(fragmenturl_node, "range");
631  if (initialization_val || range_val) {
633  rep->init_section = get_fragment(s, range_val);
634  xmlFree(range_val);
635  if (!rep->init_section) {
636  xmlFree(initialization_val);
637  return AVERROR(ENOMEM);
638  }
639  rep->init_section->url = get_content_url(baseurl_nodes, 4,
640  max_url_size,
641  rep_id_val,
642  rep_bandwidth_val,
643  initialization_val);
644  xmlFree(initialization_val);
645  if (!rep->init_section->url) {
646  av_freep(&rep->init_section);
647  return AVERROR(ENOMEM);
648  }
649  }
650  } else if (!av_strcasecmp(fragmenturl_node->name, "SegmentURL")) {
651  media_val = xmlGetProp(fragmenturl_node, "media");
652  range_val = xmlGetProp(fragmenturl_node, "mediaRange");
653  if (media_val || range_val) {
654  struct fragment *seg = get_fragment(s, range_val);
655  xmlFree(range_val);
656  if (!seg) {
657  xmlFree(media_val);
658  return AVERROR(ENOMEM);
659  }
660  seg->url = get_content_url(baseurl_nodes, 4,
661  max_url_size,
662  rep_id_val,
663  rep_bandwidth_val,
664  media_val);
665  xmlFree(media_val);
666  if (!seg->url) {
667  av_free(seg);
668  return AVERROR(ENOMEM);
669  }
670  err = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg);
671  if (err < 0) {
672  free_fragment(&seg);
673  return err;
674  }
675  }
676  }
677 
678  return 0;
679 }
680 
682  xmlNodePtr fragment_timeline_node)
683 {
684  xmlAttrPtr attr = NULL;
685  char *val = NULL;
686  int err;
687 
688  if (!av_strcasecmp(fragment_timeline_node->name, "S")) {
689  struct timeline *tml = av_mallocz(sizeof(struct timeline));
690  if (!tml) {
691  return AVERROR(ENOMEM);
692  }
693  attr = fragment_timeline_node->properties;
694  while (attr) {
695  val = xmlGetProp(fragment_timeline_node, attr->name);
696 
697  if (!val) {
698  av_log(s, AV_LOG_WARNING, "parse_manifest_segmenttimeline attr->name = %s val is NULL\n", attr->name);
699  continue;
700  }
701 
702  if (!av_strcasecmp(attr->name, "t")) {
703  tml->starttime = (int64_t)strtoll(val, NULL, 10);
704  } else if (!av_strcasecmp(attr->name, "r")) {
705  tml->repeat =(int64_t) strtoll(val, NULL, 10);
706  } else if (!av_strcasecmp(attr->name, "d")) {
707  tml->duration = (int64_t)strtoll(val, NULL, 10);
708  }
709  attr = attr->next;
710  xmlFree(val);
711  }
712  err = av_dynarray_add_nofree(&rep->timelines, &rep->n_timelines, tml);
713  if (err < 0) {
714  av_free(tml);
715  return err;
716  }
717  }
718 
719  return 0;
720 }
721 
722 static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes)
723 {
724  char *tmp_str = NULL;
725  char *path = NULL;
726  char *mpdName = NULL;
727  xmlNodePtr node = NULL;
728  char *baseurl = NULL;
729  char *root_url = NULL;
730  char *text = NULL;
731  char *tmp = NULL;
732  int isRootHttp = 0;
733  char token ='/';
734  int start = 0;
735  int rootId = 0;
736  int updated = 0;
737  int size = 0;
738  int i;
739  int tmp_max_url_size = strlen(url);
740 
741  for (i = n_baseurl_nodes-1; i >= 0 ; i--) {
742  text = xmlNodeGetContent(baseurl_nodes[i]);
743  if (!text)
744  continue;
745  tmp_max_url_size += strlen(text);
746  if (ishttp(text)) {
747  xmlFree(text);
748  break;
749  }
750  xmlFree(text);
751  }
752 
753  tmp_max_url_size = aligned(tmp_max_url_size);
754  text = av_mallocz(tmp_max_url_size + 1);
755  if (!text) {
756  updated = AVERROR(ENOMEM);
757  goto end;
758  }
759  av_strlcpy(text, url, strlen(url)+1);
760  tmp = text;
761  while (mpdName = av_strtok(tmp, "/", &tmp)) {
762  size = strlen(mpdName);
763  }
764  av_free(text);
765 
766  path = av_mallocz(tmp_max_url_size + 2);
767  tmp_str = av_mallocz(tmp_max_url_size);
768  if (!tmp_str || !path) {
769  updated = AVERROR(ENOMEM);
770  goto end;
771  }
772 
773  av_strlcpy (path, url, strlen(url) - size + 1);
774  for (rootId = n_baseurl_nodes - 1; rootId > 0; rootId --) {
775  if (!(node = baseurl_nodes[rootId])) {
776  continue;
777  }
778  text = xmlNodeGetContent(node);
779  if (ishttp(text)) {
780  xmlFree(text);
781  break;
782  }
783  xmlFree(text);
784  }
785 
786  node = baseurl_nodes[rootId];
787  baseurl = xmlNodeGetContent(node);
788  if (baseurl) {
789  size_t len = xmlStrlen(baseurl)+2;
790  char *tmp = xmlRealloc(baseurl, len);
791  if (!tmp) {
792  updated = AVERROR(ENOMEM);
793  goto end;
794  }
795  baseurl = tmp;
796  }
797  root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path;
798  if (node) {
799  xmlChar *escaped = xmlEncodeSpecialChars(NULL, root_url);
800  if (!escaped) {
801  updated = AVERROR(ENOMEM);
802  goto end;
803  }
804  xmlNodeSetContent(node, escaped);
805  xmlFree(escaped);
806  updated = 1;
807  }
808 
809  size = strlen(root_url);
810  isRootHttp = ishttp(root_url);
811 
812  if (size > 0 && root_url[size - 1] != token) {
813  av_strlcat(root_url, "/", size + 2);
814  size += 2;
815  }
816 
817  for (i = 0; i < n_baseurl_nodes; ++i) {
818  if (i == rootId) {
819  continue;
820  }
821  text = xmlNodeGetContent(baseurl_nodes[i]);
822  if (text && !av_strstart(text, "/", NULL)) {
823  memset(tmp_str, 0, strlen(tmp_str));
824  if (!ishttp(text) && isRootHttp) {
825  av_strlcpy(tmp_str, root_url, size + 1);
826  }
827  start = (text[0] == token);
828  if (start && av_stristr(tmp_str, text)) {
829  char *p = tmp_str;
830  if (!av_strncasecmp(tmp_str, "http://", 7)) {
831  p += 7;
832  } else if (!av_strncasecmp(tmp_str, "https://", 8)) {
833  p += 8;
834  }
835  p = strchr(p, '/');
836  memset(p + 1, 0, strlen(p));
837  }
838  av_strlcat(tmp_str, text + start, tmp_max_url_size);
839  xmlFree(text);
840  xmlChar* escaped = xmlEncodeSpecialChars(NULL, tmp_str);
841  if (!escaped) {
842  updated = AVERROR(ENOMEM);
843  goto end;
844  }
845  xmlNodeSetContent(baseurl_nodes[i], escaped);
846  updated = 1;
847  xmlFree(escaped);
848  }
849  }
850 
851 end:
852  if (tmp_max_url_size > *max_url_size) {
853  *max_url_size = tmp_max_url_size;
854  }
855  av_free(path);
856  av_free(tmp_str);
857  xmlFree(baseurl);
858  return updated;
859 
860 }
861 
862 #define SET_REPRESENTATION_SEQUENCE_BASE_INFO(arg, cnt) { \
863  val = get_val_from_nodes_tab((arg), (cnt), "duration"); \
864  if (val) { \
865  int64_t fragment_duration = (int64_t) strtoll(val, NULL, 10); \
866  if (fragment_duration < 0) { \
867  av_log(s, AV_LOG_WARNING, "duration invalid, autochanged to 0.\n"); \
868  fragment_duration = 0; \
869  } \
870  rep->fragment_duration = fragment_duration; \
871  av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); \
872  xmlFree(val); \
873  } \
874  val = get_val_from_nodes_tab((arg), (cnt), "timescale"); \
875  if (val) { \
876  int64_t fragment_timescale = (int64_t) strtoll(val, NULL, 10); \
877  if (fragment_timescale < 0) { \
878  av_log(s, AV_LOG_WARNING, "timescale invalid, autochanged to 0.\n"); \
879  fragment_timescale = 0; \
880  } \
881  rep->fragment_timescale = fragment_timescale; \
882  av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); \
883  xmlFree(val); \
884  } \
885  val = get_val_from_nodes_tab((arg), (cnt), "startNumber"); \
886  if (val) { \
887  int64_t start_number = (int64_t) strtoll(val, NULL, 10); \
888  if (start_number < 0) { \
889  av_log(s, AV_LOG_WARNING, "startNumber invalid, autochanged to 0.\n"); \
890  start_number = 0; \
891  } \
892  rep->start_number = rep->first_seq_no = start_number; \
893  av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); \
894  xmlFree(val); \
895  } \
896  }
897 
898 
899 static int parse_manifest_representation(AVFormatContext *s, const char *url,
900  xmlNodePtr node,
901  xmlNodePtr adaptionset_node,
902  xmlNodePtr mpd_baseurl_node,
903  xmlNodePtr period_baseurl_node,
904  xmlNodePtr period_segmenttemplate_node,
905  xmlNodePtr period_segmentlist_node,
906  xmlNodePtr fragment_template_node,
907  xmlNodePtr content_component_node,
908  xmlNodePtr adaptionset_baseurl_node,
909  xmlNodePtr adaptionset_segmentlist_node,
910  xmlNodePtr adaptionset_supplementalproperty_node)
911 {
912  int32_t ret = 0;
913  DASHContext *c = s->priv_data;
914  struct representation *rep = NULL;
915  struct fragment *seg = NULL;
916  xmlNodePtr representation_segmenttemplate_node = NULL;
917  xmlNodePtr representation_baseurl_node = NULL;
918  xmlNodePtr representation_segmentlist_node = NULL;
919  xmlNodePtr segmentlists_tab[3];
920  xmlNodePtr fragment_timeline_node = NULL;
921  xmlNodePtr fragment_templates_tab[5];
922  char *val = NULL;
923  xmlNodePtr baseurl_nodes[4];
924  xmlNodePtr representation_node = node;
925  char *rep_bandwidth_val;
926  char *rep_codecs_val;
927  char *rep_dependencyid_val;
929 
930  // try get information from representation
931  if (type == AVMEDIA_TYPE_UNKNOWN)
932  type = get_content_type(representation_node);
933  // try get information from contentComponen
934  if (type == AVMEDIA_TYPE_UNKNOWN)
935  type = get_content_type(content_component_node);
936  // try get information from adaption set
937  if (type == AVMEDIA_TYPE_UNKNOWN)
938  type = get_content_type(adaptionset_node);
941  av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skip not supported representation type\n", url);
942  return 0;
943  }
944 
945  // convert selected representation to our internal struct
946  rep = av_mallocz(sizeof(struct representation));
947  if (!rep)
948  return AVERROR(ENOMEM);
949  if (c->adaptionset_lang) {
950  rep->lang = av_strdup(c->adaptionset_lang);
951  if (!rep->lang) {
952  av_log(s, AV_LOG_ERROR, "alloc language memory failure\n");
953  av_freep(&rep);
954  return AVERROR(ENOMEM);
955  }
956  }
957  rep->parent = s;
958  representation_segmenttemplate_node = find_child_node_by_name(representation_node, "SegmentTemplate");
959  representation_baseurl_node = find_child_node_by_name(representation_node, "BaseURL");
960  representation_segmentlist_node = find_child_node_by_name(representation_node, "SegmentList");
961  rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth");
962  rep_dependencyid_val = xmlGetProp(representation_node, "dependencyId");
963  rep_codecs_val = xmlGetProp(representation_node, "codecs");
964  if (!rep_codecs_val)
965  rep_codecs_val = xmlGetProp(adaptionset_node, "codecs");
966  val = xmlGetProp(representation_node, "id");
967  if (val) {
968  rep->id = av_strdup(val);
969  xmlFree(val);
970  if (!rep->id)
971  goto enomem;
972  }
973 
974  baseurl_nodes[0] = mpd_baseurl_node;
975  baseurl_nodes[1] = period_baseurl_node;
976  baseurl_nodes[2] = adaptionset_baseurl_node;
977  baseurl_nodes[3] = representation_baseurl_node;
978 
979  ret = resolve_content_path(s, url, &c->max_url_size, baseurl_nodes, 4);
980  c->max_url_size = aligned(c->max_url_size
981  + (rep->id ? strlen(rep->id) : 0)
982  + (rep_bandwidth_val ? strlen(rep_bandwidth_val) : 0));
983  if (ret == AVERROR(ENOMEM) || ret == 0)
984  goto free;
985  if (representation_segmenttemplate_node || fragment_template_node || period_segmenttemplate_node) {
986  fragment_timeline_node = NULL;
987  fragment_templates_tab[0] = representation_segmenttemplate_node;
988  fragment_templates_tab[1] = adaptionset_segmentlist_node;
989  fragment_templates_tab[2] = fragment_template_node;
990  fragment_templates_tab[3] = period_segmenttemplate_node;
991  fragment_templates_tab[4] = period_segmentlist_node;
992 
993  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "initialization");
994  if (val) {
995  rep->init_section = av_mallocz(sizeof(struct fragment));
996  if (!rep->init_section) {
997  xmlFree(val);
998  goto enomem;
999  }
1000  c->max_url_size = aligned(c->max_url_size + strlen(val));
1001  rep->init_section->url = get_content_url(baseurl_nodes, 4,
1002  c->max_url_size, rep->id,
1003  rep_bandwidth_val, val);
1004  xmlFree(val);
1005  if (!rep->init_section->url)
1006  goto enomem;
1007  rep->init_section->size = -1;
1008  }
1009  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "media");
1010  if (val) {
1011  c->max_url_size = aligned(c->max_url_size + strlen(val));
1012  rep->url_template = get_content_url(baseurl_nodes, 4,
1013  c->max_url_size, rep->id,
1014  rep_bandwidth_val, val);
1015  xmlFree(val);
1016  }
1017  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "presentationTimeOffset");
1018  if (val) {
1019  int64_t presentation_timeoffset = (int64_t) strtoll(val, NULL, 10);
1020  if (presentation_timeoffset < 0) {
1021  av_log(s, AV_LOG_WARNING, "presentationTimeOffset invalid, autochanged to 0.\n");
1022  presentation_timeoffset = 0;
1023  }
1024  rep->presentation_timeoffset = presentation_timeoffset;
1025  av_log(s, AV_LOG_TRACE, "rep->presentation_timeoffset = [%"PRId64"]\n", rep->presentation_timeoffset);
1026  xmlFree(val);
1027  }
1028 
1029  SET_REPRESENTATION_SEQUENCE_BASE_INFO(fragment_templates_tab, 4);
1030  if (adaptionset_supplementalproperty_node) {
1031  char *scheme_id_uri = xmlGetProp(adaptionset_supplementalproperty_node, "schemeIdUri");
1032  if (scheme_id_uri) {
1033  int is_last_segment_number = !av_strcasecmp(scheme_id_uri, "http://dashif.org/guidelines/last-segment-number");
1034  xmlFree(scheme_id_uri);
1035  if (is_last_segment_number) {
1036  val = xmlGetProp(adaptionset_supplementalproperty_node, "value");
1037  if (!val) {
1038  av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n");
1039  } else {
1040  rep->last_seq_no = (int64_t)strtoll(val, NULL, 10) - 1;
1041  xmlFree(val);
1042  }
1043  }
1044  }
1045  }
1046 
1047  fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline");
1048 
1049  if (!fragment_timeline_node)
1050  fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline");
1051  if (!fragment_timeline_node)
1052  fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline");
1053  if (!fragment_timeline_node)
1054  fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline");
1055  if (fragment_timeline_node) {
1056  fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node);
1057  while (fragment_timeline_node) {
1058  ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node);
1059  if (ret < 0)
1060  goto free;
1061  fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node);
1062  }
1063  }
1064  } else if (representation_baseurl_node && !representation_segmentlist_node) {
1065  seg = av_mallocz(sizeof(struct fragment));
1066  if (!seg)
1067  goto enomem;
1068  ret = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg);
1069  if (ret < 0) {
1070  av_free(seg);
1071  goto free;
1072  }
1073  seg->url = get_content_url(baseurl_nodes, 4, c->max_url_size,
1074  rep->id, rep_bandwidth_val, NULL);
1075  if (!seg->url)
1076  goto enomem;
1077  seg->size = -1;
1078  } else if (representation_segmentlist_node) {
1079  // TODO: https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html
1080  // http://www-itec.uni-klu.ac.at/dash/ddash/mpdGenerator.php?fragmentlength=15&type=full
1081  xmlNodePtr fragmenturl_node = NULL;
1082  segmentlists_tab[0] = representation_segmentlist_node;
1083  segmentlists_tab[1] = adaptionset_segmentlist_node;
1084  segmentlists_tab[2] = period_segmentlist_node;
1085 
1086  SET_REPRESENTATION_SEQUENCE_BASE_INFO(segmentlists_tab, 3)
1087  fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node);
1088  while (fragmenturl_node) {
1089  ret = parse_manifest_segmenturlnode(s, rep, fragmenturl_node,
1090  baseurl_nodes, rep->id,
1091  rep_bandwidth_val);
1092  if (ret < 0)
1093  goto free;
1094  fragmenturl_node = xmlNextElementSibling(fragmenturl_node);
1095  }
1096 
1097  fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline");
1098  if (!fragment_timeline_node)
1099  fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline");
1100  if (fragment_timeline_node) {
1101  fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node);
1102  while (fragment_timeline_node) {
1103  ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node);
1104  if (ret < 0)
1105  goto free;
1106  fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node);
1107  }
1108  }
1109  } else {
1110  av_log(s, AV_LOG_ERROR, "Unknown format of Representation node id '%s' \n",
1111  rep->id ? rep->id : "");
1112  goto free;
1113  }
1114 
1115  if (rep->fragment_duration > 0 && !rep->fragment_timescale)
1116  rep->fragment_timescale = 1;
1117  rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0;
1118  if (rep_dependencyid_val) {
1119  rep->dependencyid = av_strdup(rep_dependencyid_val);
1120  if (!rep->dependencyid) {
1121  xmlFree(rep_dependencyid_val);
1122  goto enomem;
1123  }
1124  }
1125  if (rep_codecs_val) {
1126  rep->codecs = av_strdup(rep_codecs_val);
1127  if (!rep->codecs) {
1128  xmlFree(rep_codecs_val);
1129  goto enomem;
1130  }
1131  }
1132  rep->framerate = av_make_q(0, 0);
1133  if (type == AVMEDIA_TYPE_VIDEO) {
1134  char *rep_framerate_val = xmlGetProp(representation_node, "frameRate");
1135  if (rep_framerate_val) {
1136  ret = av_parse_video_rate(&rep->framerate, rep_framerate_val);
1137  if (ret < 0)
1138  av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val);
1139  xmlFree(rep_framerate_val);
1140  }
1141  }
1142 
1143  switch (type) {
1144  case AVMEDIA_TYPE_VIDEO:
1145  ret = av_dynarray_add_nofree(&c->videos, &c->n_videos, rep);
1146  break;
1147  case AVMEDIA_TYPE_AUDIO:
1148  ret = av_dynarray_add_nofree(&c->audios, &c->n_audios, rep);
1149  break;
1150  case AVMEDIA_TYPE_SUBTITLE:
1151  ret = av_dynarray_add_nofree(&c->subtitles, &c->n_subtitles, rep);
1152  break;
1153  }
1154  if (ret < 0)
1155  goto free;
1156 
1157 end:
1158  if (rep_bandwidth_val)
1159  xmlFree(rep_bandwidth_val);
1160  if (rep_dependencyid_val)
1161  xmlFree(rep_dependencyid_val);
1162  if (rep_codecs_val)
1163  xmlFree(rep_codecs_val);
1164 
1165  return ret;
1166 enomem:
1167  ret = AVERROR(ENOMEM);
1168 free:
1169  free_representation(rep);
1170  goto end;
1171 }
1172 
1173 static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node)
1174 {
1175  DASHContext *c = s->priv_data;
1176 
1177  if (!adaptionset_node) {
1178  av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n");
1179  return AVERROR(EINVAL);
1180  }
1181  c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang");
1182 
1183  return 0;
1184 }
1185 
1187  xmlNodePtr adaptionset_node,
1188  xmlNodePtr mpd_baseurl_node,
1189  xmlNodePtr period_baseurl_node,
1190  xmlNodePtr period_segmenttemplate_node,
1191  xmlNodePtr period_segmentlist_node)
1192 {
1193  int ret = 0;
1194  DASHContext *c = s->priv_data;
1195  xmlNodePtr fragment_template_node = NULL;
1196  xmlNodePtr content_component_node = NULL;
1197  xmlNodePtr adaptionset_baseurl_node = NULL;
1198  xmlNodePtr adaptionset_segmentlist_node = NULL;
1199  xmlNodePtr adaptionset_supplementalproperty_node = NULL;
1200  xmlNodePtr node = NULL;
1201 
1202  ret = parse_manifest_adaptationset_attr(s, adaptionset_node);
1203  if (ret < 0)
1204  return ret;
1205 
1206  node = xmlFirstElementChild(adaptionset_node);
1207  while (node) {
1208  if (!av_strcasecmp(node->name, "SegmentTemplate")) {
1209  fragment_template_node = node;
1210  } else if (!av_strcasecmp(node->name, "ContentComponent")) {
1211  content_component_node = node;
1212  } else if (!av_strcasecmp(node->name, "BaseURL")) {
1213  adaptionset_baseurl_node = node;
1214  } else if (!av_strcasecmp(node->name, "SegmentList")) {
1215  adaptionset_segmentlist_node = node;
1216  } else if (!av_strcasecmp(node->name, "SupplementalProperty")) {
1217  adaptionset_supplementalproperty_node = node;
1218  } else if (!av_strcasecmp(node->name, "Representation")) {
1220  adaptionset_node,
1221  mpd_baseurl_node,
1222  period_baseurl_node,
1223  period_segmenttemplate_node,
1224  period_segmentlist_node,
1225  fragment_template_node,
1226  content_component_node,
1227  adaptionset_baseurl_node,
1228  adaptionset_segmentlist_node,
1229  adaptionset_supplementalproperty_node);
1230  if (ret < 0)
1231  goto err;
1232  }
1233  node = xmlNextElementSibling(node);
1234  }
1235 
1236 err:
1237  xmlFree(c->adaptionset_lang);
1238  c->adaptionset_lang = NULL;
1239  return ret;
1240 }
1241 
1242 static int parse_programinformation(AVFormatContext *s, xmlNodePtr node)
1243 {
1244  xmlChar *val = NULL;
1245 
1246  node = xmlFirstElementChild(node);
1247  while (node) {
1248  if (!av_strcasecmp(node->name, "Title")) {
1249  val = xmlNodeGetContent(node);
1250  if (val) {
1251  av_dict_set(&s->metadata, "Title", val, 0);
1252  }
1253  } else if (!av_strcasecmp(node->name, "Source")) {
1254  val = xmlNodeGetContent(node);
1255  if (val) {
1256  av_dict_set(&s->metadata, "Source", val, 0);
1257  }
1258  } else if (!av_strcasecmp(node->name, "Copyright")) {
1259  val = xmlNodeGetContent(node);
1260  if (val) {
1261  av_dict_set(&s->metadata, "Copyright", val, 0);
1262  }
1263  }
1264  node = xmlNextElementSibling(node);
1265  xmlFree(val);
1266  val = NULL;
1267  }
1268  return 0;
1269 }
1270 
1271 static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
1272 {
1273  DASHContext *c = s->priv_data;
1274  int ret = 0;
1275  int close_in = 0;
1276  AVBPrint buf;
1277  AVDictionary *opts = NULL;
1278  xmlDoc *doc = NULL;
1279  xmlNodePtr root_element = NULL;
1280  xmlNodePtr node = NULL;
1281  xmlNodePtr period_node = NULL;
1282  xmlNodePtr tmp_node = NULL;
1283  xmlNodePtr mpd_baseurl_node = NULL;
1284  xmlNodePtr period_baseurl_node = NULL;
1285  xmlNodePtr period_segmenttemplate_node = NULL;
1286  xmlNodePtr period_segmentlist_node = NULL;
1287  xmlNodePtr adaptionset_node = NULL;
1288  xmlAttrPtr attr = NULL;
1289  char *val = NULL;
1290  uint32_t period_duration_sec = 0;
1291  uint32_t period_start_sec = 0;
1292 
1293  if (!in) {
1294  close_in = 1;
1295 
1296  av_dict_copy(&opts, c->avio_opts, 0);
1297  ret = s->io_open(s, &in, url, AVIO_FLAG_READ, &opts);
1298  av_dict_free(&opts);
1299  if (ret < 0)
1300  return ret;
1301  }
1302 
1303  if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&c->base_url) < 0)
1304  c->base_url = av_strdup(url);
1305 
1306  av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer bufsize
1307 
1308  if ((ret = avio_read_to_bprint(in, &buf, SIZE_MAX)) < 0 ||
1309  !avio_feof(in)) {
1310  av_log(s, AV_LOG_ERROR, "Unable to read to manifest '%s'\n", url);
1311  if (ret == 0)
1313  } else {
1314  LIBXML_TEST_VERSION
1315 
1316  doc = xmlReadMemory(buf.str, buf.len, c->base_url, NULL, 0);
1317  root_element = xmlDocGetRootElement(doc);
1318  node = root_element;
1319 
1320  if (!node) {
1322  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing root node\n", url);
1323  goto cleanup;
1324  }
1325 
1326  if (node->type != XML_ELEMENT_NODE ||
1327  av_strcasecmp(node->name, "MPD")) {
1329  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - wrong root node name[%s] type[%d]\n", url, node->name, (int)node->type);
1330  goto cleanup;
1331  }
1332 
1333  val = xmlGetProp(node, "type");
1334  if (!val) {
1335  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing type attrib\n", url);
1337  goto cleanup;
1338  }
1339  if (!av_strcasecmp(val, "dynamic"))
1340  c->is_live = 1;
1341  xmlFree(val);
1342 
1343  attr = node->properties;
1344  while (attr) {
1345  val = xmlGetProp(node, attr->name);
1346 
1347  if (!av_strcasecmp(attr->name, "availabilityStartTime")) {
1348  c->availability_start_time = get_utc_date_time_insec(s, val);
1349  av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time);
1350  } else if (!av_strcasecmp(attr->name, "availabilityEndTime")) {
1351  c->availability_end_time = get_utc_date_time_insec(s, val);
1352  av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time);
1353  } else if (!av_strcasecmp(attr->name, "publishTime")) {
1354  c->publish_time = get_utc_date_time_insec(s, val);
1355  av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time);
1356  } else if (!av_strcasecmp(attr->name, "minimumUpdatePeriod")) {
1357  c->minimum_update_period = get_duration_insec(s, val);
1358  av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period);
1359  } else if (!av_strcasecmp(attr->name, "timeShiftBufferDepth")) {
1360  c->time_shift_buffer_depth = get_duration_insec(s, val);
1361  av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth);
1362  } else if (!av_strcasecmp(attr->name, "minBufferTime")) {
1363  c->min_buffer_time = get_duration_insec(s, val);
1364  av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time);
1365  } else if (!av_strcasecmp(attr->name, "suggestedPresentationDelay")) {
1366  c->suggested_presentation_delay = get_duration_insec(s, val);
1367  av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay);
1368  } else if (!av_strcasecmp(attr->name, "mediaPresentationDuration")) {
1369  c->media_presentation_duration = get_duration_insec(s, val);
1370  av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration);
1371  }
1372  attr = attr->next;
1373  xmlFree(val);
1374  }
1375 
1376  tmp_node = find_child_node_by_name(node, "BaseURL");
1377  if (tmp_node) {
1378  mpd_baseurl_node = xmlCopyNode(tmp_node,1);
1379  } else {
1380  mpd_baseurl_node = xmlNewNode(NULL, "BaseURL");
1381  }
1382 
1383  // at now we can handle only one period, with the longest duration
1384  node = xmlFirstElementChild(node);
1385  while (node) {
1386  if (!av_strcasecmp(node->name, "Period")) {
1387  period_duration_sec = 0;
1388  period_start_sec = 0;
1389  attr = node->properties;
1390  while (attr) {
1391  val = xmlGetProp(node, attr->name);
1392  if (!av_strcasecmp(attr->name, "duration")) {
1393  period_duration_sec = get_duration_insec(s, val);
1394  } else if (!av_strcasecmp(attr->name, "start")) {
1395  period_start_sec = get_duration_insec(s, val);
1396  }
1397  attr = attr->next;
1398  xmlFree(val);
1399  }
1400  if ((period_duration_sec) >= (c->period_duration)) {
1401  period_node = node;
1402  c->period_duration = period_duration_sec;
1403  c->period_start = period_start_sec;
1404  if (c->period_start > 0)
1405  c->media_presentation_duration = c->period_duration;
1406  }
1407  } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
1408  parse_programinformation(s, node);
1409  }
1410  node = xmlNextElementSibling(node);
1411  }
1412  if (!period_node) {
1413  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing Period node\n", url);
1415  goto cleanup;
1416  }
1417 
1418  adaptionset_node = xmlFirstElementChild(period_node);
1419  while (adaptionset_node) {
1420  if (!av_strcasecmp(adaptionset_node->name, "BaseURL")) {
1421  period_baseurl_node = adaptionset_node;
1422  } else if (!av_strcasecmp(adaptionset_node->name, "SegmentTemplate")) {
1423  period_segmenttemplate_node = adaptionset_node;
1424  } else if (!av_strcasecmp(adaptionset_node->name, "SegmentList")) {
1425  period_segmentlist_node = adaptionset_node;
1426  } else if (!av_strcasecmp(adaptionset_node->name, "AdaptationSet")) {
1427  parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node, period_segmenttemplate_node, period_segmentlist_node);
1428  }
1429  adaptionset_node = xmlNextElementSibling(adaptionset_node);
1430  }
1431 cleanup:
1432  /*free the document */
1433  xmlFreeDoc(doc);
1434  xmlCleanupParser();
1435  xmlFreeNode(mpd_baseurl_node);
1436  }
1437 
1438  av_bprint_finalize(&buf, NULL);
1439  if (close_in) {
1440  ff_format_io_close(s, &in);
1441  }
1442  return ret;
1443 }
1444 
1446 {
1447  DASHContext *c = s->priv_data;
1448  int64_t num = 0;
1449  int64_t start_time_offset = 0;
1450 
1451  if (c->is_live) {
1452  if (pls->n_fragments) {
1453  av_log(s, AV_LOG_TRACE, "in n_fragments mode\n");
1454  num = pls->first_seq_no;
1455  } else if (pls->n_timelines) {
1456  av_log(s, AV_LOG_TRACE, "in n_timelines mode\n");
1457  start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - 60 * pls->fragment_timescale; // 60 seconds before end
1458  num = calc_next_seg_no_from_timelines(pls, start_time_offset);
1459  if (num == -1)
1460  num = pls->first_seq_no;
1461  } else if (pls->fragment_duration){
1462  av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset);
1463  if (pls->presentation_timeoffset) {
1464  num = pls->first_seq_no + ((get_current_time_in_sec() - c->availability_start_time) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time;
1465  } else if (c->publish_time > 0 && !c->availability_start_time) {
1466  if (c->min_buffer_time) {
1467  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;
1468  } else {
1469  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;
1470  }
1471  } else {
1472  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
1473  }
1474  }
1475  } else {
1476  num = pls->first_seq_no;
1477  }
1478  return num;
1479 }
1480 
1482 {
1483  DASHContext *c = s->priv_data;
1484  int64_t num = 0;
1485 
1486  if (c->is_live && pls->fragment_duration) {
1487  av_log(s, AV_LOG_TRACE, "in live mode\n");
1488  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;
1489  } else {
1490  num = pls->first_seq_no;
1491  }
1492  return num;
1493 }
1494 
1496 {
1497  int64_t num = 0;
1498 
1499  if (pls->n_fragments) {
1500  num = pls->first_seq_no + pls->n_fragments - 1;
1501  } else if (pls->n_timelines) {
1502  int i = 0;
1503  num = pls->first_seq_no + pls->n_timelines - 1;
1504  for (i = 0; i < pls->n_timelines; i++) {
1505  if (pls->timelines[i]->repeat == -1) {
1506  num = pls->timelines[i]->duration ? av_rescale(c->period_duration, pls->fragment_timescale, pls->timelines[i]->duration) : pls->first_seq_no;
1507  } else {
1508  num += pls->timelines[i]->repeat;
1509  }
1510  }
1511  } else if (c->is_live && pls->fragment_duration) {
1512  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale) / pls->fragment_duration;
1513  } else if (pls->fragment_duration) {
1514  num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
1515  }
1516 
1517  return num;
1518 }
1519 
1520 static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
1521 {
1522  if (rep_dest && rep_src ) {
1523  free_timelines_list(rep_dest);
1524  rep_dest->timelines = rep_src->timelines;
1525  rep_dest->n_timelines = rep_src->n_timelines;
1526  rep_dest->first_seq_no = rep_src->first_seq_no;
1527  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1528  rep_src->timelines = NULL;
1529  rep_src->n_timelines = 0;
1530  rep_dest->cur_seq_no = rep_src->cur_seq_no;
1531  }
1532 }
1533 
1534 static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
1535 {
1536  if (rep_dest && rep_src ) {
1537  free_fragment_list(rep_dest);
1538  if (rep_src->start_number > (rep_dest->start_number + rep_dest->n_fragments))
1539  rep_dest->cur_seq_no = 0;
1540  else {
1541  rep_dest->cur_seq_no += rep_src->start_number - rep_dest->start_number;
1542  if (rep_dest->cur_seq_no < 0)
1543  rep_dest->cur_seq_no = 0;
1544  }
1545  rep_dest->fragments = rep_src->fragments;
1546  rep_dest->n_fragments = rep_src->n_fragments;
1547  rep_dest->parent = rep_src->parent;
1548  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1549  rep_src->fragments = NULL;
1550  rep_src->n_fragments = 0;
1551  }
1552 }
1553 
1554 
1556 {
1557  int ret = 0, i;
1558  DASHContext *c = s->priv_data;
1559  // save current context
1560  int n_videos = c->n_videos;
1561  struct representation **videos = c->videos;
1562  int n_audios = c->n_audios;
1563  struct representation **audios = c->audios;
1564  int n_subtitles = c->n_subtitles;
1565  struct representation **subtitles = c->subtitles;
1566  char *base_url = c->base_url;
1567 
1568  c->base_url = NULL;
1569  c->n_videos = 0;
1570  c->videos = NULL;
1571  c->n_audios = 0;
1572  c->audios = NULL;
1573  c->n_subtitles = 0;
1574  c->subtitles = NULL;
1575  ret = parse_manifest(s, s->url, NULL);
1576  if (ret)
1577  goto finish;
1578 
1579  if (c->n_videos != n_videos) {
1581  "new manifest has mismatched no. of video representations, %d -> %d\n",
1582  n_videos, c->n_videos);
1583  return AVERROR_INVALIDDATA;
1584  }
1585  if (c->n_audios != n_audios) {
1587  "new manifest has mismatched no. of audio representations, %d -> %d\n",
1588  n_audios, c->n_audios);
1589  return AVERROR_INVALIDDATA;
1590  }
1591  if (c->n_subtitles != n_subtitles) {
1593  "new manifest has mismatched no. of subtitles representations, %d -> %d\n",
1594  n_subtitles, c->n_subtitles);
1595  return AVERROR_INVALIDDATA;
1596  }
1597 
1598  for (i = 0; i < n_videos; i++) {
1599  struct representation *cur_video = videos[i];
1600  struct representation *ccur_video = c->videos[i];
1601  if (cur_video->timelines) {
1602  // calc current time
1603  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale;
1604  // update segments
1605  ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1);
1606  if (ccur_video->cur_seq_no >= 0) {
1607  move_timelines(ccur_video, cur_video, c);
1608  }
1609  }
1610  if (cur_video->fragments) {
1611  move_segments(ccur_video, cur_video, c);
1612  }
1613  }
1614  for (i = 0; i < n_audios; i++) {
1615  struct representation *cur_audio = audios[i];
1616  struct representation *ccur_audio = c->audios[i];
1617  if (cur_audio->timelines) {
1618  // calc current time
1619  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale;
1620  // update segments
1621  ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1);
1622  if (ccur_audio->cur_seq_no >= 0) {
1623  move_timelines(ccur_audio, cur_audio, c);
1624  }
1625  }
1626  if (cur_audio->fragments) {
1627  move_segments(ccur_audio, cur_audio, c);
1628  }
1629  }
1630 
1631 finish:
1632  // restore context
1633  if (c->base_url)
1634  av_free(base_url);
1635  else
1636  c->base_url = base_url;
1637 
1638  if (c->subtitles)
1640  if (c->audios)
1641  free_audio_list(c);
1642  if (c->videos)
1643  free_video_list(c);
1644 
1645  c->n_subtitles = n_subtitles;
1646  c->subtitles = subtitles;
1647  c->n_audios = n_audios;
1648  c->audios = audios;
1649  c->n_videos = n_videos;
1650  c->videos = videos;
1651  return ret;
1652 }
1653 
1654 static struct fragment *get_current_fragment(struct representation *pls)
1655 {
1656  int64_t min_seq_no = 0;
1657  int64_t max_seq_no = 0;
1658  struct fragment *seg = NULL;
1659  struct fragment *seg_ptr = NULL;
1660  DASHContext *c = pls->parent->priv_data;
1661  int reload_count = 0;
1662 
1663  while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) {
1664  if (pls->cur_seq_no >= 0 && pls->cur_seq_no < pls->n_fragments) {
1665  seg_ptr = pls->fragments[pls->cur_seq_no];
1666  seg = av_mallocz(sizeof(struct fragment));
1667  if (!seg) {
1668  return NULL;
1669  }
1670  seg->url = av_strdup(seg_ptr->url);
1671  if (!seg->url) {
1672  av_free(seg);
1673  return NULL;
1674  }
1675  seg->size = seg_ptr->size;
1676  seg->url_offset = seg_ptr->url_offset;
1677  return seg;
1678  } else if (c->is_live) {
1679  if (reload_count++ >= c->max_reload) {
1680  av_log(pls->parent, AV_LOG_ERROR,
1681  "Reached max manifest reloads (%d) at seq %"PRId64"\n",
1682  c->max_reload, pls->cur_seq_no);
1683  return NULL;
1684  }
1685  refresh_manifest(pls->parent);
1686  } else {
1687  break;
1688  }
1689  }
1690  if (c->is_live) {
1691  min_seq_no = calc_min_seg_no(pls->parent, pls);
1692  max_seq_no = calc_max_seg_no(pls, c);
1693 
1694  if (pls->timelines || pls->fragments) {
1695  refresh_manifest(pls->parent);
1696  }
1697  if (pls->cur_seq_no <= min_seq_no) {
1698  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);
1699  pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls);
1700  } else if (pls->cur_seq_no > max_seq_no) {
1701  av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] max[%"PRId64"]\n", min_seq_no, max_seq_no);
1702  }
1703  seg = av_mallocz(sizeof(struct fragment));
1704  if (!seg) {
1705  return NULL;
1706  }
1707  } else if (pls->cur_seq_no <= pls->last_seq_no) {
1708  seg = av_mallocz(sizeof(struct fragment));
1709  if (!seg) {
1710  return NULL;
1711  }
1712  }
1713  if (seg) {
1714  char *tmpfilename;
1715  if (!pls->url_template) {
1716  av_log(pls->parent, AV_LOG_ERROR, "Cannot get fragment, missing template URL\n");
1717  av_free(seg);
1718  return NULL;
1719  }
1720  tmpfilename = av_mallocz(c->max_url_size);
1721  if (!tmpfilename) {
1722  av_free(seg);
1723  return NULL;
1724  }
1725  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));
1726  seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename);
1727  if (!seg->url) {
1728  av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template);
1729  seg->url = av_strdup(pls->url_template);
1730  if (!seg->url) {
1731  av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template);
1732  av_free(tmpfilename);
1733  av_free(seg);
1734  return NULL;
1735  }
1736  }
1737  av_free(tmpfilename);
1738  seg->size = -1;
1739  }
1740 
1741  return seg;
1742 }
1743 
1744 static int read_from_url(struct representation *pls, struct fragment *seg,
1745  uint8_t *buf, int buf_size)
1746 {
1747  int ret;
1748 
1749  /* limit read if the fragment was only a part of a file */
1750  if (seg->size >= 0)
1751  buf_size = FFMIN(buf_size, pls->cur_seg_size - pls->cur_seg_offset);
1752 
1753  ret = avio_read(pls->input, buf, buf_size);
1754  if (ret > 0)
1755  pls->cur_seg_offset += ret;
1756 
1757  return ret;
1758 }
1759 
1760 static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
1761 {
1762  AVDictionary *opts = NULL;
1763  char *url = NULL;
1764  int ret = 0;
1765 
1766  url = av_mallocz(c->max_url_size);
1767  if (!url) {
1768  ret = AVERROR(ENOMEM);
1769  goto cleanup;
1770  }
1771 
1772  if (seg->size >= 0) {
1773  /* try to restrict the HTTP request to the part we want
1774  * (if this is in fact a HTTP request) */
1775  av_dict_set_int(&opts, "offset", seg->url_offset, 0);
1776  av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
1777  }
1778 
1779  ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url);
1780  av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64"\n",
1781  url, seg->url_offset);
1782  ret = open_url(pls->parent, &pls->input, url, &c->avio_opts, opts, NULL);
1783 
1784 cleanup:
1785  av_free(url);
1786  av_dict_free(&opts);
1787  pls->cur_seg_offset = 0;
1788  pls->cur_seg_size = seg->size;
1789  return ret;
1790 }
1791 
1792 static int update_init_section(struct representation *pls)
1793 {
1794  static const int max_init_section_size = 1024 * 1024;
1795  DASHContext *c = pls->parent->priv_data;
1796  int64_t sec_size;
1797  int64_t urlsize;
1798  int ret;
1799 
1800  if (!pls->init_section || pls->init_sec_buf)
1801  return 0;
1802 
1803  ret = open_input(c, pls, pls->init_section);
1804  if (ret < 0) {
1806  "Failed to open an initialization section\n");
1807  return ret;
1808  }
1809 
1810  if (pls->init_section->size >= 0)
1811  sec_size = pls->init_section->size;
1812  else if ((urlsize = avio_size(pls->input)) >= 0)
1813  sec_size = urlsize;
1814  else
1815  sec_size = max_init_section_size;
1816 
1817  av_log(pls->parent, AV_LOG_DEBUG,
1818  "Downloading an initialization section of size %"PRId64"\n",
1819  sec_size);
1820 
1821  sec_size = FFMIN(sec_size, max_init_section_size);
1822 
1823  av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size);
1824 
1825  ret = read_from_url(pls, pls->init_section, pls->init_sec_buf,
1826  pls->init_sec_buf_size);
1827  ff_format_io_close(pls->parent, &pls->input);
1828 
1829  if (ret < 0)
1830  return ret;
1831 
1832  pls->init_sec_data_len = ret;
1833  pls->init_sec_buf_read_offset = 0;
1834 
1835  return 0;
1836 }
1837 
1838 static int64_t seek_data(void *opaque, int64_t offset, int whence)
1839 {
1840  struct representation *v = opaque;
1841  if (v->n_fragments && !v->init_sec_data_len) {
1842  return avio_seek(v->input, offset, whence);
1843  }
1844 
1845  return AVERROR(ENOSYS);
1846 }
1847 
1848 static int read_data(void *opaque, uint8_t *buf, int buf_size)
1849 {
1850  int ret = 0;
1851  struct representation *v = opaque;
1852  DASHContext *c = v->parent->priv_data;
1853 
1854 restart:
1855  if (!v->input) {
1856  free_fragment(&v->cur_seg);
1857  v->cur_seg = get_current_fragment(v);
1858  if (!v->cur_seg) {
1859  ret = AVERROR_EOF;
1860  goto end;
1861  }
1862 
1863  /* load/update Media Initialization Section, if any */
1864  ret = update_init_section(v);
1865  if (ret)
1866  goto end;
1867 
1868  ret = open_input(c, v, v->cur_seg);
1869  if (ret < 0) {
1870  if (ff_check_interrupt(c->interrupt_callback)) {
1871  ret = AVERROR_EXIT;
1872  goto end;
1873  }
1874  av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist\n");
1875  if (++v->n_open_failures > c->max_reload) {
1877  "Reached max consecutive fragment open failures (%d), giving up\n",
1878  c->max_reload);
1879  ret = AVERROR_EOF;
1880  goto end;
1881  }
1882  v->cur_seq_no++;
1883  goto restart;
1884  }
1885  v->n_open_failures = 0;
1886  }
1887 
1889  /* Push init section out first before first actual fragment */
1890  int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size);
1891  memcpy(buf, v->init_sec_buf, copy_size);
1892  v->init_sec_buf_read_offset += copy_size;
1893  ret = copy_size;
1894  goto end;
1895  }
1896 
1897  /* check the v->cur_seg, if it is null, get current and double check if the new v->cur_seg*/
1898  if (!v->cur_seg) {
1899  v->cur_seg = get_current_fragment(v);
1900  }
1901  if (!v->cur_seg) {
1902  ret = AVERROR_EOF;
1903  goto end;
1904  }
1905  ret = read_from_url(v, v->cur_seg, buf, buf_size);
1906  if (ret > 0)
1907  goto end;
1908 
1909  if (c->is_live || v->cur_seq_no < v->last_seq_no) {
1910  if (!v->is_restart_needed)
1911  v->cur_seq_no++;
1912  v->is_restart_needed = 1;
1913  }
1914 
1915 end:
1916  return ret;
1917 }
1918 
1919 static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url,
1920  int flags, AVDictionary **opts)
1921 {
1923  "A DASH playlist item '%s' referred to an external file '%s'. "
1924  "Opening this file was forbidden for security reasons\n",
1925  s->url, url);
1926  return AVERROR(EPERM);
1927 }
1928 
1930 {
1931  /* note: the internal buffer could have changed */
1932  av_freep(&pls->pb.pub.buffer);
1933  memset(&pls->pb, 0x00, sizeof(pls->pb));
1934  pls->ctx->pb = NULL;
1935  avformat_close_input(&pls->ctx);
1936 }
1937 
1939 {
1940  DASHContext *c = s->priv_data;
1941  const AVInputFormat *in_fmt = NULL;
1942  AVDictionary *in_fmt_opts = NULL;
1943  uint8_t *avio_ctx_buffer = NULL;
1944  int ret = 0, i;
1945 
1946  if (pls->ctx) {
1948  }
1949 
1950  if (ff_check_interrupt(&s->interrupt_callback)) {
1951  ret = AVERROR_EXIT;
1952  goto fail;
1953  }
1954 
1955  if (!(pls->ctx = avformat_alloc_context())) {
1956  ret = AVERROR(ENOMEM);
1957  goto fail;
1958  }
1959 
1960  avio_ctx_buffer = av_malloc(INITIAL_BUFFER_SIZE);
1961  if (!avio_ctx_buffer ) {
1962  ret = AVERROR(ENOMEM);
1963  avformat_free_context(pls->ctx);
1964  pls->ctx = NULL;
1965  goto fail;
1966  }
1967  ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0,
1968  pls, read_data, NULL, c->is_live ? NULL : seek_data);
1969  pls->pb.pub.seekable = 0;
1970 
1971  if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
1972  goto fail;
1973 
1974  pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO;
1975  pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
1976  pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE;
1977  pls->ctx->interrupt_callback = s->interrupt_callback;
1978  ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, "", NULL, 0, 0);
1979  if (ret < 0) {
1980  av_log(s, AV_LOG_ERROR, "Error when loading first fragment of playlist\n");
1981  avformat_free_context(pls->ctx);
1982  pls->ctx = NULL;
1983  goto fail;
1984  }
1985 
1986  pls->ctx->pb = &pls->pb.pub;
1987  pls->ctx->io_open = nested_io_open;
1988 
1989  if (c->cenc_decryption_key)
1990  av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
1991  if (c->cenc_decryption_keys)
1992  av_dict_set(&in_fmt_opts, "decryption_keys", c->cenc_decryption_keys, 0);
1993 
1994  // provide additional information from mpd if available
1995  ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url
1996  av_dict_free(&in_fmt_opts);
1997  if (ret < 0)
1998  goto fail;
1999  if (pls->n_fragments) {
2000 #if FF_API_R_FRAME_RATE
2001  if (pls->framerate.den) {
2002  for (i = 0; i < pls->ctx->nb_streams; i++)
2003  pls->ctx->streams[i]->r_frame_rate = pls->framerate;
2004  }
2005 #endif
2007  if (ret < 0)
2008  goto fail;
2009  }
2010 
2011 fail:
2012  return ret;
2013 }
2014 
2016 {
2017  int ret = 0;
2018  int i;
2019 
2020  pls->parent = s;
2021  pls->cur_seq_no = calc_cur_seg_no(s, pls);
2022 
2023  if (!pls->last_seq_no)
2024  pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
2025 
2027  if (ret < 0)
2028  return ret;
2029 
2030  for (i = 0; i < pls->ctx->nb_streams; i++) {
2032  FFStream *sti = ffstream(st);
2033  const AVStream *ist = pls->ctx->streams[i];
2034  const FFStream *isti = cffstream(ist);
2035  if (!st)
2036  return AVERROR(ENOMEM);
2037 
2038  st->id = i + pls->stream_index;
2039 
2041  if (ret < 0)
2042  return ret;
2043 
2045 
2046  // copy disposition
2047  st->disposition = ist->disposition;
2048  sti->need_parsing = isti->need_parsing;
2049  }
2050 
2051  for (i = 0; i < pls->ctx->nb_stream_groups; i++) {
2052  AVStreamGroup *istg = pls->ctx->stream_groups[i];
2053  AVStreamGroup *stg;
2054 
2055  if (istg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
2056  continue;
2057 
2058  stg = avformat_stream_group_create(s, istg->type, NULL);
2059  if (!stg)
2060  return AVERROR(ENOMEM);
2061 
2062  stg->id = s->nb_stream_groups;
2063 
2064  for (int j = 0; j < istg->nb_streams; j++) {
2065  AVStream *ist = istg->streams[j];
2066  AVStream *st = s->streams[ist->index + pls->stream_index];
2068  if (ret < 0)
2069  return ret;
2070  }
2071 
2072  switch (stg->type) {
2076  ret = av_opt_copy(lcevc, ilcevc);
2077  if (ret < 0)
2078  return ret;
2079  break;
2080  }
2081  default:
2082  av_unreachable("Unsupported Stream Group type should have been checked above");
2083  }
2084 
2085  // copy disposition
2086  stg->disposition = istg->disposition;
2087  }
2088 
2089  return 0;
2090 }
2091 
2092 static int is_common_init_section_exist(struct representation **pls, int n_pls)
2093 {
2094  struct fragment *first_init_section = pls[0]->init_section;
2095  char *url =NULL;
2096  int64_t url_offset = -1;
2097  int64_t size = -1;
2098  int i = 0;
2099 
2100  if (first_init_section == NULL || n_pls == 0)
2101  return 0;
2102 
2103  url = first_init_section->url;
2104  url_offset = first_init_section->url_offset;
2105  size = pls[0]->init_section->size;
2106  for (i=0;i<n_pls;i++) {
2107  if (!pls[i]->init_section)
2108  continue;
2109 
2110  if (av_strcasecmp(pls[i]->init_section->url, url) ||
2111  pls[i]->init_section->url_offset != url_offset ||
2112  pls[i]->init_section->size != size) {
2113  return 0;
2114  }
2115  }
2116  return 1;
2117 }
2118 
2119 static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
2120 {
2121  rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
2122  if (!rep_dest->init_sec_buf) {
2123  av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n");
2124  return AVERROR(ENOMEM);
2125  }
2126  memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
2127  rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
2128  rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
2129  rep_dest->cur_timestamp = rep_src->cur_timestamp;
2130 
2131  return 0;
2132 }
2133 
2134 static void move_metadata(AVStream *st, const char *key, char **value)
2135 {
2136  if (*value) {
2138  *value = NULL;
2139  }
2140 }
2141 
2143 {
2144  DASHContext *c = s->priv_data;
2145  struct representation *rep;
2146  AVProgram *program;
2147  int ret = 0;
2148  int stream_index = 0;
2149  int i, j;
2150 
2151  c->interrupt_callback = &s->interrupt_callback;
2152 
2153  if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0)
2154  return ret;
2155 
2156  if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
2157  return ret;
2158 
2159  /* If this isn't a live stream, fill the total duration of the
2160  * stream. */
2161  if (!c->is_live) {
2162  s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
2163  } else {
2164  av_dict_set(&c->avio_opts, "seekable", "0", 0);
2165  }
2166 
2167  if(c->n_videos)
2168  c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
2169 
2170  /* Open the demuxer for video and audio components if available */
2171  for (i = 0; i < c->n_videos; i++) {
2172  rep = c->videos[i];
2173  if (i > 0 && c->is_init_section_common_video) {
2174  ret = copy_init_section(rep, c->videos[0]);
2175  if (ret < 0)
2176  return ret;
2177  }
2178  rep->stream_index = stream_index;
2179  ret = open_demux_for_component(s, rep);
2180 
2181  if (ret)
2182  return ret;
2183  if (rep->ctx->nb_streams == 0)
2184  return AVERROR_PATCHWELCOME;
2185  stream_index += rep->ctx->nb_streams;
2186  }
2187 
2188  if(c->n_audios)
2189  c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
2190 
2191  for (i = 0; i < c->n_audios; i++) {
2192  rep = c->audios[i];
2193  if (i > 0 && c->is_init_section_common_audio) {
2194  ret = copy_init_section(rep, c->audios[0]);
2195  if (ret < 0)
2196  return ret;
2197  }
2198  rep->stream_index = stream_index;
2199  ret = open_demux_for_component(s, rep);
2200 
2201  if (ret)
2202  return ret;
2203  if (rep->ctx->nb_streams == 0)
2204  return AVERROR_PATCHWELCOME;
2205  stream_index += rep->ctx->nb_streams;
2206  }
2207 
2208  if (c->n_subtitles)
2209  c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles);
2210 
2211  for (i = 0; i < c->n_subtitles; i++) {
2212  rep = c->subtitles[i];
2213  if (i > 0 && c->is_init_section_common_subtitle) {
2214  ret = copy_init_section(rep, c->subtitles[0]);
2215  if (ret < 0)
2216  return ret;
2217  }
2218  rep->stream_index = stream_index;
2219  ret = open_demux_for_component(s, rep);
2220 
2221  if (ret)
2222  return ret;
2223  if (rep->ctx->nb_streams == 0)
2224  return AVERROR_PATCHWELCOME;
2225  stream_index += rep->ctx->nb_streams;
2226  }
2227 
2228  if (!stream_index)
2229  return AVERROR_INVALIDDATA;
2230 
2231  /* Create a program */
2232  program = av_new_program(s, 0);
2233  if (!program)
2234  return AVERROR(ENOMEM);
2235 
2236  for (i = 0; i < c->n_videos; i++) {
2237  rep = c->videos[i];
2238  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2239  if (!rep->assoc_stream)
2240  return AVERROR(ENOMEM);
2241  rep->nb_assoc_stream = rep->ctx->nb_streams;
2242  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2244  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2245  }
2246  if (rep->bandwidth > 0)
2247  av_dict_set_int(&rep->assoc_stream[0]->metadata, "variant_bitrate", rep->bandwidth, 0);
2248  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2249  }
2250  for (i = 0; i < c->n_audios; i++) {
2251  rep = c->audios[i];
2252  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2253  if (!rep->assoc_stream)
2254  return AVERROR(ENOMEM);
2255  rep->nb_assoc_stream = rep->ctx->nb_streams;
2256  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2258  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2259  }
2260  if (rep->bandwidth > 0)
2261  av_dict_set_int(&rep->assoc_stream[0]->metadata, "variant_bitrate", rep->bandwidth, 0);
2262  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2263  move_metadata(rep->assoc_stream[0], "language", &rep->lang);
2264  }
2265  for (i = 0; i < c->n_subtitles; i++) {
2266  rep = c->subtitles[i];
2267  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2268  if (!rep->assoc_stream)
2269  return AVERROR(ENOMEM);
2270  rep->nb_assoc_stream = rep->ctx->nb_streams;
2271  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2273  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2274  }
2275  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2276  move_metadata(rep->assoc_stream[0], "language", &rep->lang);
2277  }
2278 
2279  /* Create stream groups if needed */
2280  for (i = 0; i < c->n_videos; i++) {
2281  struct representation *ref;
2282  rep = c->videos[i];
2283  if (!rep->dependencyid || !rep->nb_assoc_stream)
2284  continue;
2285  for (j = 0; j < c->n_videos; j++) {
2286  if (j == i)
2287  continue;
2288  ref = c->videos[j];
2289  if (!ref->nb_assoc_stream)
2290  continue;
2291  const AVDictionaryEntry *id = av_dict_get(ref->assoc_stream[0]->metadata, "id", NULL, AV_DICT_MATCH_CASE);
2292  if (!strcmp(rep->dependencyid, id->value))
2293  break;
2294  }
2295  if (j >= c->n_videos || !av_strstart(rep->codecs, "lvc1", NULL) ||
2297  continue;
2299  if (!stg)
2300  return AVERROR(ENOMEM);
2303  ret = avformat_stream_group_add_stream(stg, ref->assoc_stream[0]);
2304  if (ret < 0)
2305  return ret;
2307  if (ret < 0)
2308  return ret;
2309  stg->id = stg->index;
2310  stg->params.layered_video->el_index = stg->nb_streams - 1;
2311  }
2312 
2313  return 0;
2314 }
2315 
2317 {
2318  int i, j;
2319 
2320  for (i = 0; i < n; i++) {
2321  struct representation *pls = p[i];
2322  int needed = !pls->nb_assoc_stream;
2323 
2324  for (int j = 0; j < pls->nb_assoc_stream; j++)
2325  needed |= pls->assoc_stream[j]->discard < AVDISCARD_ALL;
2326 
2327  if (needed && !pls->ctx) {
2328  pls->cur_seg_offset = 0;
2329  pls->init_sec_buf_read_offset = 0;
2330  /* Catch up */
2331  for (j = 0; j < n; j++) {
2332  pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no);
2333  }
2335  av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index);
2336  } else if (!needed && pls->ctx) {
2338  ff_format_io_close(pls->parent, &pls->input);
2339  av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index);
2340  }
2341  }
2342 }
2343 
2345 {
2346  DASHContext *c = s->priv_data;
2347  int ret = 0, i;
2348  int64_t mints = 0;
2349  struct representation *cur = NULL;
2350  struct representation *rep = NULL;
2351 
2352  recheck_discard_flags(s, c->videos, c->n_videos);
2353  recheck_discard_flags(s, c->audios, c->n_audios);
2354  recheck_discard_flags(s, c->subtitles, c->n_subtitles);
2355 
2356  for (i = 0; i < c->n_videos; i++) {
2357  rep = c->videos[i];
2358  if (!rep->ctx)
2359  continue;
2360  if (!cur || rep->cur_timestamp < mints) {
2361  cur = rep;
2362  mints = rep->cur_timestamp;
2363  }
2364  }
2365  for (i = 0; i < c->n_audios; i++) {
2366  rep = c->audios[i];
2367  if (!rep->ctx)
2368  continue;
2369  if (!cur || rep->cur_timestamp < mints) {
2370  cur = rep;
2371  mints = rep->cur_timestamp;
2372  }
2373  }
2374 
2375  for (i = 0; i < c->n_subtitles; i++) {
2376  rep = c->subtitles[i];
2377  if (!rep->ctx)
2378  continue;
2379  if (!cur || rep->cur_timestamp < mints) {
2380  cur = rep;
2381  mints = rep->cur_timestamp;
2382  }
2383  }
2384 
2385  if (!cur) {
2386  return AVERROR_EOF;
2387  }
2388  while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
2389  ret = av_read_frame(cur->ctx, pkt);
2390  if (ret >= 0) {
2391  /* If we got a packet, return it */
2392  cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
2393  pkt->stream_index += cur->stream_index;
2394  return 0;
2395  }
2396  if (cur->is_restart_needed) {
2397  cur->cur_seg_offset = 0;
2398  cur->init_sec_buf_read_offset = 0;
2399  cur->is_restart_needed = 0;
2400  ff_format_io_close(cur->parent, &cur->input);
2402  } else if (ret == AVERROR_EOF) {
2404  ff_format_io_close(cur->parent, &cur->input);
2405  av_log(s, AV_LOG_DEBUG, "EOF on stream_index %d\n", cur->stream_index);
2406  // prevent recheck_discard_flags() from re-enabling the component
2407  for (int i = 0; i < cur->nb_assoc_stream; i++)
2409  return FFERROR_REDO;
2410  }
2411  }
2412  return ret;
2413 }
2414 
2416 {
2417  DASHContext *c = s->priv_data;
2418  free_audio_list(c);
2419  free_video_list(c);
2421  av_dict_free(&c->avio_opts);
2422  av_freep(&c->base_url);
2423  return 0;
2424 }
2425 
2426 static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
2427 {
2428  int ret = 0;
2429  int i = 0;
2430  int j = 0;
2431  int64_t duration = 0;
2432 
2433  av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms] %s\n",
2434  seek_pos_msec, dry_run ? " (dry)" : "");
2435 
2436  // single fragment mode
2437  if (pls->n_fragments == 1) {
2438  pls->cur_timestamp = 0;
2439  pls->cur_seg_offset = 0;
2440  if (dry_run)
2441  return 0;
2442  ff_read_frame_flush(pls->ctx);
2443  return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags);
2444  }
2445 
2446  ff_format_io_close(pls->parent, &pls->input);
2447 
2448  // find the nearest fragment
2449  if (pls->n_timelines > 0 && pls->fragment_timescale > 0) {
2450  int64_t num = pls->first_seq_no;
2451  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] "
2452  "last_seq_no[%"PRId64"].\n",
2453  (int)pls->n_timelines, (int64_t)pls->last_seq_no);
2454  for (i = 0; i < pls->n_timelines; i++) {
2455  if (pls->timelines[i]->starttime > 0) {
2456  duration = pls->timelines[i]->starttime;
2457  }
2458  duration += pls->timelines[i]->duration;
2459  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2460  goto set_seq_num;
2461  }
2462  for (j = 0; j < pls->timelines[i]->repeat; j++) {
2463  duration += pls->timelines[i]->duration;
2464  num++;
2465  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2466  goto set_seq_num;
2467  }
2468  }
2469  num++;
2470  }
2471 
2472 set_seq_num:
2473  pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num;
2474  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"].\n",
2475  (int64_t)pls->cur_seq_no);
2476  } else if (pls->fragment_duration > 0) {
2477  pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000;
2478  } else {
2479  av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n");
2480  pls->cur_seq_no = pls->first_seq_no;
2481  }
2482  pls->cur_timestamp = 0;
2483  pls->cur_seg_offset = 0;
2484  pls->init_sec_buf_read_offset = 0;
2485  ret = dry_run ? 0 : reopen_demux_for_component(s, pls);
2486 
2487  return ret;
2488 }
2489 
2490 static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
2491 {
2492  int ret = 0, i;
2493  DASHContext *c = s->priv_data;
2494  int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000,
2495  s->streams[stream_index]->time_base.den,
2498  if ((flags & AVSEEK_FLAG_BYTE) || c->is_live)
2499  return AVERROR(ENOSYS);
2500 
2501  /* Seek in discarded streams with dry_run=1 to avoid reopening them */
2502  for (i = 0; i < c->n_videos; i++) {
2503  if (!ret)
2504  ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx);
2505  }
2506  for (i = 0; i < c->n_audios; i++) {
2507  if (!ret)
2508  ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
2509  }
2510  for (i = 0; i < c->n_subtitles; i++) {
2511  if (!ret)
2512  ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
2513  }
2514 
2515  return ret;
2516 }
2517 
2518 static int dash_probe(const AVProbeData *p)
2519 {
2520  if (!av_stristr(p->buf, "<MPD"))
2521  return 0;
2522 
2523  if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") ||
2524  av_stristr(p->buf, "dash:profile:isoff-live:2011") ||
2525  av_stristr(p->buf, "dash:profile:isoff-live:2012") ||
2526  av_stristr(p->buf, "dash:profile:isoff-main:2011") ||
2527  av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) {
2528  return AVPROBE_SCORE_MAX;
2529  }
2530  if (av_stristr(p->buf, "dash:profile")) {
2531  return AVPROBE_SCORE_MAX;
2532  }
2533 
2534  return 0;
2535 }
2536 
2537 #define OFFSET(x) offsetof(DASHContext, x)
2538 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
2539 static const AVOption dash_options[] = {
2540  {"allowed_extensions", "List of file extensions that dash is allowed to access",
2541  OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
2542  {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"},
2543  INT_MIN, INT_MAX, FLAGS},
2544  { "cenc_decryption_key", "Media default decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
2545  { "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 },
2546  { "max_reload", "Maximum number of manifest reloads in get_current_fragment() before giving up",
2547  OFFSET(max_reload), AV_OPT_TYPE_INT, { .i64 = 100 }, 0, INT_MAX, FLAGS },
2548  {NULL}
2549 };
2550 
2551 static const AVClass dash_class = {
2552  .class_name = "dash",
2553  .item_name = av_default_item_name,
2554  .option = dash_options,
2555  .version = LIBAVUTIL_VERSION_INT,
2556 };
2557 
2559  .p.name = "dash",
2560  .p.long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"),
2561  .p.priv_class = &dash_class,
2562  .p.flags = AVFMT_NO_BYTE_SEEK,
2563  .priv_data_size = sizeof(DASHContext),
2564  .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
2570 };
AV_OPT_SEARCH_CHILDREN
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:604
flags
const SwsFlags flags[]
Definition: swscale.c:85
reopen_demux_for_component
static int reopen_demux_for_component(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1938
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:1929
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:1401
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:1159
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:2015
read_data
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition: dashdec.c:1848
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
AVStreamGroupLayeredVideo
AVStreamGroupLayeredVideo is meant to define the relation between a base layer video stream and a sep...
Definition: avformat.h:1074
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
AV_STREAM_GROUP_PARAMS_LCEVC
@ AV_STREAM_GROUP_PARAMS_LCEVC
Definition: avformat.h:1132
get_utc_date_time_insec
static int64_t get_utc_date_time_insec(AVFormatContext *s, const char *datetime)
Definition: dashdec.c:188
ishttp
static int ishttp(char *url)
Definition: dashdec.c:172
get_current_time_in_sec
static int64_t get_current_time_in_sec(void)
Definition: dashdec.c:183
calc_min_seg_no
static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1481
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:2538
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:1654
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:1225
dash_close
static int dash_close(AVFormatContext *s)
Definition: dashdec.c:2415
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:1382
DASHContext::minimum_update_period
int64_t minimum_update_period
Definition: dashdec.c:145
AVOption
AVOption.
Definition: opt.h:428
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:615
AVFMT_FLAG_CUSTOM_IO
#define AVFMT_FLAG_CUSTOM_IO
The caller has supplied a custom AVIOContext, don't avio_close() it.
Definition: avformat.h:1473
AVSEEK_FLAG_BYTE
#define AVSEEK_FLAG_BYTE
seeking based on position in bytes
Definition: avformat.h:2574
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:1498
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:363
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:1744
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
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
DASHContext::media_presentation_duration
int64_t media_presentation_duration
Definition: dashdec.c:140
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:1584
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:830
representation::init_section
struct fragment * init_section
Definition: dashdec.c:119
finish
static void finish(void)
Definition: movenc.c:374
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:1495
ffstream
static av_always_inline FFStream * ffstream(AVStream *st)
Definition: internal.h:358
free_fragment
static void free_fragment(struct fragment **seg)
Definition: dashdec.c:328
calc_cur_seg_no
static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1445
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
DASHContext::availability_start_time
int64_t availability_start_time
Definition: dashdec.c:142
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:2316
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
av_timegm
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:573
av_new_program
AVProgram * av_new_program(AVFormatContext *ac, int id)
Definition: avformat.c:277
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:2539
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
seek_data
static int64_t seek_data(void *opaque, int64_t offset, int whence)
Definition: dashdec.c:1838
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
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:2134
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:1534
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
DASHContext::min_buffer_time
int64_t min_buffer_time
Definition: dashdec.c:147
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1465
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:1151
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:1242
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
AVStreamGroup::layered_video
struct AVStreamGroupLayeredVideo * layered_video
Definition: avformat.h:1176
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:1506
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:1314
fail
#define fail
Definition: test.h:478
representation::lang
char * lang
Definition: dashdec.c:89
internal.h
opts
static AVDictionary * opts
Definition: movenc.c:51
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:2573
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
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
av_program_add_stream_index
void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned idx)
Definition: avformat.c:338
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:2092
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:875
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:2490
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1356
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:1520
representation::timelines
struct timeline ** timelines
Definition: dashdec.c:101
AVStream::metadata
AVDictionary * metadata
Definition: avformat.h:827
time.h
ff_dash_demuxer
const FFInputFormat ff_dash_demuxer
Definition: dashdec.c:2558
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:1271
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
DASHContext::suggested_presentation_delay
int64_t suggested_presentation_delay
Definition: dashdec.c:141
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:557
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:2132
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1370
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
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:722
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:88
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:164
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:862
DASHContext::time_shift_buffer_depth
int64_t time_shift_buffer_depth
Definition: dashdec.c:146
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:952
AVMEDIA_TYPE_UNKNOWN
@ AVMEDIA_TYPE_UNKNOWN
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:199
OFFSET
#define OFFSET(x)
Definition: dashdec.c:2537
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:2119
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:2142
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
DASHContext::max_reload
int max_reload
Definition: dashdec.c:161
AV_CODEC_ID_LCEVC
@ AV_CODEC_ID_LCEVC
Definition: codec_id.h:608
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
AVStreamGroup::params
union AVStreamGroup::@454 params
Group type-specific parameters.
read_header
static int read_header(FFV1Context *f, RangeCoder *c)
Definition: ffv1dec.c:578
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:1215
get_fragment
static struct fragment * get_fragment(AVFormatContext *s, char *range)
Definition: dashdec.c:592
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
FFERROR_REDO
#define FFERROR_REDO
Returned by demuxers to indicate that data was consumed but discarded (ignored streams or junk data).
Definition: demux.h:224
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:596
avio_internal.h
dash_probe
static int dash_probe(const AVProbeData *p)
Definition: dashdec.c:2518
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
AVStreamGroupLayeredVideo::width
int width
Width of the final stream for presentation.
Definition: avformat.h:1095
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:1186
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:1238
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::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:1919
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
AVStreamGroupLayeredVideo::height
int height
Height of the final image for presentation.
Definition: avformat.h:1099
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:681
DASHContext::availability_end_time
int64_t availability_end_time
Definition: dashdec.c:143
id
enum AVCodecID id
Definition: dts2pts.c:607
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:1140
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:1202
parse_manifest_adaptationset_attr
static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node)
Definition: dashdec.c:1173
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:258
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:1555
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:1919
update_init_section
static int update_init_section(struct representation *pls)
Definition: dashdec.c:1792
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:899
AVPacket::stream_index
int stream_index
Definition: packet.h:605
dash_read_packet
static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dashdec.c:2344
open_input
static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
Definition: dashdec.c:1760
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:1167
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:469
AVFormatContext::nb_stream_groups
unsigned int nb_stream_groups
Number of elements in AVFormatContext.stream_groups.
Definition: avformat.h:1389
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:580
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
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:1204
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
DASHContext::publish_time
int64_t publish_time
Definition: dashdec.c:144
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:2426
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:275
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
AVStreamGroupLayeredVideo::el_index
unsigned int el_index
Index of the enhancement layer stream in AVStreamGroup.
Definition: avformat.h:1083
representation::fragments
struct fragment ** fragments
Definition: dashdec.c:98
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1342
dash_class
static const AVClass dash_class
Definition: dashdec.c:2551
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