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