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