2013-11-19 21:23:41 +00:00
|
|
|
EDL files
|
|
|
|
=========
|
|
|
|
|
|
|
|
EDL files basically concatenate ranges of video/audio from multiple source
|
|
|
|
files into a single continuous virtual file. Each such range is called a
|
|
|
|
segment, and consists of source file, source offset, and segment length.
|
|
|
|
|
|
|
|
For example::
|
|
|
|
|
2013-11-21 14:59:00 +00:00
|
|
|
# mpv EDL v0
|
2013-11-19 21:23:41 +00:00
|
|
|
f1.mkv,10,20
|
|
|
|
f2.mkv
|
|
|
|
f1.mkv,40,10
|
|
|
|
|
|
|
|
This would skip the first 10 seconds of the file f1.mkv, then play the next
|
|
|
|
20 seconds, then switch to the file f2.mkv and play all of it, then switch
|
|
|
|
back to f1.mkv, skip to the 40 second mark, and play 10 seconds, and then
|
|
|
|
stop playback. The difference to specifying the files directly on command
|
|
|
|
line (and using ``--{ --start=10 --length=20 f1.mkv --}`` etc.) is that the
|
2013-12-05 19:16:15 +00:00
|
|
|
virtual EDL file appears as a virtual timeline (like a single file), instead
|
|
|
|
as a playlist.
|
2013-11-19 21:23:41 +00:00
|
|
|
|
2013-12-05 19:16:15 +00:00
|
|
|
The general simplified syntax is::
|
2013-11-19 21:23:41 +00:00
|
|
|
|
2013-11-21 14:59:00 +00:00
|
|
|
# mpv EDL v0
|
2013-11-19 21:23:41 +00:00
|
|
|
<filename>
|
|
|
|
<filename>,<start in seconds>,<length in seconds>
|
|
|
|
|
|
|
|
If the start time is omitted, 0 is used. If the length is omitted, the
|
2014-10-11 23:32:42 +00:00
|
|
|
estimated remaining duration of the source file is used.
|
2013-11-19 21:23:41 +00:00
|
|
|
|
|
|
|
Note::
|
|
|
|
|
2016-02-20 15:22:15 +00:00
|
|
|
Usage of relative or absolute paths as well as any protocol prefixes may be
|
|
|
|
prevented for security reasons.
|
2013-11-19 21:23:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
Syntax of mpv EDL files
|
|
|
|
=======================
|
|
|
|
|
|
|
|
Generally, the format is relatively strict. No superfluous whitespace (except
|
|
|
|
empty lines and commented lines) are allowed. You must use UNIX line breaks.
|
|
|
|
|
2013-11-21 14:59:00 +00:00
|
|
|
The first line in the file must be ``# mpv EDL v0``. This designates that the
|
2013-11-19 21:23:41 +00:00
|
|
|
file uses format version 0, which is not frozen yet and may change any time.
|
|
|
|
(If you need a stable EDL file format, make a feature request. Likewise, if
|
|
|
|
you have suggestions for improvements, it's not too late yet.)
|
|
|
|
|
|
|
|
The rest of the lines belong to one of these classes:
|
|
|
|
|
|
|
|
1) An empty or commented line. A comment starts with ``#``, which must be the
|
|
|
|
first character in the line. The rest of the line (up until the next line
|
|
|
|
break) is ignored. An empty line has 0 bytes between two line feed bytes.
|
2017-01-30 18:38:43 +00:00
|
|
|
2) A header entry if the line starts with ``!``.
|
|
|
|
3) A segment entry in all other cases.
|
2013-11-19 21:23:41 +00:00
|
|
|
|
|
|
|
Each segment entry consists of a list of named or unnamed parameters.
|
|
|
|
Parameters are separated with ``,``. Named parameters consist of a name,
|
|
|
|
followed by ``=``, followed by the value. Unnamed parameters have only a
|
|
|
|
value, and the name is implicit from the parameter position.
|
|
|
|
|
|
|
|
Syntax::
|
|
|
|
|
|
|
|
segment_entry ::= <param> ( <param> ',' )*
|
|
|
|
param ::= [ <name> '=' ] ( <value> | '%' <number> '%' <valuebytes> )
|
|
|
|
|
2017-01-30 18:38:43 +00:00
|
|
|
The ``name`` string can consist of any characters, except ``=%,;\n!``. The
|
|
|
|
``value`` string can consist of any characters except of ``,;\n!``.
|
2013-11-19 21:23:41 +00:00
|
|
|
|
|
|
|
The construct starting with ``%`` allows defining any value with arbitrary
|
|
|
|
contents inline, where ``number`` is an integer giving the number of bytes in
|
|
|
|
``valuebytes``. If a parameter value contains disallowed characters, it has to
|
|
|
|
be guarded by a length specifier using this syntax.
|
|
|
|
|
|
|
|
The parameter name defines the meaning of the parameter:
|
|
|
|
|
|
|
|
1) ``file``, the source file to use for this segment.
|
|
|
|
2) ``start``, a time value that specifies the start offset into the source file.
|
|
|
|
3) ``length``, a time value that specifies the length of the segment.
|
|
|
|
|
2014-02-18 23:06:00 +00:00
|
|
|
See the section below for the format of timestamps.
|
2013-11-19 21:23:41 +00:00
|
|
|
|
|
|
|
Unnamed parameters carry implicit names. The parameter position determines
|
|
|
|
which of the parameters listed above is set. For example, the second parameter
|
|
|
|
implicitly uses the name ``start``.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
2013-11-21 14:59:00 +00:00
|
|
|
# mpv EDL v0
|
2013-11-19 21:23:41 +00:00
|
|
|
%18%filename,with,.mkv,10,length=20,param3=%13%value,escaped,param4=value2
|
|
|
|
|
|
|
|
this sets ``file`` to ``filename,with,.mkv``, ``start`` to ``10``, ``length``
|
|
|
|
to ``20``, ``param3`` to ``value,escaped``, ``param4`` to ``value2``.
|
|
|
|
|
|
|
|
Instead of line breaks, the character ``;`` can be used. Line feed bytes and
|
|
|
|
``;`` are treated equally.
|
2013-11-19 21:26:35 +00:00
|
|
|
|
2017-01-30 18:38:43 +00:00
|
|
|
Header entries start with ``!`` as first character after a line break. Header
|
|
|
|
entries affect all other file entries in the EDL file. Their format is highly
|
|
|
|
implementation specific. They should generally follow the file header, and come
|
|
|
|
before any file entries.
|
|
|
|
|
2019-01-05 07:43:58 +00:00
|
|
|
Disabling chapter generation and copying
|
|
|
|
========================================
|
|
|
|
|
|
|
|
By default, chapters from the source ranges are copied to the virtual file's
|
|
|
|
chapters. Also, a chapter is inserted after each range. This can be disabled
|
|
|
|
with the ``no_chapters`` header.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
!no_chapters
|
|
|
|
|
|
|
|
|
2017-01-30 18:38:43 +00:00
|
|
|
MP4 DASH
|
|
|
|
========
|
|
|
|
|
|
|
|
This is a header that helps implementing DASH, although it only provides a low
|
|
|
|
level mechanism.
|
|
|
|
|
|
|
|
If this header is set, the given url designates an mp4 init fragment. It's
|
|
|
|
downloaded, and every URL in the EDL is prefixed with the init fragment on the
|
|
|
|
byte stream level. This is mostly for use by mpv's internal ytdl support. The
|
|
|
|
ytdl script will call youtube-dl, which in turn actually processes DASH
|
|
|
|
manifests. It may work only for this very specific purpose and fail to be
|
2017-02-05 15:02:58 +00:00
|
|
|
useful in other scenarios. It can be removed or changed in incompatible ways
|
2017-01-30 18:38:43 +00:00
|
|
|
at any times.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
!mp4_dash,init=url
|
|
|
|
|
|
|
|
The ``url`` is encoded as parameter value as defined in the general EDL syntax.
|
|
|
|
It's expected to point to an "initialization fragment", which will be prefixed
|
|
|
|
to every entry in the EDL on the byte stream level.
|
|
|
|
|
|
|
|
The current implementation will
|
|
|
|
|
|
|
|
- ignore stream start times
|
|
|
|
- use durations as hint for seeking only
|
|
|
|
- not adjust source timestamps
|
|
|
|
- open and close segments (i.e. fragments) as needed
|
|
|
|
- not add segment boundaries as chapter points
|
|
|
|
- require full compatibility between all segments (same codec etc.)
|
|
|
|
|
2019-01-11 11:07:55 +00:00
|
|
|
Another header part of this mechanism is ``no_clip``. This header is similar
|
|
|
|
to ``mp4_dash``, but does not include on-demand opening/closing of segments,
|
|
|
|
and does not support init segments. It also exists solely to support internal
|
|
|
|
ytdl requirements.
|
|
|
|
|
2019-01-11 14:18:28 +00:00
|
|
|
The ``mp4_dash`` and ``no_clip`` headers are not part of the core EDL format.
|
|
|
|
They may be changed or removed at any time, depending on mpv's internal
|
|
|
|
requirements.
|
|
|
|
|
demux, demux_edl: add extension for tracks sourced from separate streams
This commit adds an extension to mpv EDL, which basically allows you to
do the same as --audio-file, --external-file, etc. in a single EDL file.
This is a relatively quick & dirty implementation. The dirty part lies
in the fact that several shortcuts are taken. For example, struct
timeline now forms a singly linked list, which is really weird, but also
means the other timeline using demuxers (cue, mkv) don't need to be
touched. Also, memory management becomes even worse (weird object
ownership rules that are just fragile WTFs). There are some other
dubious small changes, mostly related to the weird representation of
separate streams.
demux_timeline.c contains the actual implementation of the separate
stream handling. For the most part, most things that used to be on the
top level are now in struct virtual_source, of which one for each
separate stream exists. This is basically like running multiple
demux_edl.c in parallel. Some changes could strictly speaking be split
into a separate commit, such as the stream_map type change.
Mostly untested. Seems to work for the intended purpose. Potential for
regressions for other timeline uses (like ordered chapters) is probably
low. One thing which could definitely break and which I didn't test is
the pseudo-DASH fragmented EDL code, of which ytdl can trigger various
forms in obscure situations. (Uh why don't we have a test suite.)
Background:
The intention is to use this for the ytdl wrapper. A certain streaming
site from a particularly brain damaged and plain evil Silicon Valley
company usually provides streams as separate audio and video streams.
The ytdl wrapper simply does use audio-add (i.e. adding it as external
track, like with --audio-file), which works mostly fine. Unfortunately,
mpv manages caching completely separately for external files. This has
the following potential problems:
1. Seek ranges are rendered incorrectly. They always use the "main"
stream, in this case the video stream. E.g. clicking into a cached range
on the OSC could trigger a low level seek if the audio stream is
actually not cached at the target position.
2. The stream cache bloats unnecessarily. Each stream may allocate the
full configured maximum cache size, which is not what the user intends
to do. Cached ranges are not pruned the same way, which creates disjoint
cache ranges, which only use memory and won't help with fast seeking or
playback.
3. mpv will try to aggressively read from both streams. This is done
from different threads, with no regard which stream is more important.
So it might happen that one stream starves the other one, especially if
they have different bitrates.
4. Every stream will use a separate thread, which is an unnecessary
waste of system resources.
In theory, the following solutions are available (this commit works
towards D):
A. Centrally manage reading and caching of all streams. A single thread
would do all I/O, and decide from which stream it should read next. As
long as the total TCP/socket buffering is not too high, this should be
effective to avoid starvation issues. This can also manage the cached
ranges better. It would also get rid of the quite useless additional
demuxer threads. This solution is conceptually simple, but requires
refactoring the entire demuxer middle layer.
B. Attempt to coordinate the demuxer threads. This would maintain a
shared cache and readahead state to solve the mentioned problems
explicitly. While this sounds simple and like an incremental change,
it's probably hard to implement, creates more messy special cases,
solution A. seems just a better and simpler variant of this. (On the
other hand, A. requires refactoring more code.)
C. Render an intersection of the seek ranges across all streams. This
fixes only problem 1.
D. Merge all streams in a dedicated wrapper demuxer. The general demuxer
layer remains unchanged, and reading from separate streams is handled as
special case. This effectively achieves the same as A. In particular,
caching is simply handled by the usual demuxer cache layer, which sees
the wrapper demuxer as a single stream of interleaved packets. One
implementation variant of this is to reuse the EDL infrastructure, which
this commit does.
All in all, solution A would be preferable, because it's cleaner and
works for all external streams in general.
Some previous commit tried to prepare for implementing solution A. This
could still happen. But it could take years until this is finally
seriously started and finished. In any case, this commit doesn't block
or complicate such attempts, which is also why it's the way to go.
It's worth mentioning that original mplayer handles external files by
creating a wrapper demuxer. This is like a less ideal mixture of A. and
D. (The similarity with A. is that extending the mplayer approach to be
fully dynamic and without certain disadvantages caused by the wrapper
would end up with A. anyway. The similarity with D. is that due to the
wrapper, no higher level code needs to be changed.)
2019-01-04 12:09:02 +00:00
|
|
|
Separate files for tracks
|
|
|
|
=========================
|
|
|
|
|
|
|
|
The special ``new_stream`` header lets you specify separate parts and time
|
|
|
|
offsets for separate tracks. This can for example be used to source audio and
|
|
|
|
video track from separate files.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
# mpv EDL v0
|
|
|
|
video.mkv
|
|
|
|
!new_stream
|
|
|
|
audio.mkv
|
|
|
|
|
|
|
|
This adds all tracks from both files to the virtual track list. Upon playback,
|
|
|
|
the tracks will be played at the same time, instead of appending them. The files
|
|
|
|
can contain more than 1 stream; the apparent effect is the same as if the second
|
|
|
|
part after the ``!new_stream`` part were in a separate ``.edl`` file and added
|
|
|
|
with ``--external-file``.
|
|
|
|
|
|
|
|
Note that all metadata between the stream sets created by ``new_stream`` is
|
|
|
|
disjoint. Global metadata is taken from the first part only.
|
|
|
|
|
|
|
|
In context of mpv, this is redundant to the ``--audio-file`` and
|
|
|
|
``--external-file`` options, but (as of this writing) has the advantage that
|
|
|
|
this will use a unified cache for all streams.
|
|
|
|
|
2019-01-11 14:18:28 +00:00
|
|
|
The ``new_stream`` header is not part of the core EDL format. It may be changed
|
|
|
|
or removed at any time, depending on mpv's internal requirements.
|
|
|
|
|
2014-02-18 23:06:00 +00:00
|
|
|
Timestamp format
|
|
|
|
================
|
|
|
|
|
|
|
|
Currently, time values are floating point values in seconds.
|
|
|
|
|
|
|
|
As an extension, you can set the ``timestamps=chapters`` option. If this option
|
|
|
|
is set, timestamps have to be integers, and refer to chapter numbers, starting
|
|
|
|
with 0.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
# mpv EDL v0
|
|
|
|
file.mkv,2,4,timestamps=chapters
|
|
|
|
|
|
|
|
Plays chapter 3 and ends with the start of chapter 7 (4 chapters later).
|
|
|
|
|
2018-07-31 17:46:19 +00:00
|
|
|
Implicit chapters
|
|
|
|
=================
|
|
|
|
|
|
|
|
mpv will add one chapter per segment entry to the virtual timeline.
|
|
|
|
|
|
|
|
By default, the chapter's titles will match the entries' filenames.
|
|
|
|
You can override set the ``title`` option to override the chapter title for
|
|
|
|
that segment.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
# mpv EDL v0
|
|
|
|
cap.ts,5,240
|
|
|
|
OP.mkv,0,90,title=Show Opening
|
|
|
|
|
|
|
|
The virtual timeline will have two chapters, one called "cap.ts" from 0-240s
|
|
|
|
and a second one called "Show Opening" from 240-330s.
|
|
|
|
|
2013-11-19 21:26:35 +00:00
|
|
|
Syntax of EDL URIs
|
|
|
|
==================
|
|
|
|
|
2013-12-05 19:16:15 +00:00
|
|
|
mpv accepts inline EDL data in form of ``edl://`` URIs. Other than the
|
2013-11-19 21:26:35 +00:00
|
|
|
header, the syntax is exactly the same. It's far more convenient to use ``;``
|
|
|
|
instead of line breaks, but that is orthogonal.
|
|
|
|
|
|
|
|
Example: ``edl://f1.mkv,length=5,start=10;f2.mkv,30,20;f3.mkv``
|
2019-01-04 11:31:24 +00:00
|
|
|
|
|
|
|
As a quirks, mpv will accept arbitrary paths in EDLs originating from
|
|
|
|
``edl://``, while ``.edl`` does not. This makes no sense.
|