summaryrefslogtreecommitdiffstats
path: root/demux/demux_edl.c
diff options
context:
space:
mode:
Diffstat (limited to 'demux/demux_edl.c')
-rw-r--r--demux/demux_edl.c152
1 files changed, 114 insertions, 38 deletions
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 623cae35b3..8b6f402b27 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -44,12 +44,15 @@ struct tl_part {
};
struct tl_parts {
+ bool dash;
+ char *init_fragment_url;
struct tl_part *parts;
int num_parts;
};
struct priv {
bstr data;
+ bool allow_any;
};
// Parse a time (absolute file time or duration). Currently equivalent to a
@@ -64,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 ::= <entry> ( (';' | '\n') <entry> )*
@@ -78,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;
@@ -116,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);
@@ -139,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, &params, tl->cancel, tl->global);
if (d) {
MP_TARRAY_APPEND(tl, tl->sources, tl->num_sources, d);
} else {
@@ -202,61 +228,110 @@ 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;
-
- resolve_timestamps(part, source);
+ struct demuxer *source = NULL;
- double end_time = source_get_length(source);
- if (end_time >= 0)
- end_time += source->start_time;
+ 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;
- // 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;
+ if (!tl->track_layout) {
+ source = open_source(tl, part->filename);
+ if (!source)
+ goto error;
}
- 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);
+ } else {
+ MP_VERBOSE(tl, "Opening segment %d...\n", n);
+
+ source = open_source(tl, part->filename);
+ if (!source)
+ goto error;
+
+ 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;
+
+ 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:
@@ -286,8 +361,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 +377,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) {