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  rep_dest->fragments = rep_src->fragments;
1543  rep_dest->n_fragments = rep_src->n_fragments;
1544  rep_dest->parent = rep_src->parent;
1545  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1546  rep_src->fragments = NULL;
1547  rep_src->n_fragments = 0;
1548  }
1549 }
1550 
1551 
1553 {
1554  int ret = 0, i;
1555  DASHContext *c = s->priv_data;
1556  // save current context
1557  int n_videos = c->n_videos;
1558  struct representation **videos = c->videos;
1559  int n_audios = c->n_audios;
1560  struct representation **audios = c->audios;
1561  int n_subtitles = c->n_subtitles;
1562  struct representation **subtitles = c->subtitles;
1563  char *base_url = c->base_url;
1564 
1565  c->base_url = NULL;
1566  c->n_videos = 0;
1567  c->videos = NULL;
1568  c->n_audios = 0;
1569  c->audios = NULL;
1570  c->n_subtitles = 0;
1571  c->subtitles = NULL;
1572  ret = parse_manifest(s, s->url, NULL);
1573  if (ret)
1574  goto finish;
1575 
1576  if (c->n_videos != n_videos) {
1578  "new manifest has mismatched no. of video representations, %d -> %d\n",
1579  n_videos, c->n_videos);
1580  return AVERROR_INVALIDDATA;
1581  }
1582  if (c->n_audios != n_audios) {
1584  "new manifest has mismatched no. of audio representations, %d -> %d\n",
1585  n_audios, c->n_audios);
1586  return AVERROR_INVALIDDATA;
1587  }
1588  if (c->n_subtitles != n_subtitles) {
1590  "new manifest has mismatched no. of subtitles representations, %d -> %d\n",
1591  n_subtitles, c->n_subtitles);
1592  return AVERROR_INVALIDDATA;
1593  }
1594 
1595  for (i = 0; i < n_videos; i++) {
1596  struct representation *cur_video = videos[i];
1597  struct representation *ccur_video = c->videos[i];
1598  if (cur_video->timelines && cur_video->fragment_timescale > 0) {
1599  // calc current time
1600  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale;
1601  // update segments
1602  ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1);
1603  if (ccur_video->cur_seq_no >= 0) {
1604  move_timelines(ccur_video, cur_video, c);
1605  }
1606  }
1607  if (cur_video->fragments) {
1608  move_segments(ccur_video, cur_video, c);
1609  }
1610  }
1611  for (i = 0; i < n_audios; i++) {
1612  struct representation *cur_audio = audios[i];
1613  struct representation *ccur_audio = c->audios[i];
1614  if (cur_audio->timelines && cur_audio->fragment_timescale > 0) {
1615  // calc current time
1616  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale;
1617  // update segments
1618  ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1);
1619  if (ccur_audio->cur_seq_no >= 0) {
1620  move_timelines(ccur_audio, cur_audio, c);
1621  }
1622  }
1623  if (cur_audio->fragments) {
1624  move_segments(ccur_audio, cur_audio, c);
1625  }
1626  }
1627 
1628 finish:
1629  // restore context
1630  if (c->base_url)
1631  av_free(base_url);
1632  else
1633  c->base_url = base_url;
1634 
1635  if (c->subtitles)
1637  if (c->audios)
1638  free_audio_list(c);
1639  if (c->videos)
1640  free_video_list(c);
1641 
1642  c->n_subtitles = n_subtitles;
1643  c->subtitles = subtitles;
1644  c->n_audios = n_audios;
1645  c->audios = audios;
1646  c->n_videos = n_videos;
1647  c->videos = videos;
1648  return ret;
1649 }
1650 
1651 static struct fragment *get_current_fragment(struct representation *pls)
1652 {
1653  int64_t min_seq_no = 0;
1654  int64_t max_seq_no = 0;
1655  struct fragment *seg = NULL;
1656  struct fragment *seg_ptr = NULL;
1657  DASHContext *c = pls->parent->priv_data;
1658  int reload_count = 0;
1659 
1660  while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) {
1661  if (pls->cur_seq_no < pls->n_fragments) {
1662  seg_ptr = pls->fragments[pls->cur_seq_no];
1663  seg = av_mallocz(sizeof(struct fragment));
1664  if (!seg) {
1665  return NULL;
1666  }
1667  seg->url = av_strdup(seg_ptr->url);
1668  if (!seg->url) {
1669  av_free(seg);
1670  return NULL;
1671  }
1672  seg->size = seg_ptr->size;
1673  seg->url_offset = seg_ptr->url_offset;
1674  return seg;
1675  } else if (c->is_live) {
1676  if (reload_count++ >= c->max_reload) {
1677  av_log(pls->parent, AV_LOG_ERROR,
1678  "Reached max manifest reloads (%d) at seq %"PRId64"\n",
1679  c->max_reload, pls->cur_seq_no);
1680  return NULL;
1681  }
1682  refresh_manifest(pls->parent);
1683  } else {
1684  break;
1685  }
1686  }
1687  if (c->is_live) {
1688  min_seq_no = calc_min_seg_no(pls->parent, pls);
1689  max_seq_no = calc_max_seg_no(pls, c);
1690 
1691  if (pls->timelines || pls->fragments) {
1692  refresh_manifest(pls->parent);
1693  }
1694  if (pls->cur_seq_no <= min_seq_no) {
1695  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);
1696  pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls);
1697  } else if (pls->cur_seq_no > max_seq_no) {
1698  av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] max[%"PRId64"]\n", min_seq_no, max_seq_no);
1699  }
1700  seg = av_mallocz(sizeof(struct fragment));
1701  if (!seg) {
1702  return NULL;
1703  }
1704  } else if (pls->cur_seq_no <= pls->last_seq_no) {
1705  seg = av_mallocz(sizeof(struct fragment));
1706  if (!seg) {
1707  return NULL;
1708  }
1709  }
1710  if (seg) {
1711  char *tmpfilename;
1712  if (!pls->url_template) {
1713  av_log(pls->parent, AV_LOG_ERROR, "Cannot get fragment, missing template URL\n");
1714  av_free(seg);
1715  return NULL;
1716  }
1717  tmpfilename = av_mallocz(c->max_url_size);
1718  if (!tmpfilename) {
1719  av_free(seg);
1720  return NULL;
1721  }
1722  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));
1723  seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename);
1724  if (!seg->url) {
1725  av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template);
1726  seg->url = av_strdup(pls->url_template);
1727  if (!seg->url) {
1728  av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template);
1729  av_free(tmpfilename);
1730  av_free(seg);
1731  return NULL;
1732  }
1733  }
1734  av_free(tmpfilename);
1735  seg->size = -1;
1736  }
1737 
1738  return seg;
1739 }
1740 
1741 static int read_from_url(struct representation *pls, struct fragment *seg,
1742  uint8_t *buf, int buf_size)
1743 {
1744  int ret;
1745 
1746  /* limit read if the fragment was only a part of a file */
1747  if (seg->size >= 0)
1748  buf_size = FFMIN(buf_size, pls->cur_seg_size - pls->cur_seg_offset);
1749 
1750  ret = avio_read(pls->input, buf, buf_size);
1751  if (ret > 0)
1752  pls->cur_seg_offset += ret;
1753 
1754  return ret;
1755 }
1756 
1757 static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
1758 {
1759  AVDictionary *opts = NULL;
1760  char *url = NULL;
1761  int ret = 0;
1762 
1763  url = av_mallocz(c->max_url_size);
1764  if (!url) {
1765  ret = AVERROR(ENOMEM);
1766  goto cleanup;
1767  }
1768 
1769  if (seg->size >= 0) {
1770  /* try to restrict the HTTP request to the part we want
1771  * (if this is in fact a HTTP request) */
1772  av_dict_set_int(&opts, "offset", seg->url_offset, 0);
1773  av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
1774  }
1775 
1776  ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url);
1777  av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64"\n",
1778  url, seg->url_offset);
1779  ret = open_url(pls->parent, &pls->input, url, &c->avio_opts, opts, NULL);
1780 
1781 cleanup:
1782  av_free(url);
1783  av_dict_free(&opts);
1784  pls->cur_seg_offset = 0;
1785  pls->cur_seg_size = seg->size;
1786  return ret;
1787 }
1788 
1789 static int update_init_section(struct representation *pls)
1790 {
1791  static const int max_init_section_size = 1024 * 1024;
1792  DASHContext *c = pls->parent->priv_data;
1793  int64_t sec_size;
1794  int64_t urlsize;
1795  int ret;
1796 
1797  if (!pls->init_section || pls->init_sec_buf)
1798  return 0;
1799 
1800  ret = open_input(c, pls, pls->init_section);
1801  if (ret < 0) {
1803  "Failed to open an initialization section\n");
1804  return ret;
1805  }
1806 
1807  if (pls->init_section->size >= 0)
1808  sec_size = pls->init_section->size;
1809  else if ((urlsize = avio_size(pls->input)) >= 0)
1810  sec_size = urlsize;
1811  else
1812  sec_size = max_init_section_size;
1813 
1814  av_log(pls->parent, AV_LOG_DEBUG,
1815  "Downloading an initialization section of size %"PRId64"\n",
1816  sec_size);
1817 
1818  sec_size = FFMIN(sec_size, max_init_section_size);
1819 
1820  av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size);
1821 
1822  ret = read_from_url(pls, pls->init_section, pls->init_sec_buf,
1823  pls->init_sec_buf_size);
1824  ff_format_io_close(pls->parent, &pls->input);
1825 
1826  if (ret < 0)
1827  return ret;
1828 
1829  pls->init_sec_data_len = ret;
1830  pls->init_sec_buf_read_offset = 0;
1831 
1832  return 0;
1833 }
1834 
1835 static int64_t seek_data(void *opaque, int64_t offset, int whence)
1836 {
1837  struct representation *v = opaque;
1838  if (v->n_fragments && !v->init_sec_data_len) {
1839  return avio_seek(v->input, offset, whence);
1840  }
1841 
1842  return AVERROR(ENOSYS);
1843 }
1844 
1845 static int read_data(void *opaque, uint8_t *buf, int buf_size)
1846 {
1847  int ret = 0;
1848  struct representation *v = opaque;
1849  DASHContext *c = v->parent->priv_data;
1850 
1851 restart:
1852  if (!v->input) {
1853  free_fragment(&v->cur_seg);
1854  v->cur_seg = get_current_fragment(v);
1855  if (!v->cur_seg) {
1856  ret = AVERROR_EOF;
1857  goto end;
1858  }
1859 
1860  /* load/update Media Initialization Section, if any */
1861  ret = update_init_section(v);
1862  if (ret)
1863  goto end;
1864 
1865  ret = open_input(c, v, v->cur_seg);
1866  if (ret < 0) {
1867  if (ff_check_interrupt(c->interrupt_callback)) {
1868  ret = AVERROR_EXIT;
1869  goto end;
1870  }
1871  av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist\n");
1872  if (++v->n_open_failures > c->max_reload) {
1874  "Reached max consecutive fragment open failures (%d), giving up\n",
1875  c->max_reload);
1876  ret = AVERROR_EOF;
1877  goto end;
1878  }
1879  v->cur_seq_no++;
1880  goto restart;
1881  }
1882  v->n_open_failures = 0;
1883  }
1884 
1886  /* Push init section out first before first actual fragment */
1887  int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size);
1888  memcpy(buf, v->init_sec_buf, copy_size);
1889  v->init_sec_buf_read_offset += copy_size;
1890  ret = copy_size;
1891  goto end;
1892  }
1893 
1894  /* check the v->cur_seg, if it is null, get current and double check if the new v->cur_seg*/
1895  if (!v->cur_seg) {
1896  v->cur_seg = get_current_fragment(v);
1897  }
1898  if (!v->cur_seg) {
1899  ret = AVERROR_EOF;
1900  goto end;
1901  }
1902  ret = read_from_url(v, v->cur_seg, buf, buf_size);
1903  if (ret > 0)
1904  goto end;
1905 
1906  if (c->is_live || v->cur_seq_no < v->last_seq_no) {
1907  if (!v->is_restart_needed)
1908  v->cur_seq_no++;
1909  v->is_restart_needed = 1;
1910  }
1911 
1912 end:
1913  return ret;
1914 }
1915 
1916 static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url,
1917  int flags, AVDictionary **opts)
1918 {
1920  "A DASH playlist item '%s' referred to an external file '%s'. "
1921  "Opening this file was forbidden for security reasons\n",
1922  s->url, url);
1923  return AVERROR(EPERM);
1924 }
1925 
1927 {
1928  /* note: the internal buffer could have changed */
1929  av_freep(&pls->pb.pub.buffer);
1930  memset(&pls->pb, 0x00, sizeof(pls->pb));
1931  pls->ctx->pb = NULL;
1932  avformat_close_input(&pls->ctx);
1933 }
1934 
1936 {
1937  DASHContext *c = s->priv_data;
1938  const AVInputFormat *in_fmt = NULL;
1939  AVDictionary *in_fmt_opts = NULL;
1940  uint8_t *avio_ctx_buffer = NULL;
1941  int ret = 0, i;
1942 
1943  if (pls->ctx) {
1945  }
1946 
1947  if (ff_check_interrupt(&s->interrupt_callback)) {
1948  ret = AVERROR_EXIT;
1949  goto fail;
1950  }
1951 
1952  if (!(pls->ctx = avformat_alloc_context())) {
1953  ret = AVERROR(ENOMEM);
1954  goto fail;
1955  }
1956 
1957  avio_ctx_buffer = av_malloc(INITIAL_BUFFER_SIZE);
1958  if (!avio_ctx_buffer ) {
1959  ret = AVERROR(ENOMEM);
1960  avformat_free_context(pls->ctx);
1961  pls->ctx = NULL;
1962  goto fail;
1963  }
1964  ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0,
1965  pls, read_data, NULL, c->is_live ? NULL : seek_data);
1966  pls->pb.pub.seekable = 0;
1967 
1968  if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
1969  goto fail;
1970 
1971  pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO;
1972  pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
1973  pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE;
1974  pls->ctx->interrupt_callback = s->interrupt_callback;
1975  ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, "", NULL, 0, 0);
1976  if (ret < 0) {
1977  av_log(s, AV_LOG_ERROR, "Error when loading first fragment of playlist\n");
1978  avformat_free_context(pls->ctx);
1979  pls->ctx = NULL;
1980  goto fail;
1981  }
1982 
1983  pls->ctx->pb = &pls->pb.pub;
1984  pls->ctx->io_open = nested_io_open;
1985 
1986  if (c->cenc_decryption_key)
1987  av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
1988  if (c->cenc_decryption_keys)
1989  av_dict_set(&in_fmt_opts, "decryption_keys", c->cenc_decryption_keys, 0);
1990 
1991  // provide additional information from mpd if available
1992  ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url
1993  av_dict_free(&in_fmt_opts);
1994  if (ret < 0)
1995  goto fail;
1996  if (pls->n_fragments) {
1997 #if FF_API_R_FRAME_RATE
1998  if (pls->framerate.den) {
1999  for (i = 0; i < pls->ctx->nb_streams; i++)
2000  pls->ctx->streams[i]->r_frame_rate = pls->framerate;
2001  }
2002 #endif
2004  if (ret < 0)
2005  goto fail;
2006  }
2007 
2008 fail:
2009  return ret;
2010 }
2011 
2013 {
2014  int ret = 0;
2015  int i;
2016 
2017  pls->parent = s;
2018  pls->cur_seq_no = calc_cur_seg_no(s, pls);
2019 
2020  if (!pls->last_seq_no)
2021  pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
2022 
2024  if (ret < 0)
2025  return ret;
2026 
2027  for (i = 0; i < pls->ctx->nb_streams; i++) {
2029  FFStream *sti = ffstream(st);
2030  const AVStream *ist = pls->ctx->streams[i];
2031  const FFStream *isti = cffstream(ist);
2032  if (!st)
2033  return AVERROR(ENOMEM);
2034 
2035  st->id = i + pls->stream_index;
2036 
2038  if (ret < 0)
2039  return ret;
2040 
2042 
2043  // copy disposition
2044  st->disposition = ist->disposition;
2045  sti->need_parsing = isti->need_parsing;
2046  }
2047 
2048  for (i = 0; i < pls->ctx->nb_stream_groups; i++) {
2049  AVStreamGroup *istg = pls->ctx->stream_groups[i];
2050  AVStreamGroup *stg;
2051 
2052  if (istg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
2053  continue;
2054 
2055  stg = avformat_stream_group_create(s, istg->type, NULL);
2056  if (!stg)
2057  return AVERROR(ENOMEM);
2058 
2059  stg->id = s->nb_stream_groups;
2060 
2061  for (int j = 0; j < istg->nb_streams; j++) {
2062  AVStream *ist = istg->streams[j];
2063  AVStream *st = s->streams[ist->index + pls->stream_index];
2065  if (ret < 0)
2066  return ret;
2067  }
2068 
2069  switch (stg->type) {
2073  ret = av_opt_copy(lcevc, ilcevc);
2074  if (ret < 0)
2075  return ret;
2076  break;
2077  }
2078  default:
2079  av_unreachable("Unsupported Stream Group type should have been checked above");
2080  }
2081 
2082  // copy disposition
2083  stg->disposition = istg->disposition;
2084  }
2085 
2086  return 0;
2087 }
2088 
2089 static int is_common_init_section_exist(struct representation **pls, int n_pls)
2090 {
2091  struct fragment *first_init_section = pls[0]->init_section;
2092  char *url =NULL;
2093  int64_t url_offset = -1;
2094  int64_t size = -1;
2095  int i = 0;
2096 
2097  if (first_init_section == NULL || n_pls == 0)
2098  return 0;
2099 
2100  url = first_init_section->url;
2101  url_offset = first_init_section->url_offset;
2102  size = pls[0]->init_section->size;
2103  for (i=0;i<n_pls;i++) {
2104  if (!pls[i]->init_section)
2105  continue;
2106 
2107  if (av_strcasecmp(pls[i]->init_section->url, url) ||
2108  pls[i]->init_section->url_offset != url_offset ||
2109  pls[i]->init_section->size != size) {
2110  return 0;
2111  }
2112  }
2113  return 1;
2114 }
2115 
2116 static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
2117 {
2118  rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
2119  if (!rep_dest->init_sec_buf) {
2120  av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n");
2121  return AVERROR(ENOMEM);
2122  }
2123  memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
2124  rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
2125  rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
2126  rep_dest->cur_timestamp = rep_src->cur_timestamp;
2127 
2128  return 0;
2129 }
2130 
2131 static void move_metadata(AVStream *st, const char *key, char **value)
2132 {
2133  if (*value) {
2135  *value = NULL;
2136  }
2137 }
2138 
2140 {
2141  DASHContext *c = s->priv_data;
2142  struct representation *rep;
2143  AVProgram *program;
2144  int ret = 0;
2145  int stream_index = 0;
2146  int i, j;
2147 
2148  c->interrupt_callback = &s->interrupt_callback;
2149 
2150  if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0)
2151  return ret;
2152 
2153  if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
2154  return ret;
2155 
2156  /* If this isn't a live stream, fill the total duration of the
2157  * stream. */
2158  if (!c->is_live) {
2159  s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
2160  } else {
2161  av_dict_set(&c->avio_opts, "seekable", "0", 0);
2162  }
2163 
2164  if(c->n_videos)
2165  c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
2166 
2167  /* Open the demuxer for video and audio components if available */
2168  for (i = 0; i < c->n_videos; i++) {
2169  rep = c->videos[i];
2170  if (i > 0 && c->is_init_section_common_video) {
2171  ret = copy_init_section(rep, c->videos[0]);
2172  if (ret < 0)
2173  return ret;
2174  }
2175  rep->stream_index = stream_index;
2176  ret = open_demux_for_component(s, rep);
2177 
2178  if (ret)
2179  return ret;
2180  if (rep->ctx->nb_streams == 0)
2181  return AVERROR_PATCHWELCOME;
2182  stream_index += rep->ctx->nb_streams;
2183  }
2184 
2185  if(c->n_audios)
2186  c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
2187 
2188  for (i = 0; i < c->n_audios; i++) {
2189  rep = c->audios[i];
2190  if (i > 0 && c->is_init_section_common_audio) {
2191  ret = copy_init_section(rep, c->audios[0]);
2192  if (ret < 0)
2193  return ret;
2194  }
2195  rep->stream_index = stream_index;
2196  ret = open_demux_for_component(s, rep);
2197 
2198  if (ret)
2199  return ret;
2200  if (rep->ctx->nb_streams == 0)
2201  return AVERROR_PATCHWELCOME;
2202  stream_index += rep->ctx->nb_streams;
2203  }
2204 
2205  if (c->n_subtitles)
2206  c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles);
2207 
2208  for (i = 0; i < c->n_subtitles; i++) {
2209  rep = c->subtitles[i];
2210  if (i > 0 && c->is_init_section_common_subtitle) {
2211  ret = copy_init_section(rep, c->subtitles[0]);
2212  if (ret < 0)
2213  return ret;
2214  }
2215  rep->stream_index = stream_index;
2216  ret = open_demux_for_component(s, rep);
2217 
2218  if (ret)
2219  return ret;
2220  if (rep->ctx->nb_streams == 0)
2221  return AVERROR_PATCHWELCOME;
2222  stream_index += rep->ctx->nb_streams;
2223  }
2224 
2225  if (!stream_index)
2226  return AVERROR_INVALIDDATA;
2227 
2228  /* Create a program */
2229  program = av_new_program(s, 0);
2230  if (!program)
2231  return AVERROR(ENOMEM);
2232 
2233  for (i = 0; i < c->n_videos; i++) {
2234  rep = c->videos[i];
2235  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2236  if (!rep->assoc_stream)
2237  return AVERROR(ENOMEM);
2238  rep->nb_assoc_stream = rep->ctx->nb_streams;
2239  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2241  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2242  }
2243  if (rep->bandwidth > 0)
2244  av_dict_set_int(&rep->assoc_stream[0]->metadata, "variant_bitrate", rep->bandwidth, 0);
2245  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2246  }
2247  for (i = 0; i < c->n_audios; i++) {
2248  rep = c->audios[i];
2249  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2250  if (!rep->assoc_stream)
2251  return AVERROR(ENOMEM);
2252  rep->nb_assoc_stream = rep->ctx->nb_streams;
2253  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2255  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2256  }
2257  if (rep->bandwidth > 0)
2258  av_dict_set_int(&rep->assoc_stream[0]->metadata, "variant_bitrate", rep->bandwidth, 0);
2259  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2260  move_metadata(rep->assoc_stream[0], "language", &rep->lang);
2261  }
2262  for (i = 0; i < c->n_subtitles; i++) {
2263  rep = c->subtitles[i];
2264  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2265  if (!rep->assoc_stream)
2266  return AVERROR(ENOMEM);
2267  rep->nb_assoc_stream = rep->ctx->nb_streams;
2268  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2270  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2271  }
2272  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2273  move_metadata(rep->assoc_stream[0], "language", &rep->lang);
2274  }
2275 
2276  /* Create stream groups if needed */
2277  for (i = 0; i < c->n_videos; i++) {
2278  struct representation *ref;
2279  rep = c->videos[i];
2280  if (!rep->dependencyid || !rep->nb_assoc_stream)
2281  continue;
2282  for (j = 0; j < c->n_videos; j++) {
2283  if (j == i)
2284  continue;
2285  ref = c->videos[j];
2286  if (!ref->nb_assoc_stream)
2287  continue;
2288  const AVDictionaryEntry *id = av_dict_get(ref->assoc_stream[0]->metadata, "id", NULL, AV_DICT_MATCH_CASE);
2289  if (!strcmp(rep->dependencyid, id->value))
2290  break;
2291  }
2292  if (j >= c->n_videos || !av_strstart(rep->codecs, "lvc1", NULL) ||
2294  continue;
2296  if (!stg)
2297  return AVERROR(ENOMEM);
2300  ret = avformat_stream_group_add_stream(stg, ref->assoc_stream[0]);
2301  if (ret < 0)
2302  return ret;
2304  if (ret < 0)
2305  return ret;
2306  stg->id = stg->index;
2307  stg->params.layered_video->el_index = stg->nb_streams - 1;
2308  }
2309 
2310  return 0;
2311 }
2312 
2314 {
2315  int i, j;
2316 
2317  for (i = 0; i < n; i++) {
2318  struct representation *pls = p[i];
2319  int needed = !pls->nb_assoc_stream;
2320 
2321  for (int j = 0; j < pls->nb_assoc_stream; j++)
2322  needed |= pls->assoc_stream[j]->discard < AVDISCARD_ALL;
2323 
2324  if (needed && !pls->ctx) {
2325  pls->cur_seg_offset = 0;
2326  pls->init_sec_buf_read_offset = 0;
2327  /* Catch up */
2328  for (j = 0; j < n; j++) {
2329  pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no);
2330  }
2332  av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index);
2333  } else if (!needed && pls->ctx) {
2335  ff_format_io_close(pls->parent, &pls->input);
2336  av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index);
2337  }
2338  }
2339 }
2340 
2342 {
2343  DASHContext *c = s->priv_data;
2344  int ret = 0, i;
2345  int64_t mints = 0;
2346  struct representation *cur = NULL;
2347  struct representation *rep = NULL;
2348 
2349  recheck_discard_flags(s, c->videos, c->n_videos);
2350  recheck_discard_flags(s, c->audios, c->n_audios);
2351  recheck_discard_flags(s, c->subtitles, c->n_subtitles);
2352 
2353  for (i = 0; i < c->n_videos; i++) {
2354  rep = c->videos[i];
2355  if (!rep->ctx)
2356  continue;
2357  if (!cur || rep->cur_timestamp < mints) {
2358  cur = rep;
2359  mints = rep->cur_timestamp;
2360  }
2361  }
2362  for (i = 0; i < c->n_audios; i++) {
2363  rep = c->audios[i];
2364  if (!rep->ctx)
2365  continue;
2366  if (!cur || rep->cur_timestamp < mints) {
2367  cur = rep;
2368  mints = rep->cur_timestamp;
2369  }
2370  }
2371 
2372  for (i = 0; i < c->n_subtitles; i++) {
2373  rep = c->subtitles[i];
2374  if (!rep->ctx)
2375  continue;
2376  if (!cur || rep->cur_timestamp < mints) {
2377  cur = rep;
2378  mints = rep->cur_timestamp;
2379  }
2380  }
2381 
2382  if (!cur) {
2383  return AVERROR_INVALIDDATA;
2384  }
2385  while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
2386  ret = av_read_frame(cur->ctx, pkt);
2387  if (ret >= 0) {
2388  /* If we got a packet, return it */
2389  cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
2390  pkt->stream_index += cur->stream_index;
2391  return 0;
2392  }
2393  if (cur->is_restart_needed) {
2394  cur->cur_seg_offset = 0;
2395  cur->init_sec_buf_read_offset = 0;
2396  cur->is_restart_needed = 0;
2397  ff_format_io_close(cur->parent, &cur->input);
2399  }
2400  }
2401  return AVERROR_EOF;
2402 }
2403 
2405 {
2406  DASHContext *c = s->priv_data;
2407  free_audio_list(c);
2408  free_video_list(c);
2410  av_dict_free(&c->avio_opts);
2411  av_freep(&c->base_url);
2412  return 0;
2413 }
2414 
2415 static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
2416 {
2417  int ret = 0;
2418  int i = 0;
2419  int j = 0;
2420  int64_t duration = 0;
2421 
2422  av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms] %s\n",
2423  seek_pos_msec, dry_run ? " (dry)" : "");
2424 
2425  // single fragment mode
2426  if (pls->n_fragments == 1) {
2427  pls->cur_timestamp = 0;
2428  pls->cur_seg_offset = 0;
2429  if (dry_run)
2430  return 0;
2431  ff_read_frame_flush(pls->ctx);
2432  return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags);
2433  }
2434 
2435  ff_format_io_close(pls->parent, &pls->input);
2436 
2437  // find the nearest fragment
2438  if (pls->n_timelines > 0 && pls->fragment_timescale > 0) {
2439  int64_t num = pls->first_seq_no;
2440  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] "
2441  "last_seq_no[%"PRId64"].\n",
2442  (int)pls->n_timelines, (int64_t)pls->last_seq_no);
2443  for (i = 0; i < pls->n_timelines; i++) {
2444  if (pls->timelines[i]->starttime > 0) {
2445  duration = pls->timelines[i]->starttime;
2446  }
2447  duration += pls->timelines[i]->duration;
2448  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2449  goto set_seq_num;
2450  }
2451  for (j = 0; j < pls->timelines[i]->repeat; j++) {
2452  duration += pls->timelines[i]->duration;
2453  num++;
2454  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2455  goto set_seq_num;
2456  }
2457  }
2458  num++;
2459  }
2460 
2461 set_seq_num:
2462  pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num;
2463  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"].\n",
2464  (int64_t)pls->cur_seq_no);
2465  } else if (pls->fragment_duration > 0) {
2466  pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000;
2467  } else {
2468  av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n");
2469  pls->cur_seq_no = pls->first_seq_no;
2470  }
2471  pls->cur_timestamp = 0;
2472  pls->cur_seg_offset = 0;
2473  pls->init_sec_buf_read_offset = 0;
2474  ret = dry_run ? 0 : reopen_demux_for_component(s, pls);
2475 
2476  return ret;
2477 }
2478 
2479 static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
2480 {
2481  int ret = 0, i;
2482  DASHContext *c = s->priv_data;
2483  int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000,
2484  s->streams[stream_index]->time_base.den,
2487  if ((flags & AVSEEK_FLAG_BYTE) || c->is_live)
2488  return AVERROR(ENOSYS);
2489 
2490  /* Seek in discarded streams with dry_run=1 to avoid reopening them */
2491  for (i = 0; i < c->n_videos; i++) {
2492  if (!ret)
2493  ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx);
2494  }
2495  for (i = 0; i < c->n_audios; i++) {
2496  if (!ret)
2497  ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
2498  }
2499  for (i = 0; i < c->n_subtitles; i++) {
2500  if (!ret)
2501  ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
2502  }
2503 
2504  return ret;
2505 }
2506 
2507 static int dash_probe(const AVProbeData *p)
2508 {
2509  if (!av_stristr(p->buf, "<MPD"))
2510  return 0;
2511 
2512  if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") ||
2513  av_stristr(p->buf, "dash:profile:isoff-live:2011") ||
2514  av_stristr(p->buf, "dash:profile:isoff-live:2012") ||
2515  av_stristr(p->buf, "dash:profile:isoff-main:2011") ||
2516  av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) {
2517  return AVPROBE_SCORE_MAX;
2518  }
2519  if (av_stristr(p->buf, "dash:profile")) {
2520  return AVPROBE_SCORE_MAX;
2521  }
2522 
2523  return 0;
2524 }
2525 
2526 #define OFFSET(x) offsetof(DASHContext, x)
2527 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
2528 static const AVOption dash_options[] = {
2529  {"allowed_extensions", "List of file extensions that dash is allowed to access",
2530  OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
2531  {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"},
2532  INT_MIN, INT_MAX, FLAGS},
2533  { "cenc_decryption_key", "Media default decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
2534  { "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 },
2535  { "max_reload", "Maximum number of manifest reloads in get_current_fragment() before giving up",
2536  OFFSET(max_reload), AV_OPT_TYPE_INT, { .i64 = 100 }, 0, INT_MAX, FLAGS },
2537  {NULL}
2538 };
2539 
2540 static const AVClass dash_class = {
2541  .class_name = "dash",
2542  .item_name = av_default_item_name,
2543  .option = dash_options,
2544  .version = LIBAVUTIL_VERSION_INT,
2545 };
2546 
2548  .p.name = "dash",
2549  .p.long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"),
2550  .p.priv_class = &dash_class,
2551  .p.flags = AVFMT_NO_BYTE_SEEK,
2552  .priv_data_size = sizeof(DASHContext),
2553  .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
2559 };
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:1935
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:1926
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:2012
read_data
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition: dashdec.c:1845
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:2527
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:1651
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:2404
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:1741
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:829
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:2313
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:2528
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:1835
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:2131
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
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:2089
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:874
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:2479
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:2547
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:951
AVMEDIA_TYPE_UNKNOWN
@ AVMEDIA_TYPE_UNKNOWN
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:199
OFFSET
#define OFFSET(x)
Definition: dashdec.c:2526
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:2116
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:2139
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
read_header
static int read_header(FFV1Context *f, RangeCoder *c)
Definition: ffv1dec.c:574
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
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:2507
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
s
uint8_t s
Definition: llvidencdsp.c:39
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:1916
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:578
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:313
AVStreamGroup
Definition: avformat.h:1140
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:753
AVStreamGroup::params
union AVStreamGroup::@459 params
Group type-specific parameters.
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:1552
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:1789
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:2341
open_input
static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
Definition: dashdec.c:1757
timeline
Definition: dashdec.c:49
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:40
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:555
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:2415
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:2540
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