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