FFmpeg
dashdec.c
Go to the documentation of this file.
1 /*
2  * Dynamic Adaptive Streaming over HTTP demux
3  * Copyright (c) 2017 samsamsam@o2.pl based on HLS demux
4  * Copyright (c) 2017 Steven Liu
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 #include <libxml/parser.h>
23 #include <time.h>
24 #include "libavutil/bprint.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/opt.h"
27 #include "libavutil/time.h"
28 #include "libavutil/parseutils.h"
29 #include "internal.h"
30 #include "avio_internal.h"
31 #include "dash.h"
32 #include "demux.h"
33 #include "url.h"
34 
35 #define INITIAL_BUFFER_SIZE 32768
36 
37 struct fragment {
40  char *url;
41 };
42 
43 /*
44  * reference to : ISO_IEC_23009-1-DASH-2012
45  * Section: 5.3.9.6.2
46  * Table: Table 17 — Semantics of SegmentTimeline element
47  * */
48 struct timeline {
49  /* starttime: Element or Attribute Name
50  * specifies the MPD start time, in @timescale units,
51  * the first Segment in the series starts relative to the beginning of the Period.
52  * The value of this attribute must be equal to or greater than the sum of the previous S
53  * element earliest presentation time and the sum of the contiguous Segment durations.
54  * If the value of the attribute is greater than what is expressed by the previous S element,
55  * it expresses discontinuities in the timeline.
56  * If not present then the value shall be assumed to be zero for the first S element
57  * and for the subsequent S elements, the value shall be assumed to be the sum of
58  * the previous S element's earliest presentation time and contiguous duration
59  * (i.e. previous S@starttime + @duration * (@repeat + 1)).
60  * */
62  /* repeat: Element or Attribute Name
63  * specifies the repeat count of the number of following contiguous Segments with
64  * the same duration expressed by the value of @duration. This value is zero-based
65  * (e.g. a value of three means four Segments in the contiguous series).
66  * */
68  /* duration: Element or Attribute Name
69  * specifies the Segment duration, in units of the value of the @timescale.
70  * */
72 };
73 
74 /*
75  * Each playlist has its own demuxer. If it is currently active,
76  * it has an opened AVIOContext too, and potentially an AVPacket
77  * containing the next packet from this stream.
78  */
80  char *url_template;
86 
87  char *id;
88  char *lang;
89  int bandwidth;
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  xmlChar *escaped = xmlEncodeSpecialChars(NULL, root_url);
784  if (!escaped) {
785  updated = AVERROR(ENOMEM);
786  goto end;
787  }
788  xmlNodeSetContent(node, escaped);
789  xmlFree(escaped);
790  updated = 1;
791  }
792 
793  size = strlen(root_url);
794  isRootHttp = ishttp(root_url);
795 
796  if (size > 0 && root_url[size - 1] != token) {
797  av_strlcat(root_url, "/", size + 2);
798  size += 2;
799  }
800 
801  for (i = 0; i < n_baseurl_nodes; ++i) {
802  if (i == rootId) {
803  continue;
804  }
805  text = xmlNodeGetContent(baseurl_nodes[i]);
806  if (text && !av_strstart(text, "/", NULL)) {
807  memset(tmp_str, 0, strlen(tmp_str));
808  if (!ishttp(text) && isRootHttp) {
809  av_strlcpy(tmp_str, root_url, size + 1);
810  }
811  start = (text[0] == token);
812  if (start && av_stristr(tmp_str, text)) {
813  char *p = tmp_str;
814  if (!av_strncasecmp(tmp_str, "http://", 7)) {
815  p += 7;
816  } else if (!av_strncasecmp(tmp_str, "https://", 8)) {
817  p += 8;
818  }
819  p = strchr(p, '/');
820  memset(p + 1, 0, strlen(p));
821  }
822  av_strlcat(tmp_str, text + start, tmp_max_url_size);
823  xmlFree(text);
824  xmlChar* escaped = xmlEncodeSpecialChars(NULL, tmp_str);
825  if (!escaped) {
826  updated = AVERROR(ENOMEM);
827  goto end;
828  }
829  xmlNodeSetContent(baseurl_nodes[i], escaped);
830  updated = 1;
831  xmlFree(escaped);
832  }
833  }
834 
835 end:
836  if (tmp_max_url_size > *max_url_size) {
837  *max_url_size = tmp_max_url_size;
838  }
839  av_free(path);
840  av_free(tmp_str);
841  xmlFree(baseurl);
842  return updated;
843 
844 }
845 
846 #define SET_REPRESENTATION_SEQUENCE_BASE_INFO(arg, cnt) { \
847  val = get_val_from_nodes_tab((arg), (cnt), "duration"); \
848  if (val) { \
849  int64_t fragment_duration = (int64_t) strtoll(val, NULL, 10); \
850  if (fragment_duration < 0) { \
851  av_log(s, AV_LOG_WARNING, "duration invalid, autochanged to 0.\n"); \
852  fragment_duration = 0; \
853  } \
854  rep->fragment_duration = fragment_duration; \
855  av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); \
856  xmlFree(val); \
857  } \
858  val = get_val_from_nodes_tab((arg), (cnt), "timescale"); \
859  if (val) { \
860  int64_t fragment_timescale = (int64_t) strtoll(val, NULL, 10); \
861  if (fragment_timescale < 0) { \
862  av_log(s, AV_LOG_WARNING, "timescale invalid, autochanged to 0.\n"); \
863  fragment_timescale = 0; \
864  } \
865  rep->fragment_timescale = fragment_timescale; \
866  av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); \
867  xmlFree(val); \
868  } \
869  val = get_val_from_nodes_tab((arg), (cnt), "startNumber"); \
870  if (val) { \
871  int64_t start_number = (int64_t) strtoll(val, NULL, 10); \
872  if (start_number < 0) { \
873  av_log(s, AV_LOG_WARNING, "startNumber invalid, autochanged to 0.\n"); \
874  start_number = 0; \
875  } \
876  rep->start_number = rep->first_seq_no = start_number; \
877  av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); \
878  xmlFree(val); \
879  } \
880  }
881 
882 
883 static int parse_manifest_representation(AVFormatContext *s, const char *url,
884  xmlNodePtr node,
885  xmlNodePtr adaptionset_node,
886  xmlNodePtr mpd_baseurl_node,
887  xmlNodePtr period_baseurl_node,
888  xmlNodePtr period_segmenttemplate_node,
889  xmlNodePtr period_segmentlist_node,
890  xmlNodePtr fragment_template_node,
891  xmlNodePtr content_component_node,
892  xmlNodePtr adaptionset_baseurl_node,
893  xmlNodePtr adaptionset_segmentlist_node,
894  xmlNodePtr adaptionset_supplementalproperty_node)
895 {
896  int32_t ret = 0;
897  DASHContext *c = s->priv_data;
898  struct representation *rep = NULL;
899  struct fragment *seg = NULL;
900  xmlNodePtr representation_segmenttemplate_node = NULL;
901  xmlNodePtr representation_baseurl_node = NULL;
902  xmlNodePtr representation_segmentlist_node = NULL;
903  xmlNodePtr segmentlists_tab[3];
904  xmlNodePtr fragment_timeline_node = NULL;
905  xmlNodePtr fragment_templates_tab[5];
906  char *val = NULL;
907  xmlNodePtr baseurl_nodes[4];
908  xmlNodePtr representation_node = node;
909  char *rep_bandwidth_val;
911 
912  // try get information from representation
913  if (type == AVMEDIA_TYPE_UNKNOWN)
914  type = get_content_type(representation_node);
915  // try get information from contentComponen
916  if (type == AVMEDIA_TYPE_UNKNOWN)
917  type = get_content_type(content_component_node);
918  // try get information from adaption set
919  if (type == AVMEDIA_TYPE_UNKNOWN)
920  type = get_content_type(adaptionset_node);
923  av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skip not supported representation type\n", url);
924  return 0;
925  }
926 
927  // convert selected representation to our internal struct
928  rep = av_mallocz(sizeof(struct representation));
929  if (!rep)
930  return AVERROR(ENOMEM);
931  if (c->adaptionset_lang) {
932  rep->lang = av_strdup(c->adaptionset_lang);
933  if (!rep->lang) {
934  av_log(s, AV_LOG_ERROR, "alloc language memory failure\n");
935  av_freep(&rep);
936  return AVERROR(ENOMEM);
937  }
938  }
939  rep->parent = s;
940  representation_segmenttemplate_node = find_child_node_by_name(representation_node, "SegmentTemplate");
941  representation_baseurl_node = find_child_node_by_name(representation_node, "BaseURL");
942  representation_segmentlist_node = find_child_node_by_name(representation_node, "SegmentList");
943  rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth");
944  val = xmlGetProp(representation_node, "id");
945  if (val) {
946  rep->id = av_strdup(val);
947  xmlFree(val);
948  if (!rep->id)
949  goto enomem;
950  }
951 
952  baseurl_nodes[0] = mpd_baseurl_node;
953  baseurl_nodes[1] = period_baseurl_node;
954  baseurl_nodes[2] = adaptionset_baseurl_node;
955  baseurl_nodes[3] = representation_baseurl_node;
956 
957  ret = resolve_content_path(s, url, &c->max_url_size, baseurl_nodes, 4);
958  c->max_url_size = aligned(c->max_url_size
959  + (rep->id ? strlen(rep->id) : 0)
960  + (rep_bandwidth_val ? strlen(rep_bandwidth_val) : 0));
961  if (ret == AVERROR(ENOMEM) || ret == 0)
962  goto free;
963  if (representation_segmenttemplate_node || fragment_template_node || period_segmenttemplate_node) {
964  fragment_timeline_node = NULL;
965  fragment_templates_tab[0] = representation_segmenttemplate_node;
966  fragment_templates_tab[1] = adaptionset_segmentlist_node;
967  fragment_templates_tab[2] = fragment_template_node;
968  fragment_templates_tab[3] = period_segmenttemplate_node;
969  fragment_templates_tab[4] = period_segmentlist_node;
970 
971  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "initialization");
972  if (val) {
973  rep->init_section = av_mallocz(sizeof(struct fragment));
974  if (!rep->init_section) {
975  xmlFree(val);
976  goto enomem;
977  }
978  c->max_url_size = aligned(c->max_url_size + strlen(val));
979  rep->init_section->url = get_content_url(baseurl_nodes, 4,
980  c->max_url_size, rep->id,
981  rep_bandwidth_val, val);
982  xmlFree(val);
983  if (!rep->init_section->url)
984  goto enomem;
985  rep->init_section->size = -1;
986  }
987  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "media");
988  if (val) {
989  c->max_url_size = aligned(c->max_url_size + strlen(val));
990  rep->url_template = get_content_url(baseurl_nodes, 4,
991  c->max_url_size, rep->id,
992  rep_bandwidth_val, val);
993  xmlFree(val);
994  }
995  val = get_val_from_nodes_tab(fragment_templates_tab, 4, "presentationTimeOffset");
996  if (val) {
997  int64_t presentation_timeoffset = (int64_t) strtoll(val, NULL, 10);
998  if (presentation_timeoffset < 0) {
999  av_log(s, AV_LOG_WARNING, "presentationTimeOffset invalid, autochanged to 0.\n");
1000  presentation_timeoffset = 0;
1001  }
1002  rep->presentation_timeoffset = presentation_timeoffset;
1003  av_log(s, AV_LOG_TRACE, "rep->presentation_timeoffset = [%"PRId64"]\n", rep->presentation_timeoffset);
1004  xmlFree(val);
1005  }
1006 
1007  SET_REPRESENTATION_SEQUENCE_BASE_INFO(fragment_templates_tab, 4);
1008  if (adaptionset_supplementalproperty_node) {
1009  char *scheme_id_uri = xmlGetProp(adaptionset_supplementalproperty_node, "schemeIdUri");
1010  if (scheme_id_uri) {
1011  int is_last_segment_number = !av_strcasecmp(scheme_id_uri, "http://dashif.org/guidelines/last-segment-number");
1012  xmlFree(scheme_id_uri);
1013  if (is_last_segment_number) {
1014  val = xmlGetProp(adaptionset_supplementalproperty_node, "value");
1015  if (!val) {
1016  av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n");
1017  } else {
1018  rep->last_seq_no = (int64_t)strtoll(val, NULL, 10) - 1;
1019  xmlFree(val);
1020  }
1021  }
1022  }
1023  }
1024 
1025  fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline");
1026 
1027  if (!fragment_timeline_node)
1028  fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline");
1029  if (!fragment_timeline_node)
1030  fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline");
1031  if (!fragment_timeline_node)
1032  fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline");
1033  if (fragment_timeline_node) {
1034  fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node);
1035  while (fragment_timeline_node) {
1036  ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node);
1037  if (ret < 0)
1038  goto free;
1039  fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node);
1040  }
1041  }
1042  } else if (representation_baseurl_node && !representation_segmentlist_node) {
1043  seg = av_mallocz(sizeof(struct fragment));
1044  if (!seg)
1045  goto enomem;
1046  ret = av_dynarray_add_nofree(&rep->fragments, &rep->n_fragments, seg);
1047  if (ret < 0) {
1048  av_free(seg);
1049  goto free;
1050  }
1051  seg->url = get_content_url(baseurl_nodes, 4, c->max_url_size,
1052  rep->id, rep_bandwidth_val, NULL);
1053  if (!seg->url)
1054  goto enomem;
1055  seg->size = -1;
1056  } else if (representation_segmentlist_node) {
1057  // TODO: https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html
1058  // http://www-itec.uni-klu.ac.at/dash/ddash/mpdGenerator.php?fragmentlength=15&type=full
1059  xmlNodePtr fragmenturl_node = NULL;
1060  segmentlists_tab[0] = representation_segmentlist_node;
1061  segmentlists_tab[1] = adaptionset_segmentlist_node;
1062  segmentlists_tab[2] = period_segmentlist_node;
1063 
1064  SET_REPRESENTATION_SEQUENCE_BASE_INFO(segmentlists_tab, 3)
1065  fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node);
1066  while (fragmenturl_node) {
1067  ret = parse_manifest_segmenturlnode(s, rep, fragmenturl_node,
1068  baseurl_nodes, rep->id,
1069  rep_bandwidth_val);
1070  if (ret < 0)
1071  goto free;
1072  fragmenturl_node = xmlNextElementSibling(fragmenturl_node);
1073  }
1074 
1075  fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline");
1076  if (!fragment_timeline_node)
1077  fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline");
1078  if (fragment_timeline_node) {
1079  fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node);
1080  while (fragment_timeline_node) {
1081  ret = parse_manifest_segmenttimeline(s, rep, fragment_timeline_node);
1082  if (ret < 0)
1083  goto free;
1084  fragment_timeline_node = xmlNextElementSibling(fragment_timeline_node);
1085  }
1086  }
1087  } else {
1088  av_log(s, AV_LOG_ERROR, "Unknown format of Representation node id '%s' \n",
1089  rep->id ? rep->id : "");
1090  goto free;
1091  }
1092 
1093  if (rep->fragment_duration > 0 && !rep->fragment_timescale)
1094  rep->fragment_timescale = 1;
1095  rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0;
1096  rep->framerate = av_make_q(0, 0);
1097  if (type == AVMEDIA_TYPE_VIDEO) {
1098  char *rep_framerate_val = xmlGetProp(representation_node, "frameRate");
1099  if (rep_framerate_val) {
1100  ret = av_parse_video_rate(&rep->framerate, rep_framerate_val);
1101  if (ret < 0)
1102  av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val);
1103  xmlFree(rep_framerate_val);
1104  }
1105  }
1106 
1107  switch (type) {
1108  case AVMEDIA_TYPE_VIDEO:
1109  ret = av_dynarray_add_nofree(&c->videos, &c->n_videos, rep);
1110  break;
1111  case AVMEDIA_TYPE_AUDIO:
1112  ret = av_dynarray_add_nofree(&c->audios, &c->n_audios, rep);
1113  break;
1114  case AVMEDIA_TYPE_SUBTITLE:
1115  ret = av_dynarray_add_nofree(&c->subtitles, &c->n_subtitles, rep);
1116  break;
1117  }
1118  if (ret < 0)
1119  goto free;
1120 
1121 end:
1122  if (rep_bandwidth_val)
1123  xmlFree(rep_bandwidth_val);
1124 
1125  return ret;
1126 enomem:
1127  ret = AVERROR(ENOMEM);
1128 free:
1129  free_representation(rep);
1130  goto end;
1131 }
1132 
1133 static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node)
1134 {
1135  DASHContext *c = s->priv_data;
1136 
1137  if (!adaptionset_node) {
1138  av_log(s, AV_LOG_WARNING, "Cannot get AdaptionSet\n");
1139  return AVERROR(EINVAL);
1140  }
1141  c->adaptionset_lang = xmlGetProp(adaptionset_node, "lang");
1142 
1143  return 0;
1144 }
1145 
1147  xmlNodePtr adaptionset_node,
1148  xmlNodePtr mpd_baseurl_node,
1149  xmlNodePtr period_baseurl_node,
1150  xmlNodePtr period_segmenttemplate_node,
1151  xmlNodePtr period_segmentlist_node)
1152 {
1153  int ret = 0;
1154  DASHContext *c = s->priv_data;
1155  xmlNodePtr fragment_template_node = NULL;
1156  xmlNodePtr content_component_node = NULL;
1157  xmlNodePtr adaptionset_baseurl_node = NULL;
1158  xmlNodePtr adaptionset_segmentlist_node = NULL;
1159  xmlNodePtr adaptionset_supplementalproperty_node = NULL;
1160  xmlNodePtr node = NULL;
1161 
1162  ret = parse_manifest_adaptationset_attr(s, adaptionset_node);
1163  if (ret < 0)
1164  return ret;
1165 
1166  node = xmlFirstElementChild(adaptionset_node);
1167  while (node) {
1168  if (!av_strcasecmp(node->name, "SegmentTemplate")) {
1169  fragment_template_node = node;
1170  } else if (!av_strcasecmp(node->name, "ContentComponent")) {
1171  content_component_node = node;
1172  } else if (!av_strcasecmp(node->name, "BaseURL")) {
1173  adaptionset_baseurl_node = node;
1174  } else if (!av_strcasecmp(node->name, "SegmentList")) {
1175  adaptionset_segmentlist_node = node;
1176  } else if (!av_strcasecmp(node->name, "SupplementalProperty")) {
1177  adaptionset_supplementalproperty_node = node;
1178  } else if (!av_strcasecmp(node->name, "Representation")) {
1180  adaptionset_node,
1181  mpd_baseurl_node,
1182  period_baseurl_node,
1183  period_segmenttemplate_node,
1184  period_segmentlist_node,
1185  fragment_template_node,
1186  content_component_node,
1187  adaptionset_baseurl_node,
1188  adaptionset_segmentlist_node,
1189  adaptionset_supplementalproperty_node);
1190  if (ret < 0)
1191  goto err;
1192  }
1193  node = xmlNextElementSibling(node);
1194  }
1195 
1196 err:
1197  xmlFree(c->adaptionset_lang);
1198  c->adaptionset_lang = NULL;
1199  return ret;
1200 }
1201 
1202 static int parse_programinformation(AVFormatContext *s, xmlNodePtr node)
1203 {
1204  xmlChar *val = NULL;
1205 
1206  node = xmlFirstElementChild(node);
1207  while (node) {
1208  if (!av_strcasecmp(node->name, "Title")) {
1209  val = xmlNodeGetContent(node);
1210  if (val) {
1211  av_dict_set(&s->metadata, "Title", val, 0);
1212  }
1213  } else if (!av_strcasecmp(node->name, "Source")) {
1214  val = xmlNodeGetContent(node);
1215  if (val) {
1216  av_dict_set(&s->metadata, "Source", val, 0);
1217  }
1218  } else if (!av_strcasecmp(node->name, "Copyright")) {
1219  val = xmlNodeGetContent(node);
1220  if (val) {
1221  av_dict_set(&s->metadata, "Copyright", val, 0);
1222  }
1223  }
1224  node = xmlNextElementSibling(node);
1225  xmlFree(val);
1226  val = NULL;
1227  }
1228  return 0;
1229 }
1230 
1231 static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
1232 {
1233  DASHContext *c = s->priv_data;
1234  int ret = 0;
1235  int close_in = 0;
1236  AVBPrint buf;
1237  AVDictionary *opts = NULL;
1238  xmlDoc *doc = NULL;
1239  xmlNodePtr root_element = NULL;
1240  xmlNodePtr node = NULL;
1241  xmlNodePtr period_node = NULL;
1242  xmlNodePtr tmp_node = NULL;
1243  xmlNodePtr mpd_baseurl_node = NULL;
1244  xmlNodePtr period_baseurl_node = NULL;
1245  xmlNodePtr period_segmenttemplate_node = NULL;
1246  xmlNodePtr period_segmentlist_node = NULL;
1247  xmlNodePtr adaptionset_node = NULL;
1248  xmlAttrPtr attr = NULL;
1249  char *val = NULL;
1250  uint32_t period_duration_sec = 0;
1251  uint32_t period_start_sec = 0;
1252 
1253  if (!in) {
1254  close_in = 1;
1255 
1256  av_dict_copy(&opts, c->avio_opts, 0);
1257  ret = ffio_open_whitelist(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist);
1258  av_dict_free(&opts);
1259  if (ret < 0)
1260  return ret;
1261  }
1262 
1263  if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&c->base_url) < 0)
1264  c->base_url = av_strdup(url);
1265 
1266  av_bprint_init(&buf, 0, INT_MAX); // xmlReadMemory uses integer bufsize
1267 
1268  if ((ret = avio_read_to_bprint(in, &buf, SIZE_MAX)) < 0 ||
1269  !avio_feof(in)) {
1270  av_log(s, AV_LOG_ERROR, "Unable to read to manifest '%s'\n", url);
1271  if (ret == 0)
1273  } else {
1274  LIBXML_TEST_VERSION
1275 
1276  doc = xmlReadMemory(buf.str, buf.len, c->base_url, NULL, 0);
1277  root_element = xmlDocGetRootElement(doc);
1278  node = root_element;
1279 
1280  if (!node) {
1282  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing root node\n", url);
1283  goto cleanup;
1284  }
1285 
1286  if (node->type != XML_ELEMENT_NODE ||
1287  av_strcasecmp(node->name, "MPD")) {
1289  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - wrong root node name[%s] type[%d]\n", url, node->name, (int)node->type);
1290  goto cleanup;
1291  }
1292 
1293  val = xmlGetProp(node, "type");
1294  if (!val) {
1295  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing type attrib\n", url);
1297  goto cleanup;
1298  }
1299  if (!av_strcasecmp(val, "dynamic"))
1300  c->is_live = 1;
1301  xmlFree(val);
1302 
1303  attr = node->properties;
1304  while (attr) {
1305  val = xmlGetProp(node, attr->name);
1306 
1307  if (!av_strcasecmp(attr->name, "availabilityStartTime")) {
1308  c->availability_start_time = get_utc_date_time_insec(s, val);
1309  av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time);
1310  } else if (!av_strcasecmp(attr->name, "availabilityEndTime")) {
1311  c->availability_end_time = get_utc_date_time_insec(s, val);
1312  av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time);
1313  } else if (!av_strcasecmp(attr->name, "publishTime")) {
1314  c->publish_time = get_utc_date_time_insec(s, val);
1315  av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time);
1316  } else if (!av_strcasecmp(attr->name, "minimumUpdatePeriod")) {
1317  c->minimum_update_period = get_duration_insec(s, val);
1318  av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period);
1319  } else if (!av_strcasecmp(attr->name, "timeShiftBufferDepth")) {
1320  c->time_shift_buffer_depth = get_duration_insec(s, val);
1321  av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth);
1322  } else if (!av_strcasecmp(attr->name, "minBufferTime")) {
1323  c->min_buffer_time = get_duration_insec(s, val);
1324  av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time);
1325  } else if (!av_strcasecmp(attr->name, "suggestedPresentationDelay")) {
1326  c->suggested_presentation_delay = get_duration_insec(s, val);
1327  av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay);
1328  } else if (!av_strcasecmp(attr->name, "mediaPresentationDuration")) {
1329  c->media_presentation_duration = get_duration_insec(s, val);
1330  av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration);
1331  }
1332  attr = attr->next;
1333  xmlFree(val);
1334  }
1335 
1336  tmp_node = find_child_node_by_name(node, "BaseURL");
1337  if (tmp_node) {
1338  mpd_baseurl_node = xmlCopyNode(tmp_node,1);
1339  } else {
1340  mpd_baseurl_node = xmlNewNode(NULL, "BaseURL");
1341  }
1342 
1343  // at now we can handle only one period, with the longest duration
1344  node = xmlFirstElementChild(node);
1345  while (node) {
1346  if (!av_strcasecmp(node->name, "Period")) {
1347  period_duration_sec = 0;
1348  period_start_sec = 0;
1349  attr = node->properties;
1350  while (attr) {
1351  val = xmlGetProp(node, attr->name);
1352  if (!av_strcasecmp(attr->name, "duration")) {
1353  period_duration_sec = get_duration_insec(s, val);
1354  } else if (!av_strcasecmp(attr->name, "start")) {
1355  period_start_sec = get_duration_insec(s, val);
1356  }
1357  attr = attr->next;
1358  xmlFree(val);
1359  }
1360  if ((period_duration_sec) >= (c->period_duration)) {
1361  period_node = node;
1362  c->period_duration = period_duration_sec;
1363  c->period_start = period_start_sec;
1364  if (c->period_start > 0)
1365  c->media_presentation_duration = c->period_duration;
1366  }
1367  } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
1368  parse_programinformation(s, node);
1369  }
1370  node = xmlNextElementSibling(node);
1371  }
1372  if (!period_node) {
1373  av_log(s, AV_LOG_ERROR, "Unable to parse '%s' - missing Period node\n", url);
1375  goto cleanup;
1376  }
1377 
1378  adaptionset_node = xmlFirstElementChild(period_node);
1379  while (adaptionset_node) {
1380  if (!av_strcasecmp(adaptionset_node->name, "BaseURL")) {
1381  period_baseurl_node = adaptionset_node;
1382  } else if (!av_strcasecmp(adaptionset_node->name, "SegmentTemplate")) {
1383  period_segmenttemplate_node = adaptionset_node;
1384  } else if (!av_strcasecmp(adaptionset_node->name, "SegmentList")) {
1385  period_segmentlist_node = adaptionset_node;
1386  } else if (!av_strcasecmp(adaptionset_node->name, "AdaptationSet")) {
1387  parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node, period_segmenttemplate_node, period_segmentlist_node);
1388  }
1389  adaptionset_node = xmlNextElementSibling(adaptionset_node);
1390  }
1391 cleanup:
1392  /*free the document */
1393  xmlFreeDoc(doc);
1394  xmlCleanupParser();
1395  xmlFreeNode(mpd_baseurl_node);
1396  }
1397 
1398  av_bprint_finalize(&buf, NULL);
1399  if (close_in) {
1400  avio_close(in);
1401  }
1402  return ret;
1403 }
1404 
1406 {
1407  DASHContext *c = s->priv_data;
1408  int64_t num = 0;
1409  int64_t start_time_offset = 0;
1410 
1411  if (c->is_live) {
1412  if (pls->n_fragments) {
1413  av_log(s, AV_LOG_TRACE, "in n_fragments mode\n");
1414  num = pls->first_seq_no;
1415  } else if (pls->n_timelines) {
1416  av_log(s, AV_LOG_TRACE, "in n_timelines mode\n");
1417  start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - 60 * pls->fragment_timescale; // 60 seconds before end
1418  num = calc_next_seg_no_from_timelines(pls, start_time_offset);
1419  if (num == -1)
1420  num = pls->first_seq_no;
1421  else
1422  num += pls->first_seq_no;
1423  } else if (pls->fragment_duration){
1424  av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset);
1425  if (pls->presentation_timeoffset) {
1426  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;
1427  } else if (c->publish_time > 0 && !c->availability_start_time) {
1428  if (c->min_buffer_time) {
1429  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;
1430  } else {
1431  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;
1432  }
1433  } else {
1434  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
1435  }
1436  }
1437  } else {
1438  num = pls->first_seq_no;
1439  }
1440  return num;
1441 }
1442 
1444 {
1445  DASHContext *c = s->priv_data;
1446  int64_t num = 0;
1447 
1448  if (c->is_live && pls->fragment_duration) {
1449  av_log(s, AV_LOG_TRACE, "in live mode\n");
1450  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;
1451  } else {
1452  num = pls->first_seq_no;
1453  }
1454  return num;
1455 }
1456 
1458 {
1459  int64_t num = 0;
1460 
1461  if (pls->n_fragments) {
1462  num = pls->first_seq_no + pls->n_fragments - 1;
1463  } else if (pls->n_timelines) {
1464  int i = 0;
1465  num = pls->first_seq_no + pls->n_timelines - 1;
1466  for (i = 0; i < pls->n_timelines; i++) {
1467  if (pls->timelines[i]->repeat == -1) {
1468  int length_of_each_segment = pls->timelines[i]->duration / pls->fragment_timescale;
1469  num = c->period_duration / length_of_each_segment;
1470  } else {
1471  num += pls->timelines[i]->repeat;
1472  }
1473  }
1474  } else if (c->is_live && pls->fragment_duration) {
1475  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale) / pls->fragment_duration;
1476  } else if (pls->fragment_duration) {
1477  num = pls->first_seq_no + av_rescale_rnd(1, c->media_presentation_duration * pls->fragment_timescale, pls->fragment_duration, AV_ROUND_UP);
1478  }
1479 
1480  return num;
1481 }
1482 
1483 static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
1484 {
1485  if (rep_dest && rep_src ) {
1486  free_timelines_list(rep_dest);
1487  rep_dest->timelines = rep_src->timelines;
1488  rep_dest->n_timelines = rep_src->n_timelines;
1489  rep_dest->first_seq_no = rep_src->first_seq_no;
1490  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1491  rep_src->timelines = NULL;
1492  rep_src->n_timelines = 0;
1493  rep_dest->cur_seq_no = rep_src->cur_seq_no;
1494  }
1495 }
1496 
1497 static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
1498 {
1499  if (rep_dest && rep_src ) {
1500  free_fragment_list(rep_dest);
1501  if (rep_src->start_number > (rep_dest->start_number + rep_dest->n_fragments))
1502  rep_dest->cur_seq_no = 0;
1503  else
1504  rep_dest->cur_seq_no += rep_src->start_number - rep_dest->start_number;
1505  rep_dest->fragments = rep_src->fragments;
1506  rep_dest->n_fragments = rep_src->n_fragments;
1507  rep_dest->parent = rep_src->parent;
1508  rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c);
1509  rep_src->fragments = NULL;
1510  rep_src->n_fragments = 0;
1511  }
1512 }
1513 
1514 
1516 {
1517  int ret = 0, i;
1518  DASHContext *c = s->priv_data;
1519  // save current context
1520  int n_videos = c->n_videos;
1521  struct representation **videos = c->videos;
1522  int n_audios = c->n_audios;
1523  struct representation **audios = c->audios;
1524  int n_subtitles = c->n_subtitles;
1525  struct representation **subtitles = c->subtitles;
1526  char *base_url = c->base_url;
1527 
1528  c->base_url = NULL;
1529  c->n_videos = 0;
1530  c->videos = NULL;
1531  c->n_audios = 0;
1532  c->audios = NULL;
1533  c->n_subtitles = 0;
1534  c->subtitles = NULL;
1535  ret = parse_manifest(s, s->url, NULL);
1536  if (ret)
1537  goto finish;
1538 
1539  if (c->n_videos != n_videos) {
1541  "new manifest has mismatched no. of video representations, %d -> %d\n",
1542  n_videos, c->n_videos);
1543  return AVERROR_INVALIDDATA;
1544  }
1545  if (c->n_audios != n_audios) {
1547  "new manifest has mismatched no. of audio representations, %d -> %d\n",
1548  n_audios, c->n_audios);
1549  return AVERROR_INVALIDDATA;
1550  }
1551  if (c->n_subtitles != n_subtitles) {
1553  "new manifest has mismatched no. of subtitles representations, %d -> %d\n",
1554  n_subtitles, c->n_subtitles);
1555  return AVERROR_INVALIDDATA;
1556  }
1557 
1558  for (i = 0; i < n_videos; i++) {
1559  struct representation *cur_video = videos[i];
1560  struct representation *ccur_video = c->videos[i];
1561  if (cur_video->timelines) {
1562  // calc current time
1563  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale;
1564  // update segments
1565  ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1);
1566  if (ccur_video->cur_seq_no >= 0) {
1567  move_timelines(ccur_video, cur_video, c);
1568  }
1569  }
1570  if (cur_video->fragments) {
1571  move_segments(ccur_video, cur_video, c);
1572  }
1573  }
1574  for (i = 0; i < n_audios; i++) {
1575  struct representation *cur_audio = audios[i];
1576  struct representation *ccur_audio = c->audios[i];
1577  if (cur_audio->timelines) {
1578  // calc current time
1579  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale;
1580  // update segments
1581  ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1);
1582  if (ccur_audio->cur_seq_no >= 0) {
1583  move_timelines(ccur_audio, cur_audio, c);
1584  }
1585  }
1586  if (cur_audio->fragments) {
1587  move_segments(ccur_audio, cur_audio, c);
1588  }
1589  }
1590 
1591 finish:
1592  // restore context
1593  if (c->base_url)
1594  av_free(base_url);
1595  else
1596  c->base_url = base_url;
1597 
1598  if (c->subtitles)
1600  if (c->audios)
1601  free_audio_list(c);
1602  if (c->videos)
1603  free_video_list(c);
1604 
1605  c->n_subtitles = n_subtitles;
1606  c->subtitles = subtitles;
1607  c->n_audios = n_audios;
1608  c->audios = audios;
1609  c->n_videos = n_videos;
1610  c->videos = videos;
1611  return ret;
1612 }
1613 
1614 static struct fragment *get_current_fragment(struct representation *pls)
1615 {
1616  int64_t min_seq_no = 0;
1617  int64_t max_seq_no = 0;
1618  struct fragment *seg = NULL;
1619  struct fragment *seg_ptr = NULL;
1620  DASHContext *c = pls->parent->priv_data;
1621 
1622  while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) {
1623  if (pls->cur_seq_no < pls->n_fragments) {
1624  seg_ptr = pls->fragments[pls->cur_seq_no];
1625  seg = av_mallocz(sizeof(struct fragment));
1626  if (!seg) {
1627  return NULL;
1628  }
1629  seg->url = av_strdup(seg_ptr->url);
1630  if (!seg->url) {
1631  av_free(seg);
1632  return NULL;
1633  }
1634  seg->size = seg_ptr->size;
1635  seg->url_offset = seg_ptr->url_offset;
1636  return seg;
1637  } else if (c->is_live) {
1638  refresh_manifest(pls->parent);
1639  } else {
1640  break;
1641  }
1642  }
1643  if (c->is_live) {
1644  min_seq_no = calc_min_seg_no(pls->parent, pls);
1645  max_seq_no = calc_max_seg_no(pls, c);
1646 
1647  if (pls->timelines || pls->fragments) {
1648  refresh_manifest(pls->parent);
1649  }
1650  if (pls->cur_seq_no <= min_seq_no) {
1651  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);
1652  pls->cur_seq_no = calc_cur_seg_no(pls->parent, pls);
1653  } else if (pls->cur_seq_no > max_seq_no) {
1654  av_log(pls->parent, AV_LOG_VERBOSE, "new fragment: min[%"PRId64"] max[%"PRId64"]\n", min_seq_no, max_seq_no);
1655  }
1656  seg = av_mallocz(sizeof(struct fragment));
1657  if (!seg) {
1658  return NULL;
1659  }
1660  } else if (pls->cur_seq_no <= pls->last_seq_no) {
1661  seg = av_mallocz(sizeof(struct fragment));
1662  if (!seg) {
1663  return NULL;
1664  }
1665  }
1666  if (seg) {
1667  char *tmpfilename;
1668  if (!pls->url_template) {
1669  av_log(pls->parent, AV_LOG_ERROR, "Cannot get fragment, missing template URL\n");
1670  av_free(seg);
1671  return NULL;
1672  }
1673  tmpfilename = av_mallocz(c->max_url_size);
1674  if (!tmpfilename) {
1675  av_free(seg);
1676  return NULL;
1677  }
1678  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));
1679  seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename);
1680  if (!seg->url) {
1681  av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template);
1682  seg->url = av_strdup(pls->url_template);
1683  if (!seg->url) {
1684  av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template);
1685  av_free(tmpfilename);
1686  av_free(seg);
1687  return NULL;
1688  }
1689  }
1690  av_free(tmpfilename);
1691  seg->size = -1;
1692  }
1693 
1694  return seg;
1695 }
1696 
1697 static int read_from_url(struct representation *pls, struct fragment *seg,
1698  uint8_t *buf, int buf_size)
1699 {
1700  int ret;
1701 
1702  /* limit read if the fragment was only a part of a file */
1703  if (seg->size >= 0)
1704  buf_size = FFMIN(buf_size, pls->cur_seg_size - pls->cur_seg_offset);
1705 
1706  ret = avio_read(pls->input, buf, buf_size);
1707  if (ret > 0)
1708  pls->cur_seg_offset += ret;
1709 
1710  return ret;
1711 }
1712 
1713 static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
1714 {
1715  AVDictionary *opts = NULL;
1716  char *url = NULL;
1717  int ret = 0;
1718 
1719  url = av_mallocz(c->max_url_size);
1720  if (!url) {
1721  ret = AVERROR(ENOMEM);
1722  goto cleanup;
1723  }
1724 
1725  if (seg->size >= 0) {
1726  /* try to restrict the HTTP request to the part we want
1727  * (if this is in fact a HTTP request) */
1728  av_dict_set_int(&opts, "offset", seg->url_offset, 0);
1729  av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0);
1730  }
1731 
1732  ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url);
1733  av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64"\n",
1734  url, seg->url_offset);
1735  ret = open_url(pls->parent, &pls->input, url, &c->avio_opts, opts, NULL);
1736 
1737 cleanup:
1738  av_free(url);
1739  av_dict_free(&opts);
1740  pls->cur_seg_offset = 0;
1741  pls->cur_seg_size = seg->size;
1742  return ret;
1743 }
1744 
1745 static int update_init_section(struct representation *pls)
1746 {
1747  static const int max_init_section_size = 1024 * 1024;
1748  DASHContext *c = pls->parent->priv_data;
1749  int64_t sec_size;
1750  int64_t urlsize;
1751  int ret;
1752 
1753  if (!pls->init_section || pls->init_sec_buf)
1754  return 0;
1755 
1756  ret = open_input(c, pls, pls->init_section);
1757  if (ret < 0) {
1759  "Failed to open an initialization section\n");
1760  return ret;
1761  }
1762 
1763  if (pls->init_section->size >= 0)
1764  sec_size = pls->init_section->size;
1765  else if ((urlsize = avio_size(pls->input)) >= 0)
1766  sec_size = urlsize;
1767  else
1768  sec_size = max_init_section_size;
1769 
1770  av_log(pls->parent, AV_LOG_DEBUG,
1771  "Downloading an initialization section of size %"PRId64"\n",
1772  sec_size);
1773 
1774  sec_size = FFMIN(sec_size, max_init_section_size);
1775 
1776  av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size);
1777 
1778  ret = read_from_url(pls, pls->init_section, pls->init_sec_buf,
1779  pls->init_sec_buf_size);
1780  ff_format_io_close(pls->parent, &pls->input);
1781 
1782  if (ret < 0)
1783  return ret;
1784 
1785  pls->init_sec_data_len = ret;
1786  pls->init_sec_buf_read_offset = 0;
1787 
1788  return 0;
1789 }
1790 
1791 static int64_t seek_data(void *opaque, int64_t offset, int whence)
1792 {
1793  struct representation *v = opaque;
1794  if (v->n_fragments && !v->init_sec_data_len) {
1795  return avio_seek(v->input, offset, whence);
1796  }
1797 
1798  return AVERROR(ENOSYS);
1799 }
1800 
1801 static int read_data(void *opaque, uint8_t *buf, int buf_size)
1802 {
1803  int ret = 0;
1804  struct representation *v = opaque;
1805  DASHContext *c = v->parent->priv_data;
1806 
1807 restart:
1808  if (!v->input) {
1809  free_fragment(&v->cur_seg);
1810  v->cur_seg = get_current_fragment(v);
1811  if (!v->cur_seg) {
1812  ret = AVERROR_EOF;
1813  goto end;
1814  }
1815 
1816  /* load/update Media Initialization Section, if any */
1817  ret = update_init_section(v);
1818  if (ret)
1819  goto end;
1820 
1821  ret = open_input(c, v, v->cur_seg);
1822  if (ret < 0) {
1823  if (ff_check_interrupt(c->interrupt_callback)) {
1824  ret = AVERROR_EXIT;
1825  goto end;
1826  }
1827  av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist\n");
1828  v->cur_seq_no++;
1829  goto restart;
1830  }
1831  }
1832 
1834  /* Push init section out first before first actual fragment */
1835  int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size);
1836  memcpy(buf, v->init_sec_buf, copy_size);
1837  v->init_sec_buf_read_offset += copy_size;
1838  ret = copy_size;
1839  goto end;
1840  }
1841 
1842  /* check the v->cur_seg, if it is null, get current and double check if the new v->cur_seg*/
1843  if (!v->cur_seg) {
1844  v->cur_seg = get_current_fragment(v);
1845  }
1846  if (!v->cur_seg) {
1847  ret = AVERROR_EOF;
1848  goto end;
1849  }
1850  ret = read_from_url(v, v->cur_seg, buf, buf_size);
1851  if (ret > 0)
1852  goto end;
1853 
1854  if (c->is_live || v->cur_seq_no < v->last_seq_no) {
1855  if (!v->is_restart_needed)
1856  v->cur_seq_no++;
1857  v->is_restart_needed = 1;
1858  }
1859 
1860 end:
1861  return ret;
1862 }
1863 
1864 static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url,
1865  int flags, AVDictionary **opts)
1866 {
1868  "A DASH playlist item '%s' referred to an external file '%s'. "
1869  "Opening this file was forbidden for security reasons\n",
1870  s->url, url);
1871  return AVERROR(EPERM);
1872 }
1873 
1875 {
1876  /* note: the internal buffer could have changed */
1877  av_freep(&pls->pb.pub.buffer);
1878  memset(&pls->pb, 0x00, sizeof(pls->pb));
1879  pls->ctx->pb = NULL;
1880  avformat_close_input(&pls->ctx);
1881 }
1882 
1884 {
1885  DASHContext *c = s->priv_data;
1886  const AVInputFormat *in_fmt = NULL;
1887  AVDictionary *in_fmt_opts = NULL;
1888  uint8_t *avio_ctx_buffer = NULL;
1889  int ret = 0, i;
1890 
1891  if (pls->ctx) {
1893  }
1894 
1895  if (ff_check_interrupt(&s->interrupt_callback)) {
1896  ret = AVERROR_EXIT;
1897  goto fail;
1898  }
1899 
1900  if (!(pls->ctx = avformat_alloc_context())) {
1901  ret = AVERROR(ENOMEM);
1902  goto fail;
1903  }
1904 
1905  avio_ctx_buffer = av_malloc(INITIAL_BUFFER_SIZE);
1906  if (!avio_ctx_buffer ) {
1907  ret = AVERROR(ENOMEM);
1908  avformat_free_context(pls->ctx);
1909  pls->ctx = NULL;
1910  goto fail;
1911  }
1912  ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0,
1913  pls, read_data, NULL, c->is_live ? NULL : seek_data);
1914  pls->pb.pub.seekable = 0;
1915 
1916  if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
1917  goto fail;
1918 
1919  pls->ctx->flags = AVFMT_FLAG_CUSTOM_IO;
1920  pls->ctx->probesize = s->probesize > 0 ? s->probesize : 1024 * 4;
1921  pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE;
1922  pls->ctx->interrupt_callback = s->interrupt_callback;
1923  ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, "", NULL, 0, 0);
1924  if (ret < 0) {
1925  av_log(s, AV_LOG_ERROR, "Error when loading first fragment of playlist\n");
1926  avformat_free_context(pls->ctx);
1927  pls->ctx = NULL;
1928  goto fail;
1929  }
1930 
1931  pls->ctx->pb = &pls->pb.pub;
1932  pls->ctx->io_open = nested_io_open;
1933 
1934  if (c->cenc_decryption_key)
1935  av_dict_set(&in_fmt_opts, "decryption_key", c->cenc_decryption_key, 0);
1936 
1937  // provide additional information from mpd if available
1938  ret = avformat_open_input(&pls->ctx, "", in_fmt, &in_fmt_opts); //pls->init_section->url
1939  av_dict_free(&in_fmt_opts);
1940  if (ret < 0)
1941  goto fail;
1942  if (pls->n_fragments) {
1943 #if FF_API_R_FRAME_RATE
1944  if (pls->framerate.den) {
1945  for (i = 0; i < pls->ctx->nb_streams; i++)
1946  pls->ctx->streams[i]->r_frame_rate = pls->framerate;
1947  }
1948 #endif
1950  if (ret < 0)
1951  goto fail;
1952  }
1953 
1954 fail:
1955  return ret;
1956 }
1957 
1959 {
1960  int ret = 0;
1961  int i;
1962 
1963  pls->parent = s;
1964  pls->cur_seq_no = calc_cur_seg_no(s, pls);
1965 
1966  if (!pls->last_seq_no)
1967  pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
1968 
1970  if (ret < 0)
1971  return ret;
1972 
1973  for (i = 0; i < pls->ctx->nb_streams; i++) {
1975  AVStream *ist = pls->ctx->streams[i];
1976  if (!st)
1977  return AVERROR(ENOMEM);
1978 
1979  st->id = i;
1980 
1982  if (ret < 0)
1983  return ret;
1984 
1986 
1987  // copy disposition
1988  st->disposition = ist->disposition;
1989  }
1990 
1991  return 0;
1992 }
1993 
1994 static int is_common_init_section_exist(struct representation **pls, int n_pls)
1995 {
1996  struct fragment *first_init_section = pls[0]->init_section;
1997  char *url =NULL;
1998  int64_t url_offset = -1;
1999  int64_t size = -1;
2000  int i = 0;
2001 
2002  if (first_init_section == NULL || n_pls == 0)
2003  return 0;
2004 
2005  url = first_init_section->url;
2006  url_offset = first_init_section->url_offset;
2007  size = pls[0]->init_section->size;
2008  for (i=0;i<n_pls;i++) {
2009  if (!pls[i]->init_section)
2010  continue;
2011 
2012  if (av_strcasecmp(pls[i]->init_section->url, url) ||
2013  pls[i]->init_section->url_offset != url_offset ||
2014  pls[i]->init_section->size != size) {
2015  return 0;
2016  }
2017  }
2018  return 1;
2019 }
2020 
2021 static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
2022 {
2023  rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
2024  if (!rep_dest->init_sec_buf) {
2025  av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n");
2026  return AVERROR(ENOMEM);
2027  }
2028  memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
2029  rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
2030  rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
2031  rep_dest->cur_timestamp = rep_src->cur_timestamp;
2032 
2033  return 0;
2034 }
2035 
2036 static void move_metadata(AVStream *st, const char *key, char **value)
2037 {
2038  if (*value) {
2040  *value = NULL;
2041  }
2042 }
2043 
2045 {
2046  DASHContext *c = s->priv_data;
2047  struct representation *rep;
2048  AVProgram *program;
2049  int ret = 0;
2050  int stream_index = 0;
2051  int i;
2052 
2053  c->interrupt_callback = &s->interrupt_callback;
2054 
2055  if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0)
2056  return ret;
2057 
2058  if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
2059  return ret;
2060 
2061  /* If this isn't a live stream, fill the total duration of the
2062  * stream. */
2063  if (!c->is_live) {
2064  s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
2065  } else {
2066  av_dict_set(&c->avio_opts, "seekable", "0", 0);
2067  }
2068 
2069  if(c->n_videos)
2070  c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
2071 
2072  /* Open the demuxer for video and audio components if available */
2073  for (i = 0; i < c->n_videos; i++) {
2074  rep = c->videos[i];
2075  if (i > 0 && c->is_init_section_common_video) {
2076  ret = copy_init_section(rep, c->videos[0]);
2077  if (ret < 0)
2078  return ret;
2079  }
2080  ret = open_demux_for_component(s, rep);
2081 
2082  if (ret)
2083  return ret;
2084  rep->stream_index = stream_index;
2085  ++stream_index;
2086  }
2087 
2088  if(c->n_audios)
2089  c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
2090 
2091  for (i = 0; i < c->n_audios; i++) {
2092  rep = c->audios[i];
2093  if (i > 0 && c->is_init_section_common_audio) {
2094  ret = copy_init_section(rep, c->audios[0]);
2095  if (ret < 0)
2096  return ret;
2097  }
2098  ret = open_demux_for_component(s, rep);
2099 
2100  if (ret)
2101  return ret;
2102  rep->stream_index = stream_index;
2103  ++stream_index;
2104  }
2105 
2106  if (c->n_subtitles)
2107  c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles);
2108 
2109  for (i = 0; i < c->n_subtitles; i++) {
2110  rep = c->subtitles[i];
2111  if (i > 0 && c->is_init_section_common_subtitle) {
2112  ret = copy_init_section(rep, c->subtitles[0]);
2113  if (ret < 0)
2114  return ret;
2115  }
2116  ret = open_demux_for_component(s, rep);
2117 
2118  if (ret)
2119  return ret;
2120  rep->stream_index = stream_index;
2121  ++stream_index;
2122  }
2123 
2124  if (!stream_index)
2125  return AVERROR_INVALIDDATA;
2126 
2127  /* Create a program */
2128  program = av_new_program(s, 0);
2129  if (!program)
2130  return AVERROR(ENOMEM);
2131 
2132  for (i = 0; i < c->n_videos; i++) {
2133  rep = c->videos[i];
2135  rep->assoc_stream = s->streams[rep->stream_index];
2136  if (rep->bandwidth > 0)
2137  av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0);
2138  move_metadata(rep->assoc_stream, "id", &rep->id);
2139  }
2140  for (i = 0; i < c->n_audios; i++) {
2141  rep = c->audios[i];
2143  rep->assoc_stream = s->streams[rep->stream_index];
2144  if (rep->bandwidth > 0)
2145  av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0);
2146  move_metadata(rep->assoc_stream, "id", &rep->id);
2147  move_metadata(rep->assoc_stream, "language", &rep->lang);
2148  }
2149  for (i = 0; i < c->n_subtitles; i++) {
2150  rep = c->subtitles[i];
2152  rep->assoc_stream = s->streams[rep->stream_index];
2153  move_metadata(rep->assoc_stream, "id", &rep->id);
2154  move_metadata(rep->assoc_stream, "language", &rep->lang);
2155  }
2156 
2157  return 0;
2158 }
2159 
2161 {
2162  int i, j;
2163 
2164  for (i = 0; i < n; i++) {
2165  struct representation *pls = p[i];
2166  int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL;
2167 
2168  if (needed && !pls->ctx) {
2169  pls->cur_seg_offset = 0;
2170  pls->init_sec_buf_read_offset = 0;
2171  /* Catch up */
2172  for (j = 0; j < n; j++) {
2173  pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no);
2174  }
2176  av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index);
2177  } else if (!needed && pls->ctx) {
2179  ff_format_io_close(pls->parent, &pls->input);
2180  av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index);
2181  }
2182  }
2183 }
2184 
2186 {
2187  DASHContext *c = s->priv_data;
2188  int ret = 0, i;
2189  int64_t mints = 0;
2190  struct representation *cur = NULL;
2191  struct representation *rep = NULL;
2192 
2193  recheck_discard_flags(s, c->videos, c->n_videos);
2194  recheck_discard_flags(s, c->audios, c->n_audios);
2195  recheck_discard_flags(s, c->subtitles, c->n_subtitles);
2196 
2197  for (i = 0; i < c->n_videos; i++) {
2198  rep = c->videos[i];
2199  if (!rep->ctx)
2200  continue;
2201  if (!cur || rep->cur_timestamp < mints) {
2202  cur = rep;
2203  mints = rep->cur_timestamp;
2204  }
2205  }
2206  for (i = 0; i < c->n_audios; i++) {
2207  rep = c->audios[i];
2208  if (!rep->ctx)
2209  continue;
2210  if (!cur || rep->cur_timestamp < mints) {
2211  cur = rep;
2212  mints = rep->cur_timestamp;
2213  }
2214  }
2215 
2216  for (i = 0; i < c->n_subtitles; i++) {
2217  rep = c->subtitles[i];
2218  if (!rep->ctx)
2219  continue;
2220  if (!cur || rep->cur_timestamp < mints) {
2221  cur = rep;
2222  mints = rep->cur_timestamp;
2223  }
2224  }
2225 
2226  if (!cur) {
2227  return AVERROR_INVALIDDATA;
2228  }
2229  while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
2230  ret = av_read_frame(cur->ctx, pkt);
2231  if (ret >= 0) {
2232  /* If we got a packet, return it */
2233  cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
2234  pkt->stream_index = cur->stream_index;
2235  return 0;
2236  }
2237  if (cur->is_restart_needed) {
2238  cur->cur_seg_offset = 0;
2239  cur->init_sec_buf_read_offset = 0;
2240  cur->is_restart_needed = 0;
2241  ff_format_io_close(cur->parent, &cur->input);
2243  }
2244  }
2245  return AVERROR_EOF;
2246 }
2247 
2249 {
2250  DASHContext *c = s->priv_data;
2251  free_audio_list(c);
2252  free_video_list(c);
2254  av_dict_free(&c->avio_opts);
2255  av_freep(&c->base_url);
2256  return 0;
2257 }
2258 
2259 static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
2260 {
2261  int ret = 0;
2262  int i = 0;
2263  int j = 0;
2264  int64_t duration = 0;
2265 
2266  av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms] %s\n",
2267  seek_pos_msec, dry_run ? " (dry)" : "");
2268 
2269  // single fragment mode
2270  if (pls->n_fragments == 1) {
2271  pls->cur_timestamp = 0;
2272  pls->cur_seg_offset = 0;
2273  if (dry_run)
2274  return 0;
2275  ff_read_frame_flush(pls->ctx);
2276  return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags);
2277  }
2278 
2279  ff_format_io_close(pls->parent, &pls->input);
2280 
2281  // find the nearest fragment
2282  if (pls->n_timelines > 0 && pls->fragment_timescale > 0) {
2283  int64_t num = pls->first_seq_no;
2284  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] "
2285  "last_seq_no[%"PRId64"].\n",
2286  (int)pls->n_timelines, (int64_t)pls->last_seq_no);
2287  for (i = 0; i < pls->n_timelines; i++) {
2288  if (pls->timelines[i]->starttime > 0) {
2289  duration = pls->timelines[i]->starttime;
2290  }
2291  duration += pls->timelines[i]->duration;
2292  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2293  goto set_seq_num;
2294  }
2295  for (j = 0; j < pls->timelines[i]->repeat; j++) {
2296  duration += pls->timelines[i]->duration;
2297  num++;
2298  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2299  goto set_seq_num;
2300  }
2301  }
2302  num++;
2303  }
2304 
2305 set_seq_num:
2306  pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num;
2307  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"].\n",
2308  (int64_t)pls->cur_seq_no);
2309  } else if (pls->fragment_duration > 0) {
2310  pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000;
2311  } else {
2312  av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n");
2313  pls->cur_seq_no = pls->first_seq_no;
2314  }
2315  pls->cur_timestamp = 0;
2316  pls->cur_seg_offset = 0;
2317  pls->init_sec_buf_read_offset = 0;
2318  ret = dry_run ? 0 : reopen_demux_for_component(s, pls);
2319 
2320  return ret;
2321 }
2322 
2323 static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
2324 {
2325  int ret = 0, i;
2326  DASHContext *c = s->priv_data;
2327  int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000,
2328  s->streams[stream_index]->time_base.den,
2331  if ((flags & AVSEEK_FLAG_BYTE) || c->is_live)
2332  return AVERROR(ENOSYS);
2333 
2334  /* Seek in discarded streams with dry_run=1 to avoid reopening them */
2335  for (i = 0; i < c->n_videos; i++) {
2336  if (!ret)
2337  ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx);
2338  }
2339  for (i = 0; i < c->n_audios; i++) {
2340  if (!ret)
2341  ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
2342  }
2343  for (i = 0; i < c->n_subtitles; i++) {
2344  if (!ret)
2345  ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
2346  }
2347 
2348  return ret;
2349 }
2350 
2351 static int dash_probe(const AVProbeData *p)
2352 {
2353  if (!av_stristr(p->buf, "<MPD"))
2354  return 0;
2355 
2356  if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") ||
2357  av_stristr(p->buf, "dash:profile:isoff-live:2011") ||
2358  av_stristr(p->buf, "dash:profile:isoff-live:2012") ||
2359  av_stristr(p->buf, "dash:profile:isoff-main:2011") ||
2360  av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) {
2361  return AVPROBE_SCORE_MAX;
2362  }
2363  if (av_stristr(p->buf, "dash:profile")) {
2364  return AVPROBE_SCORE_MAX;
2365  }
2366 
2367  return 0;
2368 }
2369 
2370 #define OFFSET(x) offsetof(DASHContext, x)
2371 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
2372 static const AVOption dash_options[] = {
2373  {"allowed_extensions", "List of file extensions that dash is allowed to access",
2374  OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
2375  {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"},
2376  INT_MIN, INT_MAX, FLAGS},
2377  { "cenc_decryption_key", "Media decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
2378  {NULL}
2379 };
2380 
2381 static const AVClass dash_class = {
2382  .class_name = "dash",
2383  .item_name = av_default_item_name,
2384  .option = dash_options,
2385  .version = LIBAVUTIL_VERSION_INT,
2386 };
2387 
2389  .p.name = "dash",
2390  .p.long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"),
2391  .p.priv_class = &dash_class,
2392  .p.flags = AVFMT_NO_BYTE_SEEK,
2393  .priv_data_size = sizeof(DASHContext),
2394  .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
2400 };
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:1883
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:1874
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:1958
read_data
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition: dashdec.c:1801
ffio_init_context
void ffio_init_context(FFIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, const uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition: aviobuf.c:50
ffio_copy_url_options
int ffio_copy_url_options(AVIOContext *pb, AVDictionary **avio_opts)
Read url related dictionary options from the AVIOContext and write to the given dictionary.
Definition: aviobuf.c:994
representation::start_number
int64_t start_number
Definition: dashdec.c: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:1443
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:2371
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:1614
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:2248
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:1583
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:1697
avio_size
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:326
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
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:377
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:779
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:1457
free_fragment
static void free_fragment(struct fragment **seg)
Definition: dashdec.c:320
fail
#define fail()
Definition: checkasm.h:217
calc_cur_seg_no
static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1405
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:2160
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:269
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:2372
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:1791
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:231
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:2036
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:1497
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:1254
av_seek_frame
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Seek to the keyframe at timestamp.
Definition: seek.c:641
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h: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
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:1202
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
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
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
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
representation::stream_index
int stream_index
Definition: dashdec.c:85
AVFormatContext::max_analyze_duration
int64_t max_analyze_duration
Maximum duration (in AV_TIME_BASE units) of the data read from input in avformat_find_stream_info().
Definition: avformat.h: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:300
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:1994
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:824
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
dash_read_seek
static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: dashdec.c:2323
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:1483
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:2388
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:1231
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:2602
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:235
SET_REPRESENTATION_SEQUENCE_BASE_INFO
#define SET_REPRESENTATION_SEQUENCE_BASE_INFO(arg, cnt)
Definition: dashdec.c:846
FFIOContext::pub
AVIOContext pub
Definition: avio_internal.h:29
start_time
static int64_t start_time
Definition: ffplay.c:328
size
int size
Definition: twinvq_data.h:10344
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
representation::bandwidth
int bandwidth
Definition: dashdec.c:89
representation::parent
AVFormatContext * parent
Definition: dashdec.c:83
ff_format_io_close
int ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: avformat.c:870
AVMEDIA_TYPE_UNKNOWN
@ AVMEDIA_TYPE_UNKNOWN
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:199
OFFSET
#define OFFSET(x)
Definition: dashdec.c:2370
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
FFInputFormat::p
AVInputFormat p
The public AVInputFormat.
Definition: demux.h:51
copy_init_section
static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
Definition: dashdec.c:2021
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:2044
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:348
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
DASHContext::cenc_decryption_key
char * cenc_decryption_key
Definition: dashdec.c: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:581
avio_internal.h
dash_probe
static int dash_probe(const AVProbeData *p)
Definition: dashdec.c:2351
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:1146
url.h
fragment::url
char * url
Definition: dashdec.c:40
AVProgram
New fields can be added to the end with minor version bumps.
Definition: avformat.h: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:1864
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
av_malloc
void * av_malloc(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:98
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:1133
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:143
avio_read
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:615
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:1515
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:1745
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
parse_manifest_representation
static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr node, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, xmlNodePtr period_baseurl_node, xmlNodePtr period_segmenttemplate_node, xmlNodePtr period_segmentlist_node, xmlNodePtr fragment_template_node, xmlNodePtr content_component_node, xmlNodePtr adaptionset_baseurl_node, xmlNodePtr adaptionset_segmentlist_node, xmlNodePtr adaptionset_supplementalproperty_node)
Definition: dashdec.c:883
AVPacket::stream_index
int stream_index
Definition: packet.h:590
dash_read_packet
static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dashdec.c:2185
open_input
static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
Definition: dashdec.c:1713
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:565
ff_dash_fill_tmpl_params
void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size, const char *template, int rep_id, int number, int bit_rate, int64_t time)
Definition: dash.c:95
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
av_fast_malloc
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
Allocate a buffer, reusing the given one if large enough.
Definition: mem.c:557
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:247
FFInputFormat
Definition: demux.h:47
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:2259
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:2381
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:107
fragment::size
int64_t size
Definition: dashdec.c:39
avio_feof
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:349