From fb9a32977d6abf4c83a92d993af58e393819c062 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 2 Feb 2017 18:24:27 +0100 Subject: stream: get rid of streamtype enum Because it's kind of dumb. (But not sure if it was worth the trouble.) For stream_file.c, we add new explicit fields. The rest are rather special uses and can be killed by comparing the stream impl. name. The changes to DVD/BD/CD/TV are entirely untested. --- demux/demux_edl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'demux/demux_edl.c') diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 623cae35b3..240c224ab7 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -50,6 +50,7 @@ struct tl_parts { struct priv { bstr data; + bool allow_any; }; // Parse a time (absolute file time or duration). Currently equivalent to a @@ -286,8 +287,7 @@ static void build_mpv_edl_timeline(struct timeline *tl) return; } MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, tl->demuxer); - // Source is .edl and not edl:// => don't allow arbitrary paths - if (tl->demuxer->stream->uncached_type != STREAMTYPE_EDL) + if (!p->allow_any) fix_filenames(parts, tl->demuxer->filename); build_timeline(tl, parts); talloc_free(parts); @@ -303,8 +303,10 @@ static int try_open_file(struct demuxer *demuxer, enum demux_check check) demuxer->fully_read = true; struct stream *s = demuxer->stream; - if (s->uncached_type == STREAMTYPE_EDL) { + if (s->info && strcmp(s->info->name, "edl") == 0) { p->data = bstr0(s->path); + // Source is edl:// and not .edl => allow arbitrary paths + p->allow_any = true; return 0; } if (check >= DEMUX_CHECK_UNSAFE) { -- cgit v1.2.3 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_edl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'demux/demux_edl.c') diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 240c224ab7..65a18a1a41 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -254,6 +254,8 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) }; starttime += part->length; + + tl->demuxer->is_network |= source->is_network; } tl->parts[parts->num_parts] = (struct timeline_part) {.start = starttime}; tl->num_parts = parts->num_parts; -- 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_edl.c | 138 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 36 deletions(-) (limited to 'demux/demux_edl.c') diff --git a/demux/demux_edl.c b/demux/demux_edl.c index 65a18a1a41..fad73f7644 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -44,6 +44,8 @@ struct tl_part { }; struct tl_parts { + bool dash; + char *init_fragment_url; struct tl_part *parts; int num_parts; }; @@ -65,6 +67,8 @@ static bool parse_time(bstr str, double *out_time) return true; } +#define MAX_PARAMS 10 + /* Returns a list of parts, or NULL on parse error. * Syntax (without file header or URI prefix): * url ::= ( (';' | '\n') )* @@ -79,7 +83,10 @@ static struct tl_parts *parse_edl(bstr str) bstr_split_tok(str, "\n", &(bstr){0}, &str); if (bstr_eatstart0(&str, "\n") || bstr_eatstart0(&str, ";")) continue; + bool is_header = bstr_eatstart0(&str, "!"); struct tl_part p = { .length = -1 }; + bstr param_names[MAX_PARAMS]; + bstr param_vals[MAX_PARAMS]; int nparam = 0; while (1) { bstr name, val; @@ -117,10 +124,25 @@ static struct tl_parts *parse_edl(bstr str) if (bstr_equals0(val, "chapters")) p.chapter_ts = true; } + if (nparam >= MAX_PARAMS) + goto error; + param_names[nparam] = name; + param_vals[nparam] = val; nparam++; if (!bstr_eatstart0(&str, ",")) break; } + if (is_header) { + if (tl->num_parts) + goto error; // can't have header once an entry was defined + bstr type = param_vals[0]; // value, because no "=" + if (bstr_equals0(type, "mp4_dash")) { + tl->dash = true; + if (bstr_equals0(param_names[1], "init")) + tl->init_fragment_url = bstrto0(tl, param_vals[1]); + } + continue; + } if (!p.filename) goto error; MP_TARRAY_APPEND(tl, tl->parts, tl->num_parts, p); @@ -140,7 +162,10 @@ static struct demuxer *open_source(struct timeline *tl, char *filename) if (strcmp(d->stream->url, filename) == 0) return d; } - struct demuxer *d = demux_open_url(filename, NULL, tl->cancel, tl->global); + struct demuxer_params params = { + .init_fragment = tl->init_fragment, + }; + struct demuxer *d = demux_open_url(filename, ¶ms, tl->cancel, tl->global); if (d) { MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, d); } else { @@ -203,63 +228,104 @@ static void resolve_timestamps(struct tl_part *part, struct demuxer *demuxer) static void build_timeline(struct timeline *tl, struct tl_parts *parts) { + tl->track_layout = NULL; + tl->dash = parts->dash; + + if (parts->init_fragment_url && parts->init_fragment_url[0]) { + MP_VERBOSE(tl, "Opening init fragment...\n"); + stream_t *s = stream_create(parts->init_fragment_url, STREAM_READ, + tl->cancel, tl->global); + if (s) + tl->init_fragment = stream_read_complete(s, tl, 1000000); + free_stream(s); + if (!tl->init_fragment.len) { + MP_ERR(tl, "Could not read init fragment.\n"); + goto error; + } + s = open_memory_stream(tl->init_fragment.start, tl->init_fragment.len); + tl->track_layout = demux_open(s, NULL, tl->global); + if (!tl->track_layout) { + free_stream(s); + MP_ERR(tl, "Could not demux init fragment.\n"); + goto error; + } + } + tl->parts = talloc_array_ptrtype(tl, tl->parts, parts->num_parts + 1); double starttime = 0; for (int n = 0; n < parts->num_parts; n++) { struct tl_part *part = &parts->parts[n]; - struct demuxer *source = open_source(tl, part->filename); - if (!source) - goto error; + struct demuxer *source = NULL; - resolve_timestamps(part, source); + if (tl->dash) { + part->offset = starttime; + if (part->length <= 0) + MP_WARN(tl, "Segment %d has unknown duration.\n", n); + if (part->offset_set) + MP_WARN(tl, "Offsets are ignored.\n"); + tl->demuxer->is_network = true; + } else { + MP_VERBOSE(tl, "Opening segment %d...\n", n); - double end_time = source_get_length(source); - if (end_time >= 0) - end_time += source->start_time; + source = open_source(tl, part->filename); + if (!source) + goto error; - // Unknown length => use rest of the file. If duration is unknown, make - // something up. - if (part->length < 0) { - if (end_time < 0) { - MP_WARN(tl, "EDL: source file '%s' has unknown duration.\n", - part->filename); - end_time = 1; - } - part->length = end_time - part->offset; - } else if (end_time >= 0) { - double end_part = part->offset + part->length; - if (end_part > end_time) { - MP_WARN(tl, "EDL: entry %d uses %f " - "seconds, but file has only %f seconds.\n", - n, end_part, end_time); + resolve_timestamps(part, source); + + double end_time = source_get_length(source); + if (end_time >= 0) + end_time += source->start_time; + + // Unknown length => use rest of the file. If duration is unknown, make + // something up. + if (part->length < 0) { + if (end_time < 0) { + MP_WARN(tl, "EDL: source file '%s' has unknown duration.\n", + part->filename); + end_time = 1; + } + part->length = end_time - part->offset; + } else if (end_time >= 0) { + double end_part = part->offset + part->length; + if (end_part > end_time) { + MP_WARN(tl, "EDL: entry %d uses %f " + "seconds, but file has only %f seconds.\n", + n, end_part, end_time); + } } - } - // Add a chapter between each file. - struct demux_chapter ch = { - .pts = starttime, - .metadata = talloc_zero(tl, struct mp_tags), - }; - mp_tags_set_str(ch.metadata, "title", part->filename); - MP_TARRAY_APPEND(tl, tl->chapters, tl->num_chapters, ch); + // Add a chapter between each file. + struct demux_chapter ch = { + .pts = starttime, + .metadata = talloc_zero(tl, struct mp_tags), + }; + mp_tags_set_str(ch.metadata, "title", part->filename); + MP_TARRAY_APPEND(tl, tl->chapters, tl->num_chapters, ch); - // Also copy the source file's chapters for the relevant parts - copy_chapters(&tl->chapters, &tl->num_chapters, source, part->offset, - part->length, starttime); + // Also copy the source file's chapters for the relevant parts + copy_chapters(&tl->chapters, &tl->num_chapters, source, part->offset, + part->length, starttime); + } tl->parts[n] = (struct timeline_part) { .start = starttime, .source_start = part->offset, .source = source, + .url = talloc_strdup(tl, part->filename), }; starttime += part->length; - tl->demuxer->is_network |= source->is_network; + if (source) { + tl->demuxer->is_network |= source->is_network; + + if (!tl->track_layout) + tl->track_layout = source; + } } tl->parts[parts->num_parts] = (struct timeline_part) {.start = starttime}; tl->num_parts = parts->num_parts; - tl->track_layout = tl->parts[0].source; return; error: -- cgit v1.2.3 From 92f9747c2bd28816824e8edfa503a65bc500f20c Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 5 Feb 2017 15:51:36 +0100 Subject: demux_edl: fix behavior with no init segment provided Not that we use it... --- demux/demux_edl.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'demux/demux_edl.c') diff --git a/demux/demux_edl.c b/demux/demux_edl.c index fad73f7644..8b6f402b27 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -264,6 +264,12 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) if (part->offset_set) MP_WARN(tl, "Offsets are ignored.\n"); tl->demuxer->is_network = true; + + if (!tl->track_layout) { + source = open_source(tl, part->filename); + if (!source) + goto error; + } } else { MP_VERBOSE(tl, "Opening segment %d...\n", n); -- cgit v1.2.3