From 95d4c2d7f61155633e89c18e740e7cf743a655d6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 2 Feb 2017 18:38:16 +0100 Subject: player: different way to auto-enable the demuxer cache Instead of enabling it only when a stream-cache is enabled, also try to enable it independently from that if the demuxer is marked as is_network. Also add some code to the EDL code, so EDLs containing network streams are automatically cached this way. Extend the OSD info line so that it shows the demuxer cache in this case (more or less). I didn't find where or whether options.rst describes how the demuxer cache is enabled, so no changes there. --- demux/demux_timeline.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'demux/demux_timeline.c') diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index 8784dcf8f6..afd7eb5247 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -352,6 +352,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; -- cgit v1.2.3 From 97680bf6041a0512c929c927024b38235a35ce55 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 30 Jan 2017 16:16:13 +0100 Subject: demux_timeline: move code around Cosmetic preparation for later changes. --- demux/demux_timeline.c | 82 +++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'demux/demux_timeline.c') diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index afd7eb5247..c640965809 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -65,6 +65,47 @@ 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; + + 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; @@ -247,47 +288,6 @@ static void print_timeline(struct demuxer *demuxer) 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; - } -} - static int d_open(struct demuxer *demuxer, enum demux_check check) { struct priv *p = demuxer->priv = talloc_zero(demuxer, struct priv); -- cgit v1.2.3 From 61202bb3640740d2cb98cf13922dcdf67970d5ef Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 30 Jan 2017 19:38:43 +0100 Subject: ytdl_hook, edl: implement pseudo-DASH support We use the metadata provided by youtube-dl to sort-of implement fragmented DASH streaming. This is all a bit hacky, but hopefully a makeshift solution until libavformat has proper mechanisms. (Although in danger of being one of those temporary hacks that become permanent.) --- demux/demux_timeline.c | 98 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 18 deletions(-) (limited to 'demux/demux_timeline.c') diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index c640965809..4b3eb93d0d 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; @@ -79,6 +83,9 @@ 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); @@ -118,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) @@ -130,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) + 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; @@ -141,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]; @@ -170,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) @@ -178,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) @@ -217,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) @@ -255,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); @@ -273,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; } @@ -283,9 +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); + + 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; @@ -363,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); } -- cgit v1.2.3 From 8362577f8c44cf447c31ed7f30ce62cce3e95a30 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 4 Feb 2017 23:10:04 +0100 Subject: demux_timeline: more silencing --- demux/demux_timeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'demux/demux_timeline.c') diff --git a/demux/demux_timeline.c b/demux/demux_timeline.c index 4b3eb93d0d..3759c9ffc1 100644 --- a/demux/demux_timeline.c +++ b/demux/demux_timeline.c @@ -169,7 +169,7 @@ static void reopen_lazy_segments(struct demuxer *demuxer) }; p->current->d = demux_open_url(p->current->url, ¶ms, demuxer->stream->cancel, demuxer->global); - if (!p->current->d) + if (!p->current->d && !demux_cancel_test(demuxer)) MP_ERR(demuxer, "failed to load segment\n"); associate_streams(demuxer, p->current); } -- cgit v1.2.3