diff options
Diffstat (limited to 'demux/demux_edl.c')
-rw-r--r-- | demux/demux_edl.c | 128 |
1 files changed, 68 insertions, 60 deletions
diff --git a/demux/demux_edl.c b/demux/demux_edl.c index bfd5cb6dad..1f27a971a9 100644 --- a/demux/demux_edl.c +++ b/demux/demux_edl.c @@ -53,6 +53,11 @@ struct tl_parts { struct tl_parts *next; }; +struct tl_root { + struct tl_parts **pars; + int num_pars; +}; + struct priv { bstr data; bool allow_any; @@ -70,16 +75,23 @@ static bool parse_time(bstr str, double *out_time) return true; } +static struct tl_parts *add_part(struct tl_root *root) +{ + struct tl_parts *tl = talloc_zero(root, struct tl_parts); + MP_TARRAY_APPEND(root, root->pars, root->num_pars, tl); + return tl; +} + /* Returns a list of parts, or NULL on parse error. * Syntax (without file header or URI prefix): * url ::= <entry> ( (';' | '\n') <entry> )* * entry ::= <param> ( <param> ',' )* * param ::= [<string> '='] (<string> | '%' <number> '%' <bytes>) */ -static struct tl_parts *parse_edl(bstr str) +static struct tl_root *parse_edl(bstr str) { - struct tl_parts *tl = talloc_zero(NULL, struct tl_parts); - struct tl_parts *root = tl; + struct tl_root *root = talloc_zero(NULL, struct tl_root); + struct tl_parts *tl = add_part(root); while (str.len) { if (bstr_eatstart0(&str, "#")) { bstr_split_tok(str, "\n", &(bstr){0}, &str); @@ -153,9 +165,7 @@ static struct tl_parts *parse_edl(bstr str) } else if (bstr_equals0(f_type, "no_clip")) { tl->no_clip = true; } else if (bstr_equals0(f_type, "new_stream")) { - struct tl_parts *ntl = talloc_zero(tl, struct tl_parts); - tl->next = ntl; - tl = ntl; + tl = add_part(root); } else if (bstr_equals0(f_type, "no_chapters")) { tl->disable_chapters = true; } else { @@ -167,29 +177,35 @@ static struct tl_parts *parse_edl(bstr str) MP_TARRAY_APPEND(tl, tl->parts, tl->num_parts, p); } } - if (!root->num_parts) + if (!root->num_pars) goto error; + for (int n = 0; n < root->num_pars; n++) { + if (root->pars[n]->num_parts < 1) + goto error; + } return root; error: talloc_free(root); return NULL; } -static struct demuxer *open_source(struct timeline *tl, char *filename) +static struct demuxer *open_source(struct timeline *root, + struct timeline_par *tl, char *filename) { - for (int n = 0; n < tl->num_sources; n++) { - struct demuxer *d = tl->sources[n]; - if (strcmp(d->stream->url, filename) == 0) + for (int n = 0; n < tl->num_parts; n++) { + struct demuxer *d = tl->parts[n].source; + if (d && strcmp(d->stream->url, filename) == 0) return d; } struct demuxer_params params = { .init_fragment = tl->init_fragment, }; - struct demuxer *d = demux_open_url(filename, ¶ms, tl->cancel, tl->global); + struct demuxer *d = demux_open_url(filename, ¶ms, root->cancel, + root->global); if (d) { - MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, d); + MP_TARRAY_APPEND(root, root->sources, root->num_sources, d); } else { - MP_ERR(tl, "EDL: Could not open source file '%s'.\n", filename); + MP_ERR(root, "EDL: Could not open source file '%s'.\n", filename); } return d; } @@ -236,35 +252,38 @@ static void resolve_timestamps(struct tl_part *part, struct demuxer *demuxer) part->offset = demuxer->start_time; } -static void build_timeline(struct timeline *tl, struct tl_parts *parts) +static bool build_timeline(struct timeline *root, struct tl_parts *parts) { + struct timeline_par *tl = talloc_zero(root, struct timeline_par); + MP_TARRAY_APPEND(root, root->pars, root->num_pars, tl); + tl->track_layout = NULL; tl->dash = parts->dash; tl->no_clip = parts->no_clip; if (parts->init_fragment_url && parts->init_fragment_url[0]) { - MP_VERBOSE(tl, "Opening init fragment...\n"); + MP_VERBOSE(root, "Opening init fragment...\n"); stream_t *s = stream_create(parts->init_fragment_url, STREAM_READ, - tl->cancel, tl->global); + root->cancel, root->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"); + MP_ERR(root, "Could not read init fragment.\n"); goto error; } struct demuxer_params params = { .init_fragment = tl->init_fragment, }; - tl->track_layout = demux_open_url("memory://", ¶ms, tl->cancel, - tl->global); + tl->track_layout = demux_open_url("memory://", ¶ms, root->cancel, + root->global); if (!tl->track_layout) { - MP_ERR(tl, "Could not demux init fragment.\n"); + MP_ERR(root, "Could not demux init fragment.\n"); goto error; } } - tl->parts = talloc_array_ptrtype(tl, tl->parts, parts->num_parts + 1); + tl->parts = talloc_array_ptrtype(tl, tl->parts, parts->num_parts); double starttime = 0; for (int n = 0; n < parts->num_parts; n++) { struct tl_part *part = &parts->parts[n]; @@ -273,21 +292,16 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) if (tl->dash) { part->offset = starttime; if (part->length <= 0) - MP_WARN(tl, "Segment %d has unknown duration.\n", n); + MP_WARN(root, "Segment %d has unknown duration.\n", n); if (part->offset_set) - MP_WARN(tl, "Offsets are ignored.\n"); - if (tl->demuxer) - tl->demuxer->is_network = true; + MP_WARN(root, "Offsets are ignored.\n"); - if (!tl->track_layout) { - tl->track_layout = open_source(tl, part->filename); - if (!tl->track_layout) - goto error; - } + if (!tl->track_layout) + tl->track_layout = open_source(root, tl, part->filename); } else { - MP_VERBOSE(tl, "Opening segment %d...\n", n); + MP_VERBOSE(root, "Opening segment %d...\n", n); - source = open_source(tl, part->filename); + source = open_source(root, tl, part->filename); if (!source) goto error; @@ -301,7 +315,7 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) // something up. if (part->length < 0) { if (end_time < 0) { - MP_WARN(tl, "EDL: source file '%s' has unknown duration.\n", + MP_WARN(root, "EDL: source file '%s' has unknown duration.\n", part->filename); end_time = 1; } @@ -309,7 +323,7 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) } 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 " + MP_WARN(root, "EDL: entry %d uses %f " "seconds, but file has only %f seconds.\n", n, end_part, end_time); } @@ -323,33 +337,39 @@ static void build_timeline(struct timeline *tl, struct tl_parts *parts) }; mp_tags_set_str(ch.metadata, "title", part->title ? part->title : part->filename); - MP_TARRAY_APPEND(tl, tl->chapters, tl->num_chapters, ch); + MP_TARRAY_APPEND(root, root->chapters, root->num_chapters, ch); // Also copy the source file's chapters for the relevant parts - copy_chapters(&tl->chapters, &tl->num_chapters, source, + copy_chapters(&root->chapters, &root->num_chapters, source, part->offset, part->length, starttime); } } tl->parts[n] = (struct timeline_part) { .start = starttime, + .end = starttime + part->length, .source_start = part->offset, .source = source, .url = talloc_strdup(tl, part->filename), }; - starttime += part->length; + starttime = tl->parts[n].end; if (source && !tl->track_layout) tl->track_layout = source; } - tl->parts[parts->num_parts] = (struct timeline_part) {.start = starttime}; + + if (!tl->track_layout) + goto error; + if (!root->meta) + root->meta = tl->track_layout; + tl->num_parts = parts->num_parts; - return; + return true; error: - tl->num_parts = 0; - tl->num_chapters = 0; + root->num_pars = 0; + return false; } // For security, don't allow relative or absolute paths, only plain filenames. @@ -368,30 +388,18 @@ static void build_mpv_edl_timeline(struct timeline *tl) { struct priv *p = tl->demuxer->priv; - struct timeline *root_tl = tl; - struct tl_parts *root = parse_edl(p->data); + struct tl_root *root = parse_edl(p->data); if (!root) { MP_ERR(tl, "Error in EDL.\n"); return; } - for (struct tl_parts *parts = root; parts; parts = parts->next) { - if (tl->demuxer) - MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, tl->demuxer); + for (int n = 0; n < root->num_pars; n++) { + struct tl_parts *parts = root->pars[n]; if (!p->allow_any) - fix_filenames(parts, root_tl->demuxer->filename); - build_timeline(tl, parts); - - if (parts->next) { - struct timeline *ntl = talloc_zero(tl, struct timeline); - *ntl = (struct timeline) { - .global = tl->global, - .log = tl->log, - .cancel = tl->cancel, - }; - tl->next = ntl; - tl = ntl; - } + fix_filenames(parts, tl->demuxer->filename); + if (!build_timeline(tl, parts)) + break; } talloc_free(root); } |