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