summaryrefslogtreecommitdiffstats
path: root/demux/demux.c
Commit message (Collapse)AuthorAgeFilesLines
* demux: fix typoswm42019-09-191-2/+2
|
* demux: redo backstep seek handling slightly againwm42019-09-191-2/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Backstepping still could get "stuck" if the demuxer didn't seek far back enough. This commit fixes getting stuck if playing backwards from the end, and audio has ended much earlier than the video. In commit "demux: fix initial backward demuxing state in some cases", I claimed that the backward seek semantics ("snapping" backward in normal seeking, unrelated to backward playing) would take care of this. Unfortunately, this is not always quite true. In theory, a seek to any position (that does not use SEEK_FORWARD, i.e. backward snapping) should return a packet for every stream. But I have a mkv sample, where audio ends much earlier than video. Its mkvmerge created index does not have entries for audio packets, so the video index is used. This index has its last entry somewhere close after the end of audio. So no audio packets will be returned. With a "too small" back_seek_size, the demuxer will retry a seek target that ends up in this place forever. (This does not happen if you use --index=recreate. It also doesn't happen with libavformat, which always prefers its own index, while mpv's internal mkv demuxer strictly prefers the index from the file if it can be read.) Fix this by adding the back_seek_size every time we fail to see enough packets. This way the seek step can add up until it works. To prevent that back_seek_pos just "runs away" towards negative infinity by subtracting back_seek_size every time we back step to undo forward reading (e.g. if --no-cache is used), readjust the back_seek_pos to the lowest known resume position. (If the cache is active, kf_seek_pts can be used, but to work in all situations, the code needs to grab the minimum PTS in the keyframe range.)
* demux: set SEEK_HR for backstep seeks, move a hr-seek detail to playloopwm42019-09-191-10/+1
| | | | | | Just rearranging shit. Setting SEEK_HR for backstep seeks actually doesn't have much meaning, but disables the weird audio snapping for "keyframe" seeks, and I don't know it's late.
* demux: rename a variablewm42019-09-191-8/+8
| | | | | It's "better". This is all what's left from an attempt to make the code slightly nicer.
* demux: remove minor code duplicationwm42019-09-191-16/+14
| | | | | | | | | | | | | | | | | | This code used to be simpler, but now it's enough that it should be factored into a single function. Both uses of the new function are annoyingly different. The first use is the special case when a decoder tries to read packets, but the demuxer doesn't see any (like mp4 files with sparse video packets, which actually turned out to be chapter thumbnail "tracks"). Then the other stream queues will overflow, and the stream with no packets is marked EOF to avoid stalling playback. The second case is when the demxuer returns global EOF. It would be more awkward to have the loop iterating the streams in the function, because then you'd need a weird parameter to control the behavior.
* demux: fix initial backward demuxing state in some caseswm42019-09-191-59/+95
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Just "mpv file.mkv --play-direction=backward" did not work, because backward demuxing from the very end was not implemented. This is another corner case, because the resume mechanism so far requires a packet "position" (dts or pos) as reference. Now "EOF" is another possible reference. Also, the backstep mechanism could cause streams to find different playback start positions, basically leading to random playback start (instead of what you specified with --start). This happens only if backstep seeks are involved (i.e. no cached data yet), but since this is usually the case at playback start, it always happened. It was racy too, because it depended on the order the decoders on other threads requested new data. The comment below "resume_earlier" has some more blabla. Some other details are changed. I'm giving up on the "from_cache" parameter, and don't try to detect the situation when the demuxer does not seek properly. Instead, always seek back, hopefully some more. Instead of trying to adjust the backstep seek target by a random value of 1.0 seconds. Instead, always rely on the random value provided by the user via --demuxer-backward-playback-step. If the demuxer should really get "stuck" and somehow miss the seek target badly, or the user sets the option value to 0, then the demuxer will not make any progress and just eat CPU. (Although due to backward seek semantics used for backstep seeks, even a very small seek step size will work. Just not 0.) It seems this also fixes backstepping correctly when the initial seek ended at the last keyframe range. (The explanation above was about the case when it ends at EOF. These two cases are different. In the former, you just need to step to the previous keyframe range, which was broken because it didn't always react correctly to reaching EOF. In the latter, you need to do a separate search for the last keyframe.)
* demux, demux_mkv: fix seeking in cache with large codec delaywm42019-09-191-1/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | In this scenario, the demuxer will output timestamps offset by the codec delay (e.g. negative timestamps at the start; mkv simulates those), and the trimming in the decoder (often libavcodec, but ad_lavc.c in our case) will adjust the timestamps back (e.g. stream actually starts at 0). This offset needs to be taken into account when seeking. This worked in the uncached case. (demux_mkv.c is a bit tricky in that the index is already in the offset space, so it compensates even though the seek call does not reference codec_delay.) But in the cached case, seeks backwards did not seek enough, and forward they seeked too much. Fix this by adding the codec delay to the index search. We need to get "earlier" packets, so e.g. seeking to position 0 really gets the initial packets with negative timestamps. This also adjusts the seek range start. This is also pretty obvious: if the beginning of the file is cached, the seek range should start at 0, not a negative value. We compare 0-based timestamps to it later on. Not sure if this is the best approach. I also could have thought about/checked some corner cases harder. But fuck this shit. Not fixing duration (who cares) or end trimming, which would reduce the seek range and duration (who cares).
* demux: don't adjust internal backward playback seeks by start timewm42019-09-191-3/+5
| | | | | | Only timestamps that enter or leave the demuxer API should be adjusted by ts_offset (which is usually the start time). queue_seek() is also used by backward demux seeks, which uses an internal timestamp.
* Implement backwards playbackwm42019-09-191-23/+402
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | See manpage additions. This is a huge hack. You can bet there are shit tons of bugs. It's literally forcing square pegs into round holes. Hopefully, the manpage wall of text makes it clear enough that the whole shit can easily crash and burn. (Although it shouldn't literally crash. That would be a bug. It possibly _could_ start a fire by entering some sort of endless loop, not a literal one, just something where it tries to do work without making progress.) (Some obvious bugs I simply ignored for this initial version, but there's a number of potential bugs I can't even imagine. Normal playback should remain completely unaffected, though.) How this works is also described in the manpage. Basically, we demux in reverse, then we decode in reverse, then we render in reverse. The decoding part is the simplest: just reorder the decoder output. This weirdly integrates with the timeline/ordered chapter code, which also has special requirements on feeding the packets to the decoder in a non-straightforward way (it doesn't conflict, although a bugmessmass breaks correct slicing of segments, so EDL/ordered chapter playback is broken in backward direction). Backward demuxing is pretty involved. In theory, it could be much easier: simply iterating the usual demuxer output backward. But this just doesn't fit into our code, so there's a cthulhu nightmare of shit. To be specific, each stream (audio, video) is reversed separately. At least this means we can do backward playback within cached content (for example, you could play backwards in a live stream; on that note, it disables prefetching, which would lead to losing new live video, but this could be avoided). The fuckmess also meant that I didn't bother trying to support subtitles. Subtitles are a problem because they're "sparse" streams. They need to be "passively" demuxed: you don't try to read a subtitle packet, you demux audio and video, and then look whether there was a subtitle packet. This means to get subtitles for a time range, you need to know that you demuxed video and audio over this range, which becomes pretty messy when you demux audio and video backwards separately. Backward display is the most weird (and potentially buggy) part. To avoid that we need to touch a LOT of timing code, we negate all timestamps. The basic idea is that due to the navigation, all comparisons and subtractions of timestamps keep working, and you don't need to touch every single of them to "reverse" them. E.g.: bool before = pts_a < pts_b; would need to be: bool before = forward ? pts_a < pts_b : pts_a > pts_b; or: bool before = pts_a * dir < pts_b * dir; or if you, as it's implemented now, just do this after decoding: pts_a *= dir; pts_b *= dir; and then in the normal timing/renderer code: bool before = pts_a < pts_b; Consequently, we don't need many changes in the latter code. But some assumptions inhererently true for forward playback may have been broken anyway. What is mainly needed is fixing places where values are passed between positive and negative "domains". For example, seeking and timestamp user display always uses positive timestamps. The main mess is that it's not obvious which domain a given variable should or does use. Well, in my tests with a single file, it suddenly started to work when I did this. I'm honestly surprised that it did, and that I didn't have to change a single line in the timing code past decoder (just something minor to make external/cached text subtitles display). I committed it immediately while avoiding thinking about it. But there really likely are subtle problems of all sorts. As far as I'm aware, gstreamer also supports backward playback. When I looked at this years ago, I couldn't find a way to actually try this, and I didn't revisit it now. Back then I also read talk slides from the person who implemented it, and I'm not sure if and which ideas I might have taken from it. It's possible that the timestamp reversal is inspired by it, but I didn't check. (I think it claimed that it could avoid large changes by changing a sign?) VapourSynth has some sort of reverse function, which provides a backward view on a video. The function itself is trivial to implement, as VapourSynth aims to provide random access to video by frame numbers (so you just request decreasing frame numbers). From what I remember, it wasn't exactly fluid, but it worked. It's implemented by creating an index, and seeking to the target on demand, and a bunch of caching. mpv could use it, but it would either require using VapourSynth as demuxer and decoder for everything, or replacing the current file every time something is supposed to be played backwards. FFmpeg's libavfilter has reversal filters for audio and video. These require buffering the entire media data of the file, and don't really fit into mpv's architecture. It could be used by playing a libavfilter graph that also demuxes, but that's like VapourSynth but worse.
* demux: cleaner mutex usagewm42019-09-191-5/+6
| | | | | | | | | | | | | | The demuxer layer can start a thread to decouple the rest of the player from blocking I/O (such as network accesses). But this particular function does not support running with the thread enabled. The mutex use within it is only since thread_work() may temporarily unlock the mutex, and unlocking an unlocked mutex is not allowed. Most of the rest of the code still does proper locking, even if it's pointless and effectively single-threaded. To make this look slightly cleaner, extend the mutex around the rest of the code (like threaded code would have to do). This is mostly a cosmetic change.
* demux: add shitty start of stream detectionwm42019-09-191-8/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The demuxer cache benefits slightly from knowing where the current file or stream begins. For example, seeking "left most" when the start is cached would not trigger a low level seek (which would be followed by messy range joining when it notices that the newly demuxed packets overlap with an existing range). Unfortunately, since multimedia is so crazy (or actually FFmpeg in its quite imperfect attempt to be able to demux anything), it's hard to tell where a file starts. There is no feedback whether a specific seek went to the start of the file. Packets are not tagged with a flag indicating they were demuxed from the start position. There is no index available that could be used to cross-check this (even if the file contains a full and "perfect" index, like mp4). You could go by the timestamps, but who says streams start at 0? Streams can start somewhere at an extremely high timestamps (transport streams like to do that), or they could start at negative times (e.g. files with audio pre-padding will do that), and maybe some file formats simply allow negative timestamps and could start at any negative time. Even if the affected file formats don't allow it in theory, they may in practice. In addition, FFmpeg exports a start_time field, which may or may not be useful. (mpv's internal mkv demuxer also exports such a field, but doesn't bother to set it for efficiency and robustness reasons.) Anyway, this is all a huge load of crap, so I decided that if the user performs a seek command to time 0 or earlier, we consider the first packet demuxed from each stream to be at the start of the file. In addition, just trust the start_time field. This is the "shitty" part of this commit. One common case of negative timestamps is audio pre-padding. Demuxers normally behave sanely, and will treat 0 as the start of the file, and the first packets demuxed will have negative timestamps (since they contain data to discard), which doesn't break our assumptions in this commit. (Although, unfortunately, do break some other demuxer cache assumptions, and the first cached range will be shown as starting at a negative time.) Implementation-wise, this is quite simple. Just split the existing initial_state flag into two, since we want to deal with two separate aspects. In addition, this avoids the refresh seek on track switching when it happens right after a seek, instead of only after opening the demuxer.
* demux, command: export bof/eof flagswm42019-09-191-0/+2
| | | | | Export these flags with demuxer-cache-state. Useful for debugging, but any client API users could also make use of it.
* demux: remove logic duplication from packet read functionswm42019-09-191-68/+57
| | | | | | | | | | | | | | | | | There were 3 packet reading functions: the "old" demux_read_packet() that blocked (leftover from MPlayer times, but was still used until recently by some obscure code), the "new" demux_read_packet_async(), and the special demux_read_any_packet(), that is used by pseudo-demuxers like demux_edl. The first two could be used both in threaded and un-threaded mode. This made 5 cases in total. Some bits of logic was spread across all of them. Unify the logic. A recent commit made demux_read_packet() private, and the code for it in threaded mode disappears. The difference between threaded and un-threaded is minimized. It's possible that this commit causes random regression. Enjoy.
* sub: remove only user of demux_read_packet()wm42019-09-191-1/+1
| | | | | | | | | | | | | | | | | | | There are 3 packet reading functions in the demux API, which all function completely differently. One of them, demux_read_packet(), has only 1 caller, which is in dec_sub.c. Change this caller to use demux_read_packet_async() instead. Since it really wants to do a blocking call, setup some proper waiting. This uses mp_dispatch_queue, because even though it's overkill, it needs the least code. In practice, waiting actually never happens. This code is only called on code paths where everything is already read into memory (libavformat's subtitle demuxers simply behave this way). It's still a bit of a "coincidence", so implement it properly anyway. If suubtitle decoder init fails, we still need to unset the demuxer wakeup callback. Add a sub_destroy() call to the failure path. This also happens to fix a missed pthread_mutex_destroy() call (in practice this was a nop, or a memory leak on BSDs).
* demux: adjust reader_head on range joiningwm42019-09-191-0/+8
| | | | | | | | | | | | | | | | | | | I'm not sure about this, but it looks like a bug. If a stream didn't have packets, but the joined range does, the stream should obviously read the packets added by the joined range. Until now, due to reader_head being NULL, reading was only resumed if a _new_ packet was added by actual demuxing (in add_packet_locked()), which means the stream would suddenly skip ahead, past the original end of the joined range. Change it so that it will pick up the new range. Also, clear the skip_to_keyframe flag. Nothing useful can come from this flag being set; in the first place, the first packet of a range (that isn't the current range) should start with a keyframe. Some code probably enforced it (although it's fuzzy). Completely untested.
* demux: don't process obscure skipped packetswm42019-09-191-0/+5
| | | | | | | | | | When doing a seek to the end of the cache, ds->skip_to_keyframe can be set to true. Then some packets passed to add_packet_locked() may have to be skipped. In some aspects, the skipped packet was still treated as if it was going to be returned to the reader. It almost doesn't matter though: it only caused a redundant wakeup_ds() call, and could pass the packet to the stream recorder. Fix it anyway.
* demux: factor out a some packet queue codewm42019-09-191-11/+22
| | | | | Might be helpful for later. The "duplicated" ds->reader_head check above the function call is redundant, but leaving it also for later.
* demux: fix typos in commentswm42019-09-191-2/+2
| | | | How does this happen?
* player: add --demuxer-cache-wait optionwm42019-09-191-0/+11
|
* demux: fix typo in a commentwm42019-09-191-2/+2
|
* demux: fix SEEK_FORWARD into end of cached rangewm42019-09-191-0/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This fixes that there were weird delay ("buffering") when seeking into the last part of a seekable range. The exact case which triggers it if SEEK_FORWARD is used, and the seek pts is after the second-last keyframe, but before the end of the range. In that case, find_seek_target() returned NULL, and the cache layer waited until the _next_ keyframe the underlying demuxer returned until resuming playback. find_seek_target() returned NULL, because the last keyframe had kf_seek_pts unset. This field contains the lowest PTS in the packet range from the keyframe until the next keyframe (or EOF). For normal seeks, this is needed because keyframes don't necessarily have the minimum PTS in the packet range, so it needs to be computed by waiting for all packets until the next keyframe (or EOF). Strictly speaking, this behavior was correct, but it meant that the caller would set ds->skip_to_keyframe, which waits for the next newly demuxed keyframe. No packets were returned to the decoder until this happened, usually resulting in the frontend entering "buffering" mode. What it really needs to do is returning the last keyframe in the cache. In this situation, the seek target points in the middle of the last completely cached packet range (as delimited by keyframes), and SEEK_FORWARD is supposed to skip to the next keyframe. This is in line with the basic assumptions the packet cache makes (e.g. the keyframe flag means it's possible to start decoding, and the frames decoded from it and following packets will strictly have PTS values above the previous keyframe range). This means in this situation the kf_seek_pts value doesn't matter either. So fix this situation by explicitly detecting it and then returning the last cached keyframe. Should the search loop look at all packets, instead of only keyframe ones? This would mean it can know that it's within the last keyframe range (without looking at queue->seek_end). Maybe this would be a bit more natural for the SEEK_FORWARD case, but due to PTS reordering it doesn't sound like a useful thing to do. Should skip_to_keyframe be checked by the code that sets kf_seek_pts to a known value? This wouldn't help too much; the frontend would still go into "buffering" mode for no reason until the packet range is completed, although it would resume from the correct range. Should a NULL return always unconditionally use keyframe_latest? This makes sense because the seek PTS is usually already in the cached range, so this is the only case that should happen. But there are scary special cases, like sparse subtitle streams, or other uses of find_seek_target() which could be out of range now or in future. Basically, don't "risk" it. One other potential problem with this is that the "adjust seek target" code will be disabled in this case. It checks kf_seek_pts, and if it's unset, the adjustment is not done. Maybe this could be changed to use the queue's seek_end time, but I'm not sure if this is fully kosher. On the other hand, I think the main use for this adjustment is with backwards seeks, so this shouldn't matter. A previous commit dealing with audio/video stream merging mentioned how seeking forward entered "buffering" mode for unknown reasons; this commit fixes this issue.
* demux_timeline: report network speed of slave connectionswm42019-09-191-0/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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).
* demux: slightly cleanup network speed reportingwm42019-09-191-4/+29
| | | | | | | | | | | | It was an ugly hack, and the next commit will make it even uglier. Slightly reduce the ugliness to prevent death of too many brain cells, though it's still an ugly hack. The cleanup is really minor, but I guess the following commit would be much worse otherwise. In particular, this commit checks accesses (instead of having a public field with evil access rules), which should avoid misunderstandings and incorrect use. Strictly speaking, the added field is redundant, but the next commit complicates it a bit.
* demux: make demuxer list static, remove ancient commentwm42019-09-191-5/+1
| | | | | I'd actually very much encourage demuxer implementations outside problematic libavformat.
* demux: another unused functionwm42019-09-191-12/+0
|
* demux: autoselection is gonewm42019-09-191-8/+0
| | | | Was used by DVD, I think.
* demux: remove some more minor dead codewm42019-09-191-6/+4
| | | | Also add clarifications.
* demux: get rid of ->control callbackwm42019-09-191-2/+2
| | | | | | | | 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.
* demux: change hack for closing subtitle files earlywm42019-09-191-21/+20
| | | | | | | | | | | | | | | | | | | | | Subtitles (and a few other file types, like playlists) are not streamed, but fully read on opening. This means keeping the file handle or network socket open is a waste of resources and could cause other weird behavior. This is why there's a hack to close them after opening. Change this hack to make the demuxer itself do this, which is less weird. (Until recently, demuxer->stream ownership was more complex, which is why it was done this way.) There is some evil shit due to a huge ownership/lifetime mess of various objects. Especially EDL (the currently only nested demuxer case) requires being careful about mp_cancel and passing down stream pointers. As one defensive programming measure, stop accessing the "stream" variable in open_given_type(), even where it would still work. This includes removing a redundant line of code, and removing the peak call, which should not be needed anymore, as the remaining demuxers do this mostly correctly.
* demux: make demux_open() privatewm42019-09-191-2/+3
| | | | | | | | | | I always wanted to get rid of this, because it makes the ownership rules for the stream pointer really awkward. demux_edl.c was the only remaining user of this. Replace it with a semi-clever idea: the init segment shit can be used to pass the "file" contents as memory block, and "memory://" itself provides an empty stream. I have no idea if this actually works, because I didn't immediately find a test stream (would have to be some youtube DASH shit).
* demux: simplify API for returning cache statuswm42019-09-191-121/+52
| | | | | | | | Instead of going through those weird DEMUXER_CTRLs, query this information directly. I'm not sure which kind of brain damage made me use CTRLs for these. Since there are no other DEMUXER_CTRLs that make sense for the frontend, remove the remaining infrastructure for them too.
* demux: return stream file size differently, rip out stream ctrlswm42019-09-191-36/+1
| | | | | | | The stream size return was the only thing that still required doing STREAM_CTRLs from frontend through the demuxer layer. This can be done much easier, so rip it out. Also rip out the now unused infrastructure for STREAM_CTRLs via demuxer layer.
* stream_libarchive: remove base filename stuffwm42019-09-191-18/+0
| | | | | | | | Apparently this was so that when playing a video file from a .rar file, it would load external subtitles with the same name (instead of looking for mpv's rar:// mangled URL). This was requested on github almost 5 years ago. Seems like a weird feature, and I don't care. Drop it, because it complicates some in progress change.
* demux: return packets directly from demuxer instead of using sh_streamwm42019-09-191-8/+12
| | | | | | | Preparation for other potential changes to separate demuxer cache/thread and actual demuxers. Most things are untested, but it seems to work somewhat.
* demux, stream: remove old rar support in favor of libarchivewm42019-09-131-1/+0
| | | | | | The old rar code