diff options
Diffstat (limited to 'demux/demux_timeline.c')
-rw-r--r-- | demux/demux_timeline.c | 180 |
1 files changed, 122 insertions, 58 deletions
diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index 8784dcf8f6..3759c9ffc1 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -24,11 +24,14 @@ #include "demux.h" #include "timeline.h" #include "stheader.h" +#include "stream/stream.h" struct segment { int index; double start, end; double d_start; + char *url; + bool lazy; struct demuxer *d; // stream_map[sh_stream.index] = index into priv.streams, where sh_stream // is a stream from the source d. It's used to map the streams of the @@ -51,6 +54,7 @@ struct priv { struct timeline *tl; double duration; + bool dash; struct segment **segments; int num_segments; @@ -65,6 +69,50 @@ struct priv { int eos_packets; }; +static bool target_stream_used(struct segment *seg, int target_index) +{ + for (int n = 0; n < seg->num_stream_map; n++) { + if (seg->stream_map[n] == target_index) + return true; + } + return false; +} + +// Create mapping from segment streams to virtual timeline streams. +static void associate_streams(struct demuxer *demuxer, struct segment *seg) +{ + struct priv *p = demuxer->priv; + + if (!seg->d || seg->stream_map) + return; + + int counts[STREAM_TYPE_COUNT] = {0}; + + int num_streams = demux_get_num_stream(seg->d); + for (int n = 0; n < num_streams; n++) { + struct sh_stream *sh = demux_get_stream(seg->d, n); + // Try associating by demuxer ID (supposedly useful for ordered chapters). + struct sh_stream *other = + demuxer_stream_by_demuxer_id(demuxer, sh->type, sh->demuxer_id); + if (!other || !target_stream_used(seg, other->index)) { + // Try to associate the first unused stream with matching media type. + for (int i = 0; i < p->num_streams; i++) { + struct sh_stream *cur = p->streams[i].sh; + if (cur->type == sh->type && !target_stream_used(seg, cur->index)) + { + other = cur; + break; + } + } + } + + MP_TARRAY_APPEND(seg, seg->stream_map, seg->num_stream_map, + other ? other->index : -1); + + counts[sh->type] += 1; + } +} + static void reselect_streams(struct demuxer *demuxer) { struct priv *p = demuxer->priv; @@ -77,6 +125,9 @@ static void reselect_streams(struct demuxer *demuxer) for (int n = 0; n < p->num_segments; n++) { struct segment *seg = p->segments[n]; for (int i = 0; i < seg->num_stream_map; i++) { + if (!seg->d) + continue; + struct sh_stream *sh = demux_get_stream(seg->d, i); bool selected = false; if (seg->stream_map[i] >= 0) @@ -89,8 +140,42 @@ static void reselect_streams(struct demuxer *demuxer) } } +static void close_lazy_segments(struct demuxer *demuxer) +{ + struct priv *p = demuxer->priv; + + // unload previous segment + for (int n = 0; n < p->num_segments; n++) { + struct segment *seg = p->segments[n]; + if (seg != p->current && seg->d && seg->lazy) { + free_demuxer_and_stream(seg->d); + seg->d = NULL; + } + } +} + +static void reopen_lazy_segments(struct demuxer *demuxer) +{ + struct priv *p = demuxer->priv; + + if (p->current->d) + return; + + close_lazy_segments(demuxer); + + struct demuxer_params params = { + .init_fragment = p->tl->init_fragment, + .skip_lavf_probing = true, + }; + p->current->d = demux_open_url(p->current->url, ¶ms, + demuxer->stream->cancel, demuxer->global); + if (!p->current->d && !demux_cancel_test(demuxer)) + MP_ERR(demuxer, "failed to load segment\n"); + associate_streams(demuxer, p->current); +} + static void switch_segment(struct demuxer *demuxer, struct segment *new, - double start_pts, int flags) + double start_pts, int flags, bool init) { struct priv *p = demuxer->priv; @@ -100,9 +185,14 @@ static void switch_segment(struct demuxer *demuxer, struct segment *new, MP_VERBOSE(demuxer, "switch to segment %d\n", new->index); p->current = new; + reopen_lazy_segments(demuxer); + if (!new->d) + return; reselect_streams(demuxer); - demux_set_ts_offset(new->d, new->start - new->d_start); - demux_seek(new->d, start_pts, flags); + if (!p->dash) + demux_set_ts_offset(new->d, new->start - new->d_start); + if (!p->dash || !init) + demux_seek(new->d, start_pts, flags); for (int n = 0; n < p->num_streams; n++) { struct virtual_stream *vs = &p->streams[n]; @@ -129,7 +219,7 @@ static void d_seek(struct demuxer *demuxer, double seek_pts, int flags) } } - switch_segment(demuxer, new, pts, flags); + switch_segment(demuxer, new, pts, flags, false); } static int d_fill_buffer(struct demuxer *demuxer) @@ -137,9 +227,11 @@ static int d_fill_buffer(struct demuxer *demuxer) struct priv *p = demuxer->priv; if (!p->current) - switch_segment(demuxer, p->segments[0], 0, 0); + switch_segment(demuxer, p->segments[0], 0, 0, true); struct segment *seg = p->current; + if (!seg || !seg->d) + return 0; struct demux_packet *pkt = demux_read_any_packet(seg->d); if (!pkt || pkt->pts >= seg->end) @@ -176,20 +268,21 @@ static int d_fill_buffer(struct demuxer *demuxer) } if (!next) return 0; - switch_segment(demuxer, next, next->start, 0); + switch_segment(demuxer, next, next->start, 0, true); return 1; // reader will retry } if (pkt->stream < 0 || pkt->stream > seg->num_stream_map) goto drop; - if (!pkt->codec) - pkt->codec = demux_get_stream(seg->d, pkt->stream)->codec; - - if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start) - pkt->start = seg->start; - if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end) - pkt->end = seg->end; + if (!p->dash) { + if (!pkt->codec) + pkt->codec = demux_get_stream(seg->d, pkt->stream)->codec; + if (pkt->start == MP_NOPTS_VALUE || pkt->start < seg->start) + pkt->start = seg->start; + if (pkt->end == MP_NOPTS_VALUE || pkt->end > seg->end) + pkt->end = seg->end; + } pkt->stream = seg->stream_map[pkt->stream]; if (pkt->stream < 0) @@ -214,7 +307,8 @@ static int d_fill_buffer(struct demuxer *demuxer) } } - pkt->new_segment |= vs->new_segment; + if (!p->dash) + pkt->new_segment |= vs->new_segment; vs->new_segment = false; demux_add_packet(vs->sh, pkt); @@ -232,9 +326,9 @@ static void print_timeline(struct demuxer *demuxer) MP_VERBOSE(demuxer, "Timeline segments:\n"); for (int n = 0; n < p->num_segments; n++) { struct segment *seg = p->segments[n]; - int src_num = -1; - for (int i = 0; i < p->tl->num_sources; i++) { - if (p->tl->sources[i] == seg->d) { + int src_num = n; + for (int i = 0; i < n - 1; i++) { + if (seg->d && p->segments[i]->d == seg->d) { src_num = i; break; } @@ -242,50 +336,12 @@ static void print_timeline(struct demuxer *demuxer) MP_VERBOSE(demuxer, " %2d: %12f [%12f] (", n, seg->start, seg->d_start); for (int i = 0; i < seg->num_stream_map; i++) MP_VERBOSE(demuxer, "%s%d", i ? " " : "", seg->stream_map[i]); - MP_VERBOSE(demuxer, ") %d:'%s'\n", src_num, seg->d->filename); + MP_VERBOSE(demuxer, ") %d:'%s'\n", src_num, seg->url); } MP_VERBOSE(demuxer, "Total duration: %f\n", p->duration); -} -static bool target_stream_used(struct segment *seg, int target_index) -{ - for (int n = 0; n < seg->num_stream_map; n++) { - if (seg->stream_map[n] == target_index) - return true; - } - return false; -} - -// Create mapping from segment streams to virtual timeline streams. -static void associate_streams(struct demuxer *demuxer, struct segment *seg) -{ - struct priv *p = demuxer->priv; - - int counts[STREAM_TYPE_COUNT] = {0}; - - int num_streams = demux_get_num_stream(seg->d); - for (int n = 0; n < num_streams; n++) { - struct sh_stream *sh = demux_get_stream(seg->d, n); - // Try associating by demuxer ID (supposedly useful for ordered chapters). - struct sh_stream *other = - demuxer_stream_by_demuxer_id(demuxer, sh->type, sh->demuxer_id); - if (!other || !target_stream_used(seg, other->index)) { - // Try to associate the first unused stream with matching media type. - for (int i = 0; i < p->num_streams; i++) { - struct sh_stream *cur = p->streams[i].sh; - if (cur->type == sh->type && !target_stream_used(seg, cur->index)) - { - other = cur; - break; - } - } - } - - MP_TARRAY_APPEND(seg, seg->stream_map, seg->num_stream_map, - other ? other->index : -1); - - counts[sh->type] += 1; - } + if (p->dash) + MP_VERBOSE(demuxer, "Durations and offsets are non-authoritative.\n"); } static int d_open(struct demuxer *demuxer, enum demux_check check) @@ -334,6 +390,8 @@ static int d_open(struct demuxer *demuxer, enum demux_check check) struct segment *seg = talloc_ptrtype(p, seg); *seg = (struct segment){ .d = part->source, + .url = part->source ? part->source->filename : part->url, + .lazy = !part->source, .d_start = part->source_start, .start = part->start, .end = next->start, @@ -345,6 +403,8 @@ static int d_open(struct demuxer *demuxer, enum demux_check check) MP_TARRAY_APPEND(p, p->segments, p->num_segments, seg); } + p->dash = p->tl->dash; + print_timeline(demuxer); demuxer->seekable = true; @@ -352,6 +412,8 @@ static int d_open(struct demuxer *demuxer, enum demux_check check) demuxer->filetype = meta->filetype ? meta->filetype : meta->desc->name; + demuxer->is_network = p->tl->demuxer->is_network; + reselect_streams(demuxer); return 0; @@ -361,6 +423,8 @@ static void d_close(struct demuxer *demuxer) { struct priv *p = demuxer->priv; struct demuxer *master = p->tl->demuxer; + p->current = NULL; + close_lazy_segments(demuxer); timeline_destroy(p->tl); free_demuxer(master); } |