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  FFStream *sti = ffstream(st);
2009  const AVStream *ist = pls->ctx->streams[i];
2010  const FFStream *isti = cffstream(ist);
2011  if (!st)
2012  return AVERROR(ENOMEM);
2013 
2014  st->id = i + pls->stream_index;
2015 
2017  if (ret < 0)
2018  return ret;
2019 
2021 
2022  // copy disposition
2023  st->disposition = ist->disposition;
2024  sti->need_parsing = isti->need_parsing;
2025  }
2026 
2027  for (i = 0; i < pls->ctx->nb_stream_groups; i++) {
2028  AVStreamGroup *istg = pls->ctx->stream_groups[i];
2029  AVStreamGroup *stg;
2030 
2031  if (istg->type != AV_STREAM_GROUP_PARAMS_LCEVC)
2032  continue;
2033 
2034  stg = avformat_stream_group_create(s, istg->type, NULL);
2035  if (!stg)
2036  return AVERROR(ENOMEM);
2037 
2038  stg->id = s->nb_stream_groups;
2039 
2040  for (int j = 0; j < istg->nb_streams; j++) {
2041  AVStream *ist = istg->streams[j];
2042  AVStream *st = s->streams[ist->index + pls->stream_index];
2044  if (ret < 0)
2045  return ret;
2046  }
2047 
2048  switch (stg->type) {
2050  AVStreamGroupLCEVC *ilcevc = istg->params.lcevc;
2051  AVStreamGroupLCEVC *lcevc = stg->params.lcevc;
2052  ret = av_opt_copy(lcevc, ilcevc);
2053  if (ret < 0)
2054  return ret;
2055  break;
2056  }
2057  default:
2058  av_unreachable("Unsupported Stream Group type should have been checked above");
2059  }
2060 
2061  // copy disposition
2062  stg->disposition = istg->disposition;
2063  }
2064 
2065  return 0;
2066 }
2067 
2068 static int is_common_init_section_exist(struct representation **pls, int n_pls)
2069 {
2070  struct fragment *first_init_section = pls[0]->init_section;
2071  char *url =NULL;
2072  int64_t url_offset = -1;
2073  int64_t size = -1;
2074  int i = 0;
2075 
2076  if (first_init_section == NULL || n_pls == 0)
2077  return 0;
2078 
2079  url = first_init_section->url;
2080  url_offset = first_init_section->url_offset;
2081  size = pls[0]->init_section->size;
2082  for (i=0;i<n_pls;i++) {
2083  if (!pls[i]->init_section)
2084  continue;
2085 
2086  if (av_strcasecmp(pls[i]->init_section->url, url) ||
2087  pls[i]->init_section->url_offset != url_offset ||
2088  pls[i]->init_section->size != size) {
2089  return 0;
2090  }
2091  }
2092  return 1;
2093 }
2094 
2095 static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
2096 {
2097  rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
2098  if (!rep_dest->init_sec_buf) {
2099  av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n");
2100  return AVERROR(ENOMEM);
2101  }
2102  memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
2103  rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
2104  rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
2105  rep_dest->cur_timestamp = rep_src->cur_timestamp;
2106 
2107  return 0;
2108 }
2109 
2110 static void move_metadata(AVStream *st, const char *key, char **value)
2111 {
2112  if (*value) {
2114  *value = NULL;
2115  }
2116 }
2117 
2119 {
2120  DASHContext *c = s->priv_data;
2121  struct representation *rep;
2122  AVProgram *program;
2123  int ret = 0;
2124  int stream_index = 0;
2125  int i, j;
2126 
2127  c->interrupt_callback = &s->interrupt_callback;
2128 
2129  if ((ret = ffio_copy_url_options(s->pb, &c->avio_opts)) < 0)
2130  return ret;
2131 
2132  if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
2133  return ret;
2134 
2135  /* If this isn't a live stream, fill the total duration of the
2136  * stream. */
2137  if (!c->is_live) {
2138  s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
2139  } else {
2140  av_dict_set(&c->avio_opts, "seekable", "0", 0);
2141  }
2142 
2143  if(c->n_videos)
2144  c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
2145 
2146  /* Open the demuxer for video and audio components if available */
2147  for (i = 0; i < c->n_videos; i++) {
2148  rep = c->videos[i];
2149  if (i > 0 && c->is_init_section_common_video) {
2150  ret = copy_init_section(rep, c->videos[0]);
2151  if (ret < 0)
2152  return ret;
2153  }
2154  rep->stream_index = stream_index;
2155  ret = open_demux_for_component(s, rep);
2156 
2157  if (ret)
2158  return ret;
2159  stream_index += rep->ctx->nb_streams;
2160  }
2161 
2162  if(c->n_audios)
2163  c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
2164 
2165  for (i = 0; i < c->n_audios; i++) {
2166  rep = c->audios[i];
2167  if (i > 0 && c->is_init_section_common_audio) {
2168  ret = copy_init_section(rep, c->audios[0]);
2169  if (ret < 0)
2170  return ret;
2171  }
2172  rep->stream_index = stream_index;
2173  ret = open_demux_for_component(s, rep);
2174 
2175  if (ret)
2176  return ret;
2177  stream_index += rep->ctx->nb_streams;
2178  }
2179 
2180  if (c->n_subtitles)
2181  c->is_init_section_common_subtitle = is_common_init_section_exist(c->subtitles, c->n_subtitles);
2182 
2183  for (i = 0; i < c->n_subtitles; i++) {
2184  rep = c->subtitles[i];
2185  if (i > 0 && c->is_init_section_common_subtitle) {
2186  ret = copy_init_section(rep, c->subtitles[0]);
2187  if (ret < 0)
2188  return ret;
2189  }
2190  rep->stream_index = stream_index;
2191  ret = open_demux_for_component(s, rep);
2192 
2193  if (ret)
2194  return ret;
2195  stream_index += rep->ctx->nb_streams;
2196  }
2197 
2198  if (!stream_index)
2199  return AVERROR_INVALIDDATA;
2200 
2201  /* Create a program */
2202  program = av_new_program(s, 0);
2203  if (!program)
2204  return AVERROR(ENOMEM);
2205 
2206  for (i = 0; i < c->n_videos; i++) {
2207  rep = c->videos[i];
2208  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2209  if (!rep->assoc_stream)
2210  return AVERROR(ENOMEM);
2211  rep->nb_assoc_stream = rep->ctx->nb_streams;
2212  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2214  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2215  }
2216  if (rep->bandwidth > 0)
2217  av_dict_set_int(&rep->assoc_stream[0]->metadata, "variant_bitrate", rep->bandwidth, 0);
2218  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2219  }
2220  for (i = 0; i < c->n_audios; i++) {
2221  rep = c->audios[i];
2222  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2223  if (!rep->assoc_stream)
2224  return AVERROR(ENOMEM);
2225  rep->nb_assoc_stream = rep->ctx->nb_streams;
2226  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2228  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2229  }
2230  if (rep->bandwidth > 0)
2231  av_dict_set_int(&rep->assoc_stream[0]->metadata, "variant_bitrate", rep->bandwidth, 0);
2232  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2233  move_metadata(rep->assoc_stream[0], "language", &rep->lang);
2234  }
2235  for (i = 0; i < c->n_subtitles; i++) {
2236  rep = c->subtitles[i];
2237  rep->assoc_stream = av_malloc_array(rep->ctx->nb_streams, sizeof(*rep->assoc_stream));
2238  if (!rep->assoc_stream)
2239  return AVERROR(ENOMEM);
2240  rep->nb_assoc_stream = rep->ctx->nb_streams;
2241  for (int j = 0; j < rep->ctx->nb_streams; j++) {
2243  rep->assoc_stream[j] = s->streams[rep->stream_index + j];
2244  }
2245  move_metadata(rep->assoc_stream[0], "id", &rep->id);
2246  move_metadata(rep->assoc_stream[0], "language", &rep->lang);
2247  }
2248 
2249  /* Create stream groups if needed */
2250  for (i = 0; i < c->n_videos; i++) {
2251  struct representation *ref;
2252  rep = c->videos[i];
2253  if (!rep->dependencyid || !rep->nb_assoc_stream)
2254  continue;
2255  for (j = 0; j < c->n_videos; j++) {
2256  if (j == i)
2257  continue;
2258  ref = c->videos[j];
2259  if (!ref->nb_assoc_stream)
2260  continue;
2261  const AVDictionaryEntry *id = av_dict_get(ref->assoc_stream[0]->metadata, "id", NULL, AV_DICT_MATCH_CASE);
2262  if (!strcmp(rep->dependencyid, id->value))
2263  break;
2264  }
2265  if (j >= c->n_videos || !av_strstart(rep->codecs, "lvc1", NULL) ||
2267  continue;
2269  if (!stg)
2270  return AVERROR(ENOMEM);
2271  stg->params.lcevc->width = rep->assoc_stream[0]->codecpar->width;
2272  stg->params.lcevc->height = rep->assoc_stream[0]->codecpar->height;
2273  ret = avformat_stream_group_add_stream(stg, ref->assoc_stream[0]);
2274  if (ret < 0)
2275  return ret;
2277  if (ret < 0)
2278  return ret;
2279  stg->id = stg->index;
2280  stg->params.lcevc->lcevc_index = stg->nb_streams - 1;
2281  }
2282 
2283  return 0;
2284 }
2285 
2287 {
2288  int i, j;
2289 
2290  for (i = 0; i < n; i++) {
2291  struct representation *pls = p[i];
2292  int needed = !pls->nb_assoc_stream;
2293 
2294  for (int j = 0; j < pls->nb_assoc_stream; j++)
2295  needed |= pls->assoc_stream[j]->discard < AVDISCARD_ALL;
2296 
2297  if (needed && !pls->ctx) {
2298  pls->cur_seg_offset = 0;
2299  pls->init_sec_buf_read_offset = 0;
2300  /* Catch up */
2301  for (j = 0; j < n; j++) {
2302  pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no);
2303  }
2305  av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index);
2306  } else if (!needed && pls->ctx) {
2308  ff_format_io_close(pls->parent, &pls->input);
2309  av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index);
2310  }
2311  }
2312 }
2313 
2315 {
2316  DASHContext *c = s->priv_data;
2317  int ret = 0, i;
2318  int64_t mints = 0;
2319  struct representation *cur = NULL;
2320  struct representation *rep = NULL;
2321 
2322  recheck_discard_flags(s, c->videos, c->n_videos);
2323  recheck_discard_flags(s, c->audios, c->n_audios);
2324  recheck_discard_flags(s, c->subtitles, c->n_subtitles);
2325 
2326  for (i = 0; i < c->n_videos; i++) {
2327  rep = c->videos[i];
2328  if (!rep->ctx)
2329  continue;
2330  if (!cur || rep->cur_timestamp < mints) {
2331  cur = rep;
2332  mints = rep->cur_timestamp;
2333  }
2334  }
2335  for (i = 0; i < c->n_audios; i++) {
2336  rep = c->audios[i];
2337  if (!rep->ctx)
2338  continue;
2339  if (!cur || rep->cur_timestamp < mints) {
2340  cur = rep;
2341  mints = rep->cur_timestamp;
2342  }
2343  }
2344 
2345  for (i = 0; i < c->n_subtitles; i++) {
2346  rep = c->subtitles[i];
2347  if (!rep->ctx)
2348  continue;
2349  if (!cur || rep->cur_timestamp < mints) {
2350  cur = rep;
2351  mints = rep->cur_timestamp;
2352  }
2353  }
2354 
2355  if (!cur) {
2356  return AVERROR_INVALIDDATA;
2357  }
2358  while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
2359  ret = av_read_frame(cur->ctx, pkt);
2360  if (ret >= 0) {
2361  /* If we got a packet, return it */
2362  cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
2363  pkt->stream_index += cur->stream_index;
2364  return 0;
2365  }
2366  if (cur->is_restart_needed) {
2367  cur->cur_seg_offset = 0;
2368  cur->init_sec_buf_read_offset = 0;
2369  cur->is_restart_needed = 0;
2370  ff_format_io_close(cur->parent, &cur->input);
2372  }
2373  }
2374  return AVERROR_EOF;
2375 }
2376 
2378 {
2379  DASHContext *c = s->priv_data;
2380  free_audio_list(c);
2381  free_video_list(c);
2383  av_dict_free(&c->avio_opts);
2384  av_freep(&c->base_url);
2385  return 0;
2386 }
2387 
2388 static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
2389 {
2390  int ret = 0;
2391  int i = 0;
2392  int j = 0;
2393  int64_t duration = 0;
2394 
2395  av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms] %s\n",
2396  seek_pos_msec, dry_run ? " (dry)" : "");
2397 
2398  // single fragment mode
2399  if (pls->n_fragments == 1) {
2400  pls->cur_timestamp = 0;
2401  pls->cur_seg_offset = 0;
2402  if (dry_run)
2403  return 0;
2404  ff_read_frame_flush(pls->ctx);
2405  return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags);
2406  }
2407 
2408  ff_format_io_close(pls->parent, &pls->input);
2409 
2410  // find the nearest fragment
2411  if (pls->n_timelines > 0 && pls->fragment_timescale > 0) {
2412  int64_t num = pls->first_seq_no;
2413  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] "
2414  "last_seq_no[%"PRId64"].\n",
2415  (int)pls->n_timelines, (int64_t)pls->last_seq_no);
2416  for (i = 0; i < pls->n_timelines; i++) {
2417  if (pls->timelines[i]->starttime > 0) {
2418  duration = pls->timelines[i]->starttime;
2419  }
2420  duration += pls->timelines[i]->duration;
2421  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2422  goto set_seq_num;
2423  }
2424  for (j = 0; j < pls->timelines[i]->repeat; j++) {
2425  duration += pls->timelines[i]->duration;
2426  num++;
2427  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2428  goto set_seq_num;
2429  }
2430  }
2431  num++;
2432  }
2433 
2434 set_seq_num:
2435  pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num;
2436  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"].\n",
2437  (int64_t)pls->cur_seq_no);
2438  } else if (pls->fragment_duration > 0) {
2439  pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000;
2440  } else {
2441  av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n");
2442  pls->cur_seq_no = pls->first_seq_no;
2443  }
2444  pls->cur_timestamp = 0;
2445  pls->cur_seg_offset = 0;
2446  pls->init_sec_buf_read_offset = 0;
2447  ret = dry_run ? 0 : reopen_demux_for_component(s, pls);
2448 
2449  return ret;
2450 }
2451 
2452 static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
2453 {
2454  int ret = 0, i;
2455  DASHContext *c = s->priv_data;
2456  int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000,
2457  s->streams[stream_index]->time_base.den,
2460  if ((flags & AVSEEK_FLAG_BYTE) || c->is_live)
2461  return AVERROR(ENOSYS);
2462 
2463  /* Seek in discarded streams with dry_run=1 to avoid reopening them */
2464  for (i = 0; i < c->n_videos; i++) {
2465  if (!ret)
2466  ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx);
2467  }
2468  for (i = 0; i < c->n_audios; i++) {
2469  if (!ret)
2470  ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
2471  }
2472  for (i = 0; i < c->n_subtitles; i++) {
2473  if (!ret)
2474  ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
2475  }
2476 
2477  return ret;
2478 }
2479 
2480 static int dash_probe(const AVProbeData *p)
2481 {
2482  if (!av_stristr(p->buf, "<MPD"))
2483  return 0;
2484 
2485  if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") ||
2486  av_stristr(p->buf, "dash:profile:isoff-live:2011") ||
2487  av_stristr(p->buf, "dash:profile:isoff-live:2012") ||
2488  av_stristr(p->buf, "dash:profile:isoff-main:2011") ||
2489  av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) {
2490  return AVPROBE_SCORE_MAX;
2491  }
2492  if (av_stristr(p->buf, "dash:profile")) {
2493  return AVPROBE_SCORE_MAX;
2494  }
2495 
2496  return 0;
2497 }
2498 
2499 #define OFFSET(x) offsetof(DASHContext, x)
2500 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
2501 static const AVOption dash_options[] = {
2502  {"allowed_extensions", "List of file extensions that dash is allowed to access",
2503  OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
2504  {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"},
2505  INT_MIN, INT_MAX, FLAGS},
2506  { "cenc_decryption_key", "Media default decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
2507  { "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 },
2508  {NULL}
2509 };
2510 
2511 static const AVClass dash_class = {
2512  .class_name = "dash",
2513  .item_name = av_default_item_name,
2514  .option = dash_options,
2515  .version = LIBAVUTIL_VERSION_INT,
2516 };
2517 
2519  .p.name = "dash",
2520  .p.long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"),
2521  .p.priv_class = &dash_class,
2522  .p.flags = AVFMT_NO_BYTE_SEEK,
2523  .priv_data_size = sizeof(DASHContext),
2524  .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
2530 };
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:477
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:2500
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:2377
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:2518
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
cffstream
static const av_always_inline FFStream * cffstream(const AVStream *st)
Definition: internal.h:367
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:895
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
ffstream
static av_always_inline FFStream * ffstream(AVStream *st)
Definition: internal.h:362
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:2286
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:860
AVRational::num
int num
Numerator.
Definition: rational.h:59
dash_options
static const AVOption dash_options[]
Definition: dashdec.c:2501
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:2110
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
FFStream::need_parsing
enum AVStreamParseType need_parsing
Definition: internal.h:314
representation::assoc_stream
AVStream ** assoc_stream
Definition: dashdec.c:94
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: defs.h:232
AVFormatContext
Format I/O context.
Definition: avformat.h: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:2517
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:332
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:2068
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: avformat.c:940
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:2452
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:2518
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
FFStream
Definition: internal.h:128
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:1017
AVMEDIA_TYPE_UNKNOWN
@ AVMEDIA_TYPE_UNKNOWN
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:199
OFFSET
#define OFFSET(x)
Definition: dashdec.c:2499
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:2095
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:2118
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:2480
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:2314
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:663
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:622
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:2388
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:2511
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