summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/edl-mpv.rst30
-rw-r--r--demux/demux_edl.c18
2 files changed, 47 insertions, 1 deletions
diff --git a/DOCS/edl-mpv.rst b/DOCS/edl-mpv.rst
index ec8dce01cc..c5771c2bca 100644
--- a/DOCS/edl-mpv.rst
+++ b/DOCS/edl-mpv.rst
@@ -216,6 +216,36 @@ Example::
The virtual timeline will have two chapters, one called "cap.ts" from 0-240s
and a second one called "Show Opening" from 240-330s.
+Entry which defines the track layout
+====================================
+
+Normally, you're supposed to put only files with compatible layouts into an EDL
+file. However, at least the mpv implementation accepts entries that use
+different codecs, or even have a different number of audio/video/subtitle
+tracks. In this case, it's not obvious, which virtual tracks the EDL show should
+expose when being played.
+
+Currently, mpv will apply an arbitrary heuristic which tracks the EDL file
+should expose. (Before mpv 0.30.0, it always used the first source file in the
+segment list.)
+
+You can set the ``layout`` option to ``this`` to make a specific entry define
+the track layout.
+
+Example::
+
+ # mpv EDL v0
+ file_with_2_streams.ts,5,240
+ file_with_5_streams.mkv,0,90,layout=this
+
+The way the different virtual EDL tracks are associated with the per-segment
+ones is highly implementation-defined, and uses a heuristic. If a segment is
+missing a track, there will be a "hole", and bad behavior may result. Improving
+this is subject to further development (due to being fringe cases, they don't
+have a high priority).
+
+If future versions of mpv change this again, this option may be ignored.
+
Syntax of EDL URIs
==================
diff --git a/demux/demux_edl.c b/demux/demux_edl.c
index 205d607427..7016df3558 100644
--- a/demux/demux_edl.c
+++ b/demux/demux_edl.c
@@ -40,6 +40,7 @@ struct tl_part {
double offset; // offset into the source file
bool offset_set;
bool chapter_ts;
+ bool is_layout;
double length; // length of the part (-1 if rest of the file)
char *title;
};
@@ -151,6 +152,9 @@ static struct tl_root *parse_edl(bstr str)
p.chapter_ts = true;
} else if (bstr_equals0(name, "title")) {
p.title = bstrto0(tl, val);
+ } else if (bstr_equals0(name, "layout")) {
+ if (bstr_equals0(val, "this"))
+ p.is_layout = true;
}
}
nparam++;
@@ -357,10 +361,22 @@ static struct timeline_par *build_timeline(struct timeline *root,
starttime = tl->parts[n].end;
- if (source && !tl->track_layout)
+ if (source && !tl->track_layout && part->is_layout)
tl->track_layout = source;
}
+ if (!tl->track_layout) {
+ // Use a heuristic to select the "broadest" part as layout.
+ for (int n = 0; n < parts->num_parts; n++) {
+ struct demuxer *s = tl->parts[n].source;
+ if (!s)
+ continue;
+ if (!tl->track_layout ||
+ demux_get_num_stream(s) > demux_get_num_stream(tl->track_layout))
+ tl->track_layout = s;
+ }
+ }
+
if (!tl->track_layout)
goto error;
if (!root->meta)