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