FFmpeg  4.3
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)) {
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")) {
571  } else if (av_stristr((const char *)val, "audio")) {
573  } else if (av_stristr((const char *)val, "text")) {
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 
823 static int parse_manifest_representation(AVFormatContext *s, const char *url,
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);
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);
901  c->max_url_size = aligned(c->max_url_size
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")) {
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:
1185  av_freep(&c->adaptionset_lang);
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)
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) {
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")) {
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);
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)
1364  c->media_presentation_duration = c->period_duration;
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);
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) {
1426  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time;
1427  } else if (c->publish_time > 0 && !c->availability_start_time) {
1428  if (c->min_buffer_time) {
1429  num = pls->first_seq_no + (((c->publish_time + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time;
1430  } else {
1431  num = pls->first_seq_no + (((c->publish_time - c->time_shift_buffer_depth + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
1432  }
1433  } else {
1434  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration;
1435  }
1436  }
1437  } else {
1438  num = pls->first_seq_no;
1439  }
1440  return num;
1441 }
1442 
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");
1450  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->time_shift_buffer_depth) * pls->fragment_timescale) / pls->fragment_duration;
1451  } else {
1452  num = pls->first_seq_no;
1453  }
1454  return num;
1455 }
1456 
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) {
1475  num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale) / pls->fragment_duration;
1476  } else if (pls->fragment_duration) {
1477  num = pls->first_seq_no + (c->media_presentation_duration * pls->fragment_timescale) / 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) {
1541  "new manifest has mismatched no. of video representations, %d -> %d\n",
1542  n_videos, c->n_videos);
1543  return AVERROR_INVALIDDATA;
1544  }
1545  if (c->n_audios != n_audios) {
1547  "new manifest has mismatched no. of audio representations, %d -> %d\n",
1548  n_audios, c->n_audios);
1549  return AVERROR_INVALIDDATA;
1550  }
1551  if (c->n_subtitles != n_subtitles) {
1553  "new manifest has mismatched no. of subtitles representations, %d -> %d\n",
1554  n_subtitles, c->n_subtitles);
1555  return AVERROR_INVALIDDATA;
1556  }
1557 
1558  for (i = 0; i < n_videos; i++) {
1559  struct representation *cur_video = videos[i];
1560  struct representation *ccur_video = c->videos[i];
1561  if (cur_video->timelines) {
1562  // calc current time
1563  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale;
1564  // update segments
1565  ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1);
1566  if (ccur_video->cur_seq_no >= 0) {
1567  move_timelines(ccur_video, cur_video, c);
1568  }
1569  }
1570  if (cur_video->fragments) {
1571  move_segments(ccur_video, cur_video, c);
1572  }
1573  }
1574  for (i = 0; i < n_audios; i++) {
1575  struct representation *cur_audio = audios[i];
1576  struct representation *ccur_audio = c->audios[i];
1577  if (cur_audio->timelines) {
1578  // calc current time
1579  int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale;
1580  // update segments
1581  ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1);
1582  if (ccur_audio->cur_seq_no >= 0) {
1583  move_timelines(ccur_audio, cur_audio, c);
1584  }
1585  }
1586  if (cur_audio->fragments) {
1587  move_segments(ccur_audio, cur_audio, c);
1588  }
1589  }
1590 
1591 finish:
1592  // restore context
1593  if (c->base_url)
1594  av_free(base_url);
1595  else
1596  c->base_url = base_url;
1597 
1598  if (c->subtitles)
1600  if (c->audios)
1601  free_audio_list(c);
1602  if (c->videos)
1603  free_video_list(c);
1604 
1605  c->n_subtitles = n_subtitles;
1606  c->subtitles = subtitles;
1607  c->n_audios = n_audios;
1608  c->audios = audios;
1609  c->n_videos = n_videos;
1610  c->videos = videos;
1611  return ret;
1612 }
1613 
1614 static struct fragment *get_current_fragment(struct representation *pls)
1615 {
1616  int64_t min_seq_no = 0;
1617  int64_t max_seq_no = 0;
1618  struct fragment *seg = NULL;
1619  struct fragment *seg_ptr = NULL;
1620  DASHContext *c = pls->parent->priv_data;
1621 
1622  while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) {
1623  if (pls->cur_seq_no < pls->n_fragments) {
1624  seg_ptr = pls->fragments[pls->cur_seq_no];
1625  seg = av_mallocz(sizeof(struct fragment));
1626  if (!seg) {
1627  return NULL;
1628  }
1629  seg->url = av_strdup(seg_ptr->url);
1630  if (!seg->url) {
1631  av_free(seg);
1632  return NULL;
1633  }
1634  seg->size = seg_ptr->size;
1635  seg->url_offset = seg_ptr->url_offset;
1636  return seg;
1637  } else if (c->is_live) {
1638  refresh_manifest(pls->parent);
1639  } else {
1640  break;
1641  }
1642  }
1643  if (c->is_live) {
1644  min_seq_no = calc_min_seg_no(pls->parent, pls);
1645  max_seq_no = calc_max_seg_no(pls, c);
1646 
1647  if (pls->timelines || pls->fragments) {
1648  refresh_manifest(pls->parent);
1649  }
1650  if (pls->cur_seq_no <= min_seq_no) {
1651  av_log(pls->parent, AV_LOG_VERBOSE, "old fragment: cur[%"PRId64"] min[%"PRId64"] max[%"PRId64"], 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  }
1671  ff_dash_fill_tmpl_params(tmpfilename, c->max_url_size, pls->url_template, 0, pls->cur_seq_no, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no));
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) {
1816  if (ff_check_interrupt(c->interrupt_callback)) {
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 {
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 
1916  if (ff_check_interrupt(&s->interrupt_callback)) {
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;
1945  pls->ctx->max_analyze_duration = s->max_analyze_duration > 0 ? s->max_analyze_duration : 4 * AV_TIME_BASE;
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
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 
1991  if (ret < 0) {
1992  goto fail;
1993  }
1994  for (i = 0; i < pls->ctx->nb_streams; i++) {
1996  AVStream *ist = pls->ctx->streams[i];
1997  if (!st) {
1998  ret = AVERROR(ENOMEM);
1999  goto fail;
2000  }
2001  st->id = i;
2004  }
2005 
2006  return 0;
2007 fail:
2008  return ret;
2009 }
2010 
2011 static int is_common_init_section_exist(struct representation **pls, int n_pls)
2012 {
2013  struct fragment *first_init_section = pls[0]->init_section;
2014  char *url =NULL;
2015  int64_t url_offset = -1;
2016  int64_t size = -1;
2017  int i = 0;
2018 
2019  if (first_init_section == NULL || n_pls == 0)
2020  return 0;
2021 
2022  url = first_init_section->url;
2023  url_offset = first_init_section->url_offset;
2024  size = pls[0]->init_section->size;
2025  for (i=0;i<n_pls;i++) {
2026  if (av_strcasecmp(pls[i]->init_section->url,url) || pls[i]->init_section->url_offset != url_offset || pls[i]->init_section->size != size) {
2027  return 0;
2028  }
2029  }
2030  return 1;
2031 }
2032 
2033 static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
2034 {
2035  rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
2036  if (!rep_dest->init_sec_buf) {
2037  av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n");
2038  return AVERROR(ENOMEM);
2039  }
2040  memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
2041  rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
2042  rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
2043  rep_dest->cur_timestamp = rep_src->cur_timestamp;
2044 
2045  return 0;
2046 }
2047 
2048 
2050 {
2051  DASHContext *c = s->priv_data;
2052  struct representation *rep;
2053  int ret = 0;
2054  int stream_index = 0;
2055  int i;
2056 
2057  c->interrupt_callback = &s->interrupt_callback;
2058 
2059  if ((ret = save_avio_options(s)) < 0)
2060  goto fail;
2061 
2062  if ((ret = parse_manifest(s, s->url, s->pb)) < 0)
2063  goto fail;
2064 
2065  /* If this isn't a live stream, fill the total duration of the
2066  * stream. */
2067  if (!c->is_live) {
2068  s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
2069  } else {
2070  av_dict_set(&c->avio_opts, "seekable", "0", 0);
2071  }
2072 
2073  if(c->n_videos)
2074  c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos);
2075 
2076  /* Open the demuxer for video and audio components if available */
2077  for (i = 0; i < c->n_videos; i++) {
2078  rep = c->videos[i];
2079  if (i > 0 && c->is_init_section_common_video) {
2080  ret = copy_init_section(rep, c->videos[0]);
2081  if (ret < 0)
2082  goto fail;
2083  }
2084  ret = open_demux_for_component(s, rep);
2085 
2086  if (ret)
2087  goto fail;
2088  rep->stream_index = stream_index;
2089  ++stream_index;
2090  }
2091 
2092  if(c->n_audios)
2093  c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios);
2094 
2095  for (i = 0; i < c->n_audios; i++) {
2096  rep = c->audios[i];
2097  if (i > 0 && c->is_init_section_common_audio) {
2098  ret = copy_init_section(rep, c->audios[0]);
2099  if (ret < 0)
2100  goto fail;
2101  }
2102  ret = open_demux_for_component(s, rep);
2103 
2104  if (ret)
2105  goto fail;
2106  rep->stream_index = stream_index;
2107  ++stream_index;
2108  }
2109 
2110  if (c->n_subtitles)
2111  c->is_init_section_common_audio = is_common_init_section_exist(c->subtitles, c->n_subtitles);
2112 
2113  for (i = 0; i < c->n_subtitles; i++) {
2114  rep = c->subtitles[i];
2115  if (i > 0 && c->is_init_section_common_audio) {
2116  ret = copy_init_section(rep, c->subtitles[0]);
2117  if (ret < 0)
2118  goto fail;
2119  }
2120  ret = open_demux_for_component(s, rep);
2121 
2122  if (ret)
2123  goto fail;
2124  rep->stream_index = stream_index;
2125  ++stream_index;
2126  }
2127 
2128  if (!stream_index) {
2130  goto fail;
2131  }
2132 
2133  /* Create a program */
2134  if (!ret) {
2135  AVProgram *program;
2136  program = av_new_program(s, 0);
2137  if (!program) {
2138  goto fail;
2139  }
2140 
2141  for (i = 0; i < c->n_videos; i++) {
2142  rep = c->videos[i];
2144  rep->assoc_stream = s->streams[rep->stream_index];
2145  if (rep->bandwidth > 0)
2146  av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0);
2147  if (rep->id[0])
2148  av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0);
2149  }
2150  for (i = 0; i < c->n_audios; i++) {
2151  rep = c->audios[i];
2153  rep->assoc_stream = s->streams[rep->stream_index];
2154  if (rep->bandwidth > 0)
2155  av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0);
2156  if (rep->id[0])
2157  av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0);
2158  if (rep->lang) {
2159  av_dict_set(&rep->assoc_stream->metadata, "language", rep->lang, 0);
2160  av_freep(&rep->lang);
2161  }
2162  }
2163  for (i = 0; i < c->n_subtitles; i++) {
2164  rep = c->subtitles[i];
2166  rep->assoc_stream = s->streams[rep->stream_index];
2167  if (rep->id[0])
2168  av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0);
2169  if (rep->lang) {
2170  av_dict_set(&rep->assoc_stream->metadata, "language", rep->lang, 0);
2171  av_freep(&rep->lang);
2172  }
2173  }
2174  }
2175 
2176  return 0;
2177 fail:
2178  return ret;
2179 }
2180 
2181 static void recheck_discard_flags(AVFormatContext *s, struct representation **p, int n)
2182 {
2183  int i, j;
2184 
2185  for (i = 0; i < n; i++) {
2186  struct representation *pls = p[i];
2187  int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL;
2188 
2189  if (needed && !pls->ctx) {
2190  pls->cur_seg_offset = 0;
2191  pls->init_sec_buf_read_offset = 0;
2192  /* Catch up */
2193  for (j = 0; j < n; j++) {
2194  pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no);
2195  }
2197  av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index);
2198  } else if (!needed && pls->ctx) {
2200  ff_format_io_close(pls->parent, &pls->input);
2201  av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index);
2202  }
2203  }
2204 }
2205 
2207 {
2208  DASHContext *c = s->priv_data;
2209  int ret = 0, i;
2210  int64_t mints = 0;
2211  struct representation *cur = NULL;
2212  struct representation *rep = NULL;
2213 
2214  recheck_discard_flags(s, c->videos, c->n_videos);
2215  recheck_discard_flags(s, c->audios, c->n_audios);
2216  recheck_discard_flags(s, c->subtitles, c->n_subtitles);
2217 
2218  for (i = 0; i < c->n_videos; i++) {
2219  rep = c->videos[i];
2220  if (!rep->ctx)
2221  continue;
2222  if (!cur || rep->cur_timestamp < mints) {
2223  cur = rep;
2224  mints = rep->cur_timestamp;
2225  }
2226  }
2227  for (i = 0; i < c->n_audios; i++) {
2228  rep = c->audios[i];
2229  if (!rep->ctx)
2230  continue;
2231  if (!cur || rep->cur_timestamp < mints) {
2232  cur = rep;
2233  mints = rep->cur_timestamp;
2234  }
2235  }
2236 
2237  for (i = 0; i < c->n_subtitles; i++) {
2238  rep = c->subtitles[i];
2239  if (!rep->ctx)
2240  continue;
2241  if (!cur || rep->cur_timestamp < mints) {
2242  cur = rep;
2243  mints = rep->cur_timestamp;
2244  }
2245  }
2246 
2247  if (!cur) {
2248  return AVERROR_INVALIDDATA;
2249  }
2250  while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
2251  ret = av_read_frame(cur->ctx, pkt);
2252  if (ret >= 0) {
2253  /* If we got a packet, return it */
2254  cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
2255  pkt->stream_index = cur->stream_index;
2256  return 0;
2257  }
2258  if (cur->is_restart_needed) {
2259  cur->cur_seg_offset = 0;
2260  cur->init_sec_buf_read_offset = 0;
2261  ff_format_io_close(cur->parent, &cur->input);
2263  cur->is_restart_needed = 0;
2264  }
2265  }
2266  return AVERROR_EOF;
2267 }
2268 
2270 {
2271  DASHContext *c = s->priv_data;
2272  free_audio_list(c);
2273  free_video_list(c);
2274  av_dict_free(&c->avio_opts);
2275  av_freep(&c->base_url);
2276  return 0;
2277 }
2278 
2279 static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
2280 {
2281  int ret = 0;
2282  int i = 0;
2283  int j = 0;
2284  int64_t duration = 0;
2285 
2286  av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d%s\n",
2287  seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : "");
2288 
2289  // single fragment mode
2290  if (pls->n_fragments == 1) {
2291  pls->cur_timestamp = 0;
2292  pls->cur_seg_offset = 0;
2293  if (dry_run)
2294  return 0;
2295  ff_read_frame_flush(pls->ctx);
2296  return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags);
2297  }
2298 
2299  ff_format_io_close(pls->parent, &pls->input);
2300 
2301  // find the nearest fragment
2302  if (pls->n_timelines > 0 && pls->fragment_timescale > 0) {
2303  int64_t num = pls->first_seq_no;
2304  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline start n_timelines[%d] "
2305  "last_seq_no[%"PRId64"], playlist %d.\n",
2306  (int)pls->n_timelines, (int64_t)pls->last_seq_no, (int)pls->rep_idx);
2307  for (i = 0; i < pls->n_timelines; i++) {
2308  if (pls->timelines[i]->starttime > 0) {
2309  duration = pls->timelines[i]->starttime;
2310  }
2311  duration += pls->timelines[i]->duration;
2312  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2313  goto set_seq_num;
2314  }
2315  for (j = 0; j < pls->timelines[i]->repeat; j++) {
2316  duration += pls->timelines[i]->duration;
2317  num++;
2318  if (seek_pos_msec < ((duration * 1000) / pls->fragment_timescale)) {
2319  goto set_seq_num;
2320  }
2321  }
2322  num++;
2323  }
2324 
2325 set_seq_num:
2326  pls->cur_seq_no = num > pls->last_seq_no ? pls->last_seq_no : num;
2327  av_log(pls->parent, AV_LOG_VERBOSE, "dash_seek with SegmentTimeline end cur_seq_no[%"PRId64"], playlist %d.\n",
2328  (int64_t)pls->cur_seq_no, (int)pls->rep_idx);
2329  } else if (pls->fragment_duration > 0) {
2330  pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000;
2331  } else {
2332  av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n");
2333  pls->cur_seq_no = pls->first_seq_no;
2334  }
2335  pls->cur_timestamp = 0;
2336  pls->cur_seg_offset = 0;
2337  pls->init_sec_buf_read_offset = 0;
2338  ret = dry_run ? 0 : reopen_demux_for_component(s, pls);
2339 
2340  return ret;
2341 }
2342 
2343 static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
2344 {
2345  int ret = 0, i;
2346  DASHContext *c = s->priv_data;
2347  int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000,
2348  s->streams[stream_index]->time_base.den,
2351  if ((flags & AVSEEK_FLAG_BYTE) || c->is_live)
2352  return AVERROR(ENOSYS);
2353 
2354  /* Seek in discarded streams with dry_run=1 to avoid reopening them */
2355  for (i = 0; i < c->n_videos; i++) {
2356  if (!ret)
2357  ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx);
2358  }
2359  for (i = 0; i < c->n_audios; i++) {
2360  if (!ret)
2361  ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
2362  }
2363  for (i = 0; i < c->n_subtitles; i++) {
2364  if (!ret)
2365  ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
2366  }
2367 
2368  return ret;
2369 }
2370 
2371 static int dash_probe(const AVProbeData *p)
2372 {
2373  if (!av_stristr(p->buf, "<MPD"))
2374  return 0;
2375 
2376  if (av_stristr(p->buf, "dash:profile:isoff-on-demand:2011") ||
2377  av_stristr(p->buf, "dash:profile:isoff-live:2011") ||
2378  av_stristr(p->buf, "dash:profile:isoff-live:2012") ||
2379  av_stristr(p->buf, "dash:profile:isoff-main:2011") ||
2380  av_stristr(p->buf, "3GPP:PSS:profile:DASH1")) {
2381  return AVPROBE_SCORE_MAX;
2382  }
2383  if (av_stristr(p->buf, "dash:profile")) {
2384  return AVPROBE_SCORE_MAX;
2385  }
2386 
2387  return 0;
2388 }
2389 
2390 #define OFFSET(x) offsetof(DASHContext, x)
2391 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
2392 static const AVOption dash_options[] = {
2393  {"allowed_extensions", "List of file extensions that dash is allowed to access",
2394  OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
2395  {.str = "aac,m4a,m4s,m4v,mov,mp4,webm,ts"},
2396  INT_MIN, INT_MAX, FLAGS},
2397  {NULL}
2398 };
2399 
2400 static const AVClass dash_class = {
2401  .class_name = "dash",
2402  .item_name = av_default_item_name,
2403  .option = dash_options,
2404  .version = LIBAVUTIL_VERSION_INT,
2405 };
2406 
2408  .name = "dash",
2409  .long_name = NULL_IF_CONFIG_SMALL("Dynamic Adaptive Streaming over HTTP"),
2410  .priv_class = &dash_class,
2411  .priv_data_size = sizeof(DASHContext),
2418 };
reopen_demux_for_component
static int reopen_demux_for_component(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1904
close_demux_for_component
static void close_demux_for_component(struct representation *pls)
Definition: dashdec.c:1894
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
calc_next_seg_no_from_timelines
static int64_t calc_next_seg_no_from_timelines(struct representation *pls, int64_t cur_time)
Definition: dashdec.c:290
AVFMT_NO_BYTE_SEEK
#define AVFMT_NO_BYTE_SEEK
Format does not allow seeking by bytes.
Definition: avformat.h:470
program
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C program
Definition: undefined.txt:6
open_demux_for_component
static int open_demux_for_component(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1978
read_data
static int read_data(void *opaque, uint8_t *buf, int buf_size)
Definition: dashdec.c:1794
representation::rep_idx
int rep_idx
Definition: dashdec.c:84
representation::start_number
int64_t start_number
Definition: dashdec.c:103
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4519
representation::type
enum AVMediaType type
Definition: dashdec.c:88
get_current_time_in_sec
static uint64_t get_current_time_in_sec(void)
Definition: dashdec.c:176
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
avio_close
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:1147
ishttp
static int ishttp(char *url)
Definition: dashdec.c:165
calc_min_seg_no
static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1443
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
FLAGS
#define FLAGS
Definition: dashdec.c:2391
av_stristr
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle.
Definition: avstring.c:56
representation::assoc_stream
AVStream * assoc_stream
Definition: dashdec.c:93
free_video_list
static void free_video_list(DASHContext *c)
Definition: dashdec.c:369
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:55
AVStream::discard
enum AVDiscard discard
Selects which packets can be discarded at will and do not need to be demuxed.
Definition: avformat.h:920
representation::init_sec_buf_read_offset
uint32_t init_sec_buf_read_offset
Definition: dashdec.c:120
representation::cur_seq_no
int64_t cur_seq_no
Definition: dashdec.c:110
get_current_fragment
static struct fragment * get_current_fragment(struct representation *pls)
Definition: dashdec.c:1614
DASHContext::n_subtitles
int n_subtitles
Definition: dashdec.c:133
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:213
representation::cur_seg_offset
int64_t cur_seg_offset
Definition: dashdec.c:111
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:26
dash_close
static int dash_close(AVFormatContext *s)
Definition: dashdec.c:2269
cleanup
static av_cold void cleanup(FlashSV2Context *s)
Definition: flashsv2enc.c:127
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1403
AVOption
AVOption.
Definition: opt.h:246
DASHContext::interrupt_callback
AVIOInterruptCB * interrupt_callback
Definition: dashdec.c:154
parse_manifest_segmenturlnode
static int parse_manifest_segmenturlnode(AVFormatContext *s, struct representation *rep, xmlNodePtr fragmenturl_node, xmlNodePtr *baseurl_nodes, char *rep_id_val, char *rep_bandwidth_val)
Definition: dashdec.c:601
AVFMT_FLAG_CUSTOM_IO
#define AVFMT_FLAG_CUSTOM_IO
The caller has supplied a custom AVIOContext, don't avio_close() it.
Definition: avformat.h:1474
AVSEEK_FLAG_BYTE
#define AVSEEK_FLAG_BYTE
seeking based on position in bytes
Definition: avformat.h:2497
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
DASHContext::n_audios
int n_audios
Definition: dashdec.c:131
AVDictionary
Definition: dict.c:30
representation::last_seq_no
int64_t last_seq_no
Definition: dashdec.c:102
AVFormatContext::probesize
int64_t probesize
Maximum size of the data read from input for determining the input container format.
Definition: avformat.h:1501
av_read_frame
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
Return the next frame of a stream.
Definition: utils.c:1773
read_from_url
static int read_from_url(struct representation *pls, struct fragment *seg, uint8_t *buf, int buf_size)
Definition: dashdec.c:1689
avio_size
int64_t avio_size(AVIOContext *s)
Get the filesize.
Definition: aviobuf.c:334
representation::n_fragments
int n_fragments
Definition: dashdec.c:95
DASHContext::availability_end_time
uint64_t availability_end_time
Definition: dashdec.c:140
find_child_node_by_name
static xmlNodePtr find_child_node_by_name(xmlNodePtr rootnode, const char *nodename)
Definition: dashdec.c:540
representation::first_seq_no
int64_t first_seq_no
Definition: dashdec.c:101
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
AVIOInterruptCB
Callback for checking whether to abort blocking functions.
Definition: avio.h:58
fragment
Definition: dashdec.c:35
ff_const59
#define ff_const59
The ff_const59 define is not part of the public API and will be removed without further warning.
Definition: avformat.h:535
DASHContext::n_videos
int n_videos
Definition: dashdec.c:129
DASHContext
Definition: dashdec.c:125
get_segment_start_time_based_on_timeline
static int64_t get_segment_start_time_based_on_timeline(struct representation *pls, int64_t cur_seq_no)
Definition: dashdec.c:255
DASHContext::subtitles
struct representation ** subtitles
Definition: dashdec.c:134
AVPROBE_SCORE_MAX
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:453
avformat_close_input
void avformat_close_input(AVFormatContext **s)
Close an opened input AVFormatContext.
Definition: utils.c:4491
avio_open2
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:1141
representation::init_section
struct fragment * init_section
Definition: dashdec.c:116
finish
static void finish(void)
Definition: movenc.c:345
DASHContext::publish_time
uint64_t publish_time
Definition: dashdec.c:141
free_timelines_list
static void free_timelines_list(struct representation *pls)
Definition: dashdec.c:340
calc_max_seg_no
static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c)
Definition: dashdec.c:1457
free_fragment
static void free_fragment(struct fragment **seg)
Definition: dashdec.c:320
fail
#define fail()
Definition: checkasm.h:123
calc_cur_seg_no
static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls)
Definition: dashdec.c:1405
read_seek
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags)
Definition: libcdio.c:153
read_close
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
val
static double val(void *priv, double ch)
Definition: aeval.c:76
recheck_discard_flags
static void recheck_discard_flags(AVFormatContext *s, struct representation **p, int n)
Definition: dashdec.c:2181
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
dynarray_add
#define dynarray_add(tab, nb_ptr, elem)
Definition: internal.h:197
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:83
av_timegm
time_t av_timegm(struct tm *tm)
Convert the decomposed UTC time in tm to a time_t value.
Definition: parseutils.c:568
av_new_program
AVProgram * av_new_program(AVFormatContext *s, int id)
Definition: utils.c:4618
get_utc_date_time_insec
static uint64_t get_utc_date_time_insec(AVFormatContext *s, const char *datetime)
Definition: dashdec.c:181
get_content_type
static enum AVMediaType get_content_type(xmlNodePtr node)
Definition: dashdec.c:557
ff_check_interrupt
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition: avio.c:663
AVRational::num
int num
Numerator.
Definition: rational.h:59
dash_options
static const AVOption dash_options[]
Definition: dashdec.c:2392
DASHContext::avio_opts
AVDictionary * avio_opts
Definition: dashdec.c:156
AV_DICT_DONT_STRDUP_VAL
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition: dict.h:74
DASHContext::suggested_presentation_delay
uint64_t suggested_presentation_delay
Definition: dashdec.c:138
seek_data
static int64_t seek_data(void *opaque, int64_t offset, int whence)
Definition: dashdec.c:1784
aligned
static int aligned(int val)
Definition: dashdec.c:171
representation::n_timelines
int n_timelines
Definition: dashdec.c:98
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:202
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
AVInputFormat
Definition: avformat.h:636
free_representation
static void free_representation(struct representation *pls)
Definition: dashdec.c:351
duration
int64_t duration
Definition: movenc.c:63
DASHContext::max_url_size
int max_url_size
Definition: dashdec.c:157
DASHContext::allowed_extensions
char * allowed_extensions
Definition: dashdec.c:155
intreadwrite.h
move_segments
static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
Definition: dashdec.c:1497
s
#define s(width, name)
Definition: cbs_vp9.c:257
fragment::url_offset
int64_t url_offset
Definition: dashdec.c:36
DASHContext::adaptionset_lang
char * adaptionset_lang
Definition: dashdec.c:151
avio_read_to_bprint
int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size)
Read contents of h into print buffer, up to max_size bytes, or up to EOF.
Definition: aviobuf.c:1228
av_seek_frame
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Seek to the keyframe at timestamp.
Definition: utils.c:2520
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1466
AVInputFormat::name
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:641
free_fragment_list
static void free_fragment_list(struct representation *pls)
Definition: dashdec.c:329
AVProbeData::buf
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:443
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:184
av_match_ext
int av_match_ext(const char *filename, const char *extensions)
Return a positive value if the given filename has one of the given extensions, 0 otherwise.
Definition: format.c:38
representation::is_restart_needed
int is_restart_needed
Definition: dashdec.c:122
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
parse_programinformation
static int parse_programinformation(AVFormatContext *s, xmlNodePtr node)
Definition: dashdec.c:1189
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
get_duration_insec
static uint32_t get_duration_insec(AVFormatContext *s, const char *duration)
Definition: dashdec.c:211
DASHContext::videos
struct representation ** videos
Definition: dashdec.c:130
INITIAL_BUFFER_SIZE
#define INITIAL_BUFFER_SIZE
Definition: dashdec.c:31
representation::cur_timestamp
int64_t cur_timestamp
Definition: dashdec.c:121
timeline::duration
int64_t duration
Definition: dashdec.c:69
representation::init_sec_buf_size
uint32_t init_sec_buf_size
Definition: dashdec.c:118
representation::stream_index
int stream_index
Definition: dashdec.c:86
int32_t
int32_t
Definition: audio_convert.c:194
AVFormatContext::max_analyze_duration
int64_t max_analyze_duration
Maximum duration (in AV_TIME_BASE units) of the data read from input in avformat_find_stream_info().
Definition: avformat.h:1509
representation::ctx
AVFormatContext * ctx
Definition: dashdec.c:82
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: avcodec.h:236
AVFormatContext
Format I/O context.
Definition: avformat.h:1335
representation::lang
char * lang
Definition: dashdec.c:90
internal.h
opts
AVDictionary * opts
Definition: movenc.c:50
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1012
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
hours
FFmpeg Automated Testing Environment ************************************Introduction Using FATE from your FFmpeg source directory Submitting the results to the FFmpeg result aggregation server Uploading new samples to the fate suite FATE makefile targets and variables Makefile targets Makefile variables Examples Introduction **************FATE is an extended regression suite on the client side and a means for results aggregation and presentation on the server side The first part of this document explains how you can use FATE from your FFmpeg source directory to test your ffmpeg binary The second part describes how you can run FATE to submit the results to FFmpeg’s FATE server In any way you can have a look at the publicly viewable FATE results by visiting this as it can be seen if some test on some platform broke with their recent contribution This usually happens on the platforms the developers could not test on The second part of this document describes how you can run FATE to submit your results to FFmpeg’s FATE server If you want to submit your results be sure to check that your combination of OS and compiler is not already listed on the above mentioned website In the third part you can find a comprehensive listing of FATE makefile targets and variables Using FATE from your FFmpeg source directory **********************************************If you want to run FATE on your machine you need to have the samples in place You can get the samples via the build target fate rsync Use this command from the top level source this will cause FATE to fail NOTE To use a custom wrapper to run the pass ‘ target exec’ to ‘configure’ or set the TARGET_EXEC Make variable Submitting the results to the FFmpeg result aggregation server ****************************************************************To submit your results to the server you should run fate through the shell script ‘tests fate sh’ from the FFmpeg sources This script needs to be invoked with a configuration file as its first argument tests fate sh path to fate_config A configuration file template with comments describing the individual configuration variables can be found at ‘doc fate_config sh template’ Create a configuration that suits your based on the configuration template The ‘slot’ configuration variable can be any string that is not yet but it is suggested that you name it adhering to the following pattern ‘ARCH OS COMPILER COMPILER VERSION’ The configuration file itself will be sourced in a shell therefore all shell features may be used This enables you to setup the environment as you need it for your build For your first test runs the ‘fate_recv’ variable should be empty or commented out This will run everything as normal except that it will omit the submission of the results to the server The following files should be present in $workdir as specified in the configuration it may help to try out the ‘ssh’ command with one or more ‘ v’ options You should get detailed output concerning your SSH configuration and the authentication process The only thing left is to automate the execution of the fate sh script and the synchronisation of the samples directory Uploading new samples to the fate suite *****************************************If you need a sample uploaded send a mail to samples request This is for developers who have an account on the fate suite server If you upload new please make sure they are as small as space on each network bandwidth and so on benefit from smaller test cases Also keep in mind older checkouts use existing sample that means in practice generally do not remove or overwrite files as it likely would break older checkouts or releases Also all needed samples for a commit should be ideally hours
Definition: fate.txt:145
AVSEEK_FLAG_BACKWARD
#define AVSEEK_FLAG_BACKWARD
Definition: avformat.h:2496
read_header
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:527
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
MAX_MANIFEST_SIZE
#define MAX_MANIFEST_SIZE
Definition: dashdec.c:32
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:894
NULL
#define NULL
Definition: coverity.c:32
read_probe
static int read_probe(const AVProbeData *pd)
Definition: jvdec.c:55
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_strireplace
char * av_strireplace(const char *str, const char *from, const char *to)
Locale-independent strings replace.
Definition: avstring.c:235
is_common_init_section_exist
static int is_common_init_section_exist(struct representation **pls, int n_pls)
Definition: dashdec.c:2011
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
dash_read_seek
static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
Definition: dashdec.c:2343
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1377
parseutils.h
AVProbeData
This structure contains the data a format has to probe a file.
Definition: avformat.h:441
move_timelines
static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c)
Definition: dashdec.c:1483
representation::timelines
struct timeline ** timelines
Definition: dashdec.c:99
AVStream::metadata
AVDictionary * metadata
Definition: avformat.h:929
DASHContext::minimum_update_period
uint64_t minimum_update_period
Definition: dashdec.c:142
time.h
open_url
static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, AVDictionary *opts, AVDictionary *opts2, int *is_http)
Definition: dashdec.c:402
timeline::starttime
int64_t starttime
Definition: dashdec.c:59
DASHContext::period_start
uint64_t period_start
Definition: dashdec.c:148
parse_manifest
static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
Definition: dashdec.c:1218
representation::url_template
char * url_template
Definition: dashdec.c:78
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVFormatContext::nb_streams
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1391
get_val_from_nodes_tab
static char * get_val_from_nodes_tab(xmlNodePtr *nodes, const int n_nodes, const char *attrname)
Definition: dashdec.c:524
av_strncasecmp
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:223
av_rescale_rnd
int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd)
Rescale a 64-bit integer with specified rounding.
Definition: mathematics.c:58
DASHContext::time_shift_buffer_depth
uint64_t time_shift_buffer_depth
Definition: dashdec.c:143
avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
Read packets of a media file to get stream information.
Definition: utils.c:3615
AVIOContext
Bytestream IO Context.
Definition: avio.h:161
resolve_content_path
static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes)
Definition: dashdec.c:704
ffio_init_context
int ffio_init_context(AVIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition: aviobuf.c:76
AVMediaType
AVMediaType
Definition: avutil.h:199
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:186
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:144
DASHContext::media_presentation_duration
uint64_t media_presentation_duration
Definition: dashdec.c:137
AVIOContext::seekable
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:260
representation::pb
AVIOContext pb
Definition: dashdec.c:79
start_time
static int64_t start_time
Definition: ffplay.c:332
FFMAX
#define FFMAX(a, b)
Definition: common.h:94
avpriv_set_pts_info
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4938
ff_copy_whiteblacklists
int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src)
Copies the whilelists from one context to the other.
Definition: utils.c:159
size
int size
Definition: twinvq_data.h:11134
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
representation::bandwidth
int bandwidth
Definition: dashdec.c:91
representation::parent
AVFormatContext * parent
Definition: dashdec.c:81
representation::rep_count
int rep_count
Definition: dashdec.c:85
AVMEDIA_TYPE_UNKNOWN
@ AVMEDIA_TYPE_UNKNOWN
Usually treated as AVMEDIA_TYPE_DATA.
Definition: avutil.h:200
OFFSET
#define OFFSET(x)
Definition: dashdec.c:2390
AV_OPT_SEARCH_CHILDREN
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:558
copy_init_section
static int copy_init_section(struct representation *rep_dest, struct representation *rep_src)
Definition: dashdec.c:2033
DASHContext::availability_start_time
uint64_t availability_start_time
Definition: dashdec.c:139
ff_dash_demuxer
AVInputFormat ff_dash_demuxer
Definition: dashdec.c:2407
representation::init_sec_data_len
uint32_t init_sec_data_len
Definition: dashdec.c:119
dash_read_header
static int dash_read_header(AVFormatContext *s)
Definition: dashdec.c:2049
FFMIN
#define FFMIN(a, b)
Definition: common.h:96
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
free_audio_list
static void free_audio_list(DASHContext *c)
Definition: dashdec.c:380
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:203
representation::framerate
AVRational framerate
Definition: dashdec.c:92
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:34
representation::id
char id[20]
Definition: dashdec.c:89
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
av_parse_video_rate
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
Definition: parseutils.c:179
in
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
Definition: audio_convert.c:326
free_subtitle_list
static void free_subtitle_list(DASHContext *c)
Definition: dashdec.c:391
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:348
avio_internal.h
avformat_open_input
int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options)
Open an input stream and read the header.
Definition: utils.c:533
dash_probe
static int dash_probe(const AVProbeData *p)
Definition: dashdec.c:2371
AV_TIME_BASE
#define AV_TIME_BASE
Internal time base represented as integer.
Definition: avutil.h:254
DASHContext::audios
struct representation ** audios
Definition: dashdec.c:132
representation::fragment_timescale
int64_t fragment_timescale
Definition: dashdec.c:106
needed
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is needed
Definition: filter_design.txt:212
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:82
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
DASHContext::is_init_section_common_audio
int is_init_section_common_audio
Definition: dashdec.c:161
parse_manifest_adaptationset
static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, xmlNodePtr period_baseurl_node, xmlNodePtr period_segmenttemplate_node, xmlNodePtr period_segmentlist_node)
Definition: dashdec.c:1134
uint8_t
uint8_t
Definition: audio_convert.c:194
fragment::url
char * url
Definition: dashdec.c:38
AVProgram
New fields can be added to the end with minor version bumps.
Definition: avformat.h:1257
save_avio_options
static int save_avio_options(AVFormatContext *s)
Definition: dashdec.c:1857
av_rescale
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
DASHContext::min_buffer_time
uint64_t min_buffer_time
Definition: dashdec.c:144
nested_io_open
static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **opts)
Definition: dashdec.c:1884
DASHContext::is_live
int is_live
Definition: dashdec.c:153
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:872
ret
ret
Definition: filter_design.txt:187
read_packet
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
AVStream
Stream structure.
Definition: avformat.h:865
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:241
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
av_strlcat
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes,...
Definition: avstring.c:93
representation::input
AVIOContext * input
Definition: dashdec.c:80
get_Fragment
static struct fragment * get_Fragment(char *range)
Definition: dashdec.c:583
parse_manifest_segmenttimeline
static int parse_manifest_segmenttimeline(AVFormatContext *s, struct representation *rep, xmlNodePtr fragment_timeline_node)
Definition: dashdec.c:668
ff_make_absolute_url
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
representation
Definition: dashdec.c:77
representation::init_sec_buf
uint8_t * init_sec_buf
Definition: dashdec.c:117
avcodec_parameters_copy
int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src)
Copy the contents of src to dst.
Definition: utils.c:2064
MAX_URL_SIZE
#define MAX_URL_SIZE
Definition: internal.h:30
parse_manifest_adaptationset_attr
static int parse_manifest_adaptationset_attr(AVFormatContext *s, xmlNodePtr adaptionset_node)
Definition: dashdec.c:1121
pkt
static AVPacket pkt
Definition: demuxing_decoding.c:54
AVRational::den
int den
Denominator.
Definition: rational.h:60
representation::cur_seg
struct fragment * cur_seg
Definition: dashdec.c:113
get_content_url
static char * get_content_url(xmlNodePtr *baseurl_nodes, int n_baseurl_nodes, int max_url_size, char *rep_id_val, char *rep_bandwidth_val, char *val)
Definition: dashdec.c:468
DASHContext::is_init_section_common_video
int is_init_section_common_video
Definition: dashdec.c:160
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4448
avio_read
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:625
AVStream::r_frame_rate
AVRational r_frame_rate
Real base framerate of the stream.
Definition: avformat.h:989
refresh_manifest
static int refresh_manifest(AVFormatContext *s)
Definition: dashdec.c:1515
AVFormatContext::io_open
int(* io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
A callback for opening new IO streams.
Definition: avformat.h:1917
update_init_section
static int update_init_section(struct representation *pls)
Definition: dashdec.c:1737
parse_manifest_representation
static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr node, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, xmlNodePtr period_baseurl_node, xmlNodePtr period_segmenttemplate_node, xmlNodePtr period_segmentlist_node, xmlNodePtr fragment_template_node, xmlNodePtr content_component_node, xmlNodePtr adaptionset_baseurl_node, xmlNodePtr adaptionset_segmentlist_node, xmlNodePtr adaptionset_supplementalproperty_node)
Definition: dashdec.c:823
AVPacket::stream_index
int stream_index
Definition: packet.h:357
dash_read_packet
static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dashdec.c:2206
open_input
static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg)
Definition: dashdec.c:1705
timeline
Definition: dashdec.c:46
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
av_dict_set_int
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set that converts the value to a string and stores it.
Definition: dict.c:147
ff_format_io_close
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: utils.c:5685
representation::cur_seg_size
int64_t cur_seg_size
Definition: dashdec.c:112
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:674
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVIOContext::buffer
unsigned char * buffer
Start of the buffer.
Definition: avio.h:226
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
av_probe_input_buffer
int av_probe_input_buffer(AVIOContext *pb, ff_const59 AVInputFormat **fmt, const char *url, void *logctx, unsigned int offset, unsigned int max_probe_size)
Like av_probe_input_buffer2() but returns 0 on success.
Definition: format.c:312
AVPacket
This structure stores compressed data.
Definition: packet.h:332
ff_read_frame_flush
void ff_read_frame_flush(AVFormatContext *s)
Flush the frame reader.
Definition: utils.c:1924
ff_dash_fill_tmpl_params
void ff_dash_fill_tmpl_params(char *dst, size_t buffer_size, const char *template, int rep_id, int number, int bit_rate, int64_t time)
Definition: dash.c:96
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
av_fast_malloc
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
Allocate a buffer, reusing the given one if large enough.
Definition: mem.c:502
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:217
representation::fragment_duration
int64_t fragment_duration
Definition: dashdec.c:105
avio_find_protocol_name
const char * avio_find_protocol_name(const char *url)
Return the name of the protocol that will handle the passed URL.
Definition: avio.c:472
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:564
av_strlcpy
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:83
av_opt_get
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:779
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
dash_seek
static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run)
Definition: dashdec.c:2279
representation::pkt
AVPacket pkt
Definition: dashdec.c:83
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:56
timeline::repeat
int64_t repeat
Definition: dashdec.c:65
dash.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Definition: opt.h:227
DASHContext::base_url
char * base_url
Definition: dashdec.c:127
AVStream::pts_wrap_bits
int pts_wrap_bits
number of bits in pts (used for wrapping control)
Definition: avformat.h:1057
int
int
Definition: ffmpeg_filter.c:192
representation::fragments
struct fragment ** fragments
Definition: dashdec.c:96
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1363
dash_class
static const AVClass dash_class
Definition: dashdec.c:2400
DASHContext::period_duration
uint64_t period_duration
Definition: dashdec.c:147
representation::presentation_timeoffset
int64_t presentation_timeoffset
Definition: dashdec.c:108
fragment::size
int64_t size
Definition: dashdec.c:37
DEFAULT_MANIFEST_SIZE
#define DEFAULT_MANIFEST_SIZE
Definition: dashdec.c:33
avio_feof
int avio_feof(AVIOContext *s)
Similar to feof() but also returns nonzero on read errors.
Definition: aviobuf.c:356
av_program_add_stream_index
void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx)