Coverage Report

Created: 2026-07-25 07:52

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