1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-31 15:59:34 +00:00
Commit Graph

36 Commits

Author SHA1 Message Date
wm4
319cbb0ed4 demux_timeline: include "dash" hint in reported file format 2019-01-05 14:25:16 +01:00
wm4
a747e987ca demux_timeline: disable end-of-segment handling in DASH mode
Normal EDL needs to clip packets coming from the underlying demuxer to
the segment range (including complicated stuff due to frame reordering).
This is unwanted In pseudo-DASH mode. A broken or subtly incorrect
manifest would lead to "bad stuff" happening. The intention of the
pseudo-DASH mode is to literally concatenate fragments.
2019-01-05 14:23:42 +01:00
wm4
aaa0e29f64 demux_timeline: fix network speed thing in dash mode
Quite obviously the code was stupid garbage.
2019-01-05 14:19:23 +01:00
wm4
4a00ec8419 demux_timeline: fix stream selection logic in DASH mode
There isn't necessarily a segment opened, but this does not mean no
stream is selected.
2019-01-05 14:17:48 +01:00
wm4
36b8b9c5aa demux_timeline: report network speed of slave connections
demux_timeline doesn't do any transport accesses itself. The slave
demuxers do this (these will actually access the stream layer and
perform e.g. network accesses). As a consequence, demux_timeline always
reported 0 bytes read, and network speed display didn't work.

Fix this by awkwardly reporting the amount of read bytes upwards. This
is not very nice, and requires explicit calls whenever the slave "might"
have read data.

Due to the way the reporting is done, it only works if the slaves do not
run demuxer threads, which makes things even less nice. (Fortunately
they don't anyway, because it would be a waste of resources.) Some
identifiers contain the word "hack" as a warning.

Some of the stupidity comes from the fact that demux.c itself resets the
stats randomly in order to calculate the bytes_per_second value, which
is useless for a slave, but of course is still done, because demux.c
itself is not aware of whether it's on the slave or top-level layer.

Unfortunately, this must do.

In theory, the demuxer thread/cache layer should be separated from
demuxer implementations. This would get rid of all the awkwardness and
nonsense. For example, the only threading involved would be the caching
layer, completely separate from demuxers themselves. It'd be the only
thing calculates speed rates for the player frontend, too (instead of
doing it for each demuxer, even if unused).
2019-01-05 09:11:18 +01:00
wm4
3903196883 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-05 09:11:18 +01:00
wm4
d3c7da53e8 demux: get rid of ->control callback
The only thing left is the notification for track switching. Just get
rid of that.

There's probably no real reason to get rid of control(), but why not. I
think I was actually trying to do some real work but fuck that.
2018-09-07 23:10:26 +02:00
wm4
283362f5c4 demux_timeline: fix off by one error, rearrange weird code
This code set pkt->stream to a value which I'm not sure whether it's
correct. A recent commit overwrote it with a value that is definitely
correct.

There appears to be an off by one error. No fucking clue whether this
was somehow correct, but applying an apparent fix does not seem to break
anything, so whatever.
2018-09-07 21:32:01 +02:00
wm4
59e78cb028 demux: return packets directly from demuxer instead of using sh_stream
Preparation for other potential changes to separate demuxer cache/thread
and actual demuxers.

Most things are untested, but it seems to work somewhat.
2018-09-07 15:20:32 +02:00
wm4
d33e5972b3 demux: get rid of free_demuxer[_and_stream]()
Them being separate is just dumb. Replace them with a single
demux_free() function, and free its stream by default. Not freeing the
stream is only needed in 1 special case (demux_disc.c), use a special
flag to not free the stream in this case.
2018-05-24 19:56:35 +02:00
wm4
f9713921a3 demux: add a "cancel" field
Instead of relying on demuxer->stream->cancel. This is better because
the stream is potentially closed and replaced.
2018-05-24 19:56:35 +02:00
wm4
b782c90180 demux_timeline: disable pointless packet cache for sub-demuxers
It seems like there's nothing stopping from sub-demuxers from keeping
packets in the cache, even if it's completely pointless. The top-most
demuxer (demux_timeline) already takes care of caching, so sub-demuxers
only waste space and time with this.

Add a function that can disable the packet cache even at runtime and
after packets are read. (It's not clear whether it really can happen
that packets are read before demux_timeline gets the sub-demuxers, but
there's no reason to make it too fragile.) Call it on all sub-demuxers.

For this to work, it seems we have to move the code for setting the
seekable_cache flag to before demux_timeline is potentially initialized,
because otherwise the cache would be reenabled if the demuxer triggering
timeline support is a timeline segment itself (e.g. ordered chapters).
2017-12-10 06:37:49 +02:00
wm4
ae8b531207 demux_timeline: don't use segments for DASH
Recent regression. Crashes because it sets the segmented flag, without
actually setting the fields required for segmentation.
2017-10-26 00:38:20 +02:00
wm4
374e3bd83c demux_timeline: trust attached picture flag
Fully fixes behavior of the files mentioned in the previous commit. Will
probably lead to worse behavior if someone tries to fix real video and
cover art tracks, but that's a broken fringe case anyway.
2017-10-25 16:39:33 +02:00
wm4
a5b51f75dc demux: get rid of demux_packet.new_segment field
The new_segment field was used to track the decoder data flow handler of
timeline boundaries, which are used for ordered chapters etc. (anything
that sets demuxer_desc.load_timeline). This broke seeking with the
demuxer cache enabled. The demuxer is expected to set the new_segment
field after every seek or segment boundary switch, so the cached packets
basically contained incorrect values for this, and the decoders were not
initialized correctly.

Fix this by getting rid of the flag completely. Let the decoders instead
compare the segment information by content, which is hopefully enough.
(In theory, two segments with same information could perhaps appear in
broken-ish corner cases, or in an attempt to simulate looping, and such.
I preferred the simple solution over others, such as generating unique
and stable segment IDs.)

We still add a "segmented" field to make it explicit whether segments
are used, instead of doing something silly like testing arbitrary other
segment fields for validity.

Cached seeking with timeline stuff is still slightly broken even with
this commit: the seek logic is not aware of the overlap that segments
can have, and the timestamp clamping that needs to be performed in
theory to account for the fact that a packet might contain a frame that
is always clipped off by segment handling. This can be fixed later.
2017-10-24 19:35:55 +02:00
wm4
bb9679d9a3 demux_timeline: change virtual_stream array to array of pointers
Needed for a failed thing, leaving it anyway because it causes no harm
and might be less awkward if struct virtual_stream is possibly extended
anyway in the future.
2017-10-24 19:24:20 +02:00
wm4
dbd22f43be demux: drop redundant SEEK_BACKWARD flag
Seems like most code dealing with this was for setting it in redundant
cases. Now SEEK_BACKWARD is redundant, and SEEK_FORWARD is the odd one
out.

Also fix that SEEK_FORWARD was not correctly unset in try_seek_cache().

In demux_mkv_seek(), make the arbitrary decision that a video stream is
not required for the subtitle prefetch logic to be active. We might want
subtitles with long duration even with audio only playback, or if the
file is used as external subtitle.
2017-10-23 19:05:39 +02:00
wm4
1890529857 demux: get rid of DEMUXER_CTRL_GET_TIME_LENGTH
Similar purpose as f34e1a0dee.

Somehow this is much more natural too, and needs less code.

This breaks runtime updates to duration. This could easily be fixed, but
no important demuxer does this anyway. Only demux_raw and demux_disc
might (the latter for BD/DVD). For the latter it might actually have
some importance when changing titles at runtime (I guess?), but guess
what, I don't care.
2017-06-20 14:22:10 +02:00
wm4
f34e1a0dee demux: replace custom return codes with CONTROL_ ones
This is more uniform, and potentially gets rid of some past copyrights.

It might be that this subtly changes caching behavior (it seems before
this, it synced to the demuxer if the length was unknown, which is not
what we want.)
2017-06-19 17:56:51 +02:00
wm4
8362577f8c demux_timeline: more silencing 2017-02-04 23:10:04 +01:00
wm4
61202bb364 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.)
2017-02-04 22:34:38 +01:00
wm4
97680bf604 demux_timeline: move code around
Cosmetic preparation for later changes.
2017-02-04 22:19:21 +01:00
wm4
95d4c2d7f6 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.
2017-02-02 18:38:16 +01:00
wm4
b787a4121a demux_timeline: always signal new segment after a seek
This is needed to put the decoders into the correct state. In
particular, decoders will not initialize the current segment without
this flag. The intention of not setting the flag for seeks within the
segments were to avoid costly decoder reinits, but it seems this is
better handled explicitly in the decoder wrappers.
2016-11-09 16:44:06 +01:00
wm4
39ae261cc5 demux_timeline: enable refresh seeks in some situations
Play a trick to make the packet pos field monotonically increasing over
segment boundaries if the source demuxers return monotonically
increasing pos values. This allows the demuxer to uniquely identify
packets with the pos field, and can do refresh seeks using that.

Normally, the packet pos field is used as a fallback for determining the
playback position if the demuxer returns no proper duration. But
demux_timeline.c always will, and the packet pos fields usually make no
sense in relation to the returned file size anyway if the timeline
source demuxers originate from separate streams.
2016-08-07 13:53:34 +02:00
wm4
d41f0a54b0 player: improve instant track switching
When switching tracks, we normally have the problem that data gets lost
due to readahead buffering. (Which in turn is because we're stubborn and
instruct the demuxers to discard data on unselected streams.) The
demuxer layer has a hack that re-reads discarded buffered data if a
stream is enabled mid-stream, so track switching will seem instant.

A somewhat similar problem is when all tracks of an external files were
disabled - when enabling the first track, we have to seek to the target
position.

Handle these with the same mechanism. Pass the "current time" to the
demuxer's stream switch function, and let the demuxer figure out what to
do. The demuxer will issue a refresh seek (if possible) to update the
new stream, or will issue a "normal" seek if there was no active stream
yet.

One case that changes is when a video/audio stream is enabled on an
external file with only a subtitle stream active, and the demuxer does
not support rrefresh seeks. This is a fuzzy case, because subtitles are
sparse, and the demuxer might have skipped large amounts of data. We
used to seek (and send the subtitle decoder some subtitle packets
twice). This case is sort of obscure and insane, and the fix would be
questionable, so we simply don't care.

Should mostly fix .
2016-08-06 15:47:04 +02:00
wm4
6e45e1de77 demux_timeline: restore mkv edition switching 2016-07-14 18:26:58 +02:00
wm4
dafafc90de demux_timeline: request subtitle prefetching on crossing segments
SEEK_HR is interpreted by demux_mkv.c, and enables subtitle preroll by
prefetching additional subtitle pakcets which might overlap with the
seek destination. This should make the case work when segment boundaries
fall into the middle of subtitle events.

This still usually leaves a flicker of at least 1 frame on start,
because dec_sub.c does not ensure that enough subtitles are read before
rendering after a segment switch. (Probably a WONTFIX.)
2016-03-25 17:27:02 +01:00
wm4
fd57503890 demux_timeline: skip decoder reinit when seeking to same segment
"Normal" seeks, which don't actually switch the segment, do not need to
reinit the decoders.
2016-03-17 21:32:41 +01:00
wm4
a6f8a6977e demux_timeline: set correct seekable flags
Tricky misleading crap.

Fixes .
2016-03-03 15:31:44 +01:00
wm4
92ba630796 demux: remove relative seeking
Ever since a change in mplayer2 or so, relative seeks were translated to
absolute seeks before sending them to the demuxer in most cases. The
only exception in current mpv is DVD seeking.

Remove the SEEK_ABSOLUTE flag; it's not the implied default. SEEK_FACTOR
is kept, because it's sometimes slightly useful for seeking in things
like transport streams. (And maybe mkv files without duration set?)

DVD seeking is terrible because DVD and libdvdnav are terrible, but
mostly because libdvdnav is terrible. libdvdnav does not expose seeking
with seek tables. (Although I know xbmc/kodi use an undocumented API
that is not declared in the headers by dladdr()ing it - I think the
function is dvdnav_jump_to_sector_by_time().) With the current mpv
policy if not giving a shit about DVD, just revert our half-working seek
hacks and always use dvdnav_time_search(). Relative seeking might get
stuck sometimes; in this case --hr-seek=always is recommended.
2016-02-28 19:28:34 +01:00
wm4
08dbaf1dcc demux_timeline: slightly improve reported file format
Report the underlying demuxer's format. Since there can be many demuxers
participating, pick the "main" segment.
2016-02-25 22:49:50 +01:00
wm4
297fdcc095 demux_timeline: fix nested timelines
You can e.g. reference ordered chapters or other EDL files in EDLs.
There were some bugs left which broke this in some cases.
2016-02-20 16:22:15 +01:00
wm4
ce0b99314b demux_timeline: cosmetics: move a function
Gets rid of a forward declaration.
2016-02-16 21:06:02 +01:00
wm4
3c3cd0c540 demux_timeline: disable cache for inactive segments
This is achieved indirectly by deslecting all streams for the non-
current segment (and if the segment doesn't share the demuxer with the
currently active one).

Restores functionality added with commit 46bcdb70.
2016-02-16 21:05:18 +01:00
wm4
0af5335383 Rewrite ordered chapters and timeline stuff
This uses a different method to piece segments together. The old
approach basically changes to a new file (with a new start offset) any
time a segment ends. This meant waiting for audio/video end on segment
end, and then changing to the new segment all at once. It had a very
weird impact on the playback core, and some things (like truly gapless
segment transitions, or frame backstepping) just didn't work.

The new approach adds the demux_timeline pseudo-demuxer, which presents
an uniform packet stream from the many segments. This is pretty similar
to how ordered chapters are implemented everywhere else. It also reminds
of the FFmpeg concat pseudo-demuxer.

The "pure" version of this approach doesn't work though. Segments can
actually have different codec configurations (different extradata), and
subtitles are most likely broken too. (Subtitles have multiple corner
cases which break the pure stream-concatenation approach completely.)

To counter this, we do two things:
- Reinit the decoder with each segment. We go as far as allowing
  concatenating files with completely different codecs for the sake
  of EDL (which also uses the timeline infrastructure). A "lighter"
  approach would try to make use of decoder mechanism to update e.g.
  the extradata, but that seems fragile.
- Clip decoded data to segment boundaries. This is equivalent to
  normal playback core mechanisms like hr-seek, but now the playback
  core doesn't need to care about these things.

These two mechanisms are equivalent to what happened in the old
implementation, except they don't happen in the playback core anymore.
In other words, the playback core is completely relieved from timeline
implementation details. (Which honestly is exactly what I'm trying to
do here. I don't think ordered chapter behavior deserves improvement,
even if it's bad - but I want to get it out from the playback core.)

There is code duplication between audio and video decoder common code.
This is awful and could be shareable - but this will happen later.

Note that the audio path has some code to clip audio frames for the
purpose of codec preroll/gapless handling, but it's not shared as
sharing it would cause more pain than it would help.
2016-02-15 21:04:07 +01:00