summaryrefslogtreecommitdiffstats
path: root/demux
Commit message (Collapse)AuthorAgeFilesLines
* 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_lavf: also fix cache seeking with large codec delaywm42019-09-191-0/+2
| | | | | | | | | Fixes the same thing as the previous commit did with demux_mkv. I'm not sure if this is correct or a good idea (well, it works with my sample file). There are some shady things in this, but describing them would require too many expletives.
* demux, demux_mkv: fix seeking in cache with large codec delaywm42019-09-193-1/+10
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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_mkv: stop setting per-packet initial padding from codec delaywm42019-09-191-2/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | This is a bad approach, and should be handled by a codec parameter field (in mp_codec_params or AVCodecParameters). It's bad because it's overly complicated, and has potential to break demuxer cache assumptions: packets that were "intended" for seek resuming may suddenly appear in the middle of a stream, when you seek back and play a cached part again. (In general it was fine though, because seek range joining tends to remove the first audio packet of the next range when trying to find an overlap.) demux_mkv.c does not try to export its codec_delay field through the codec parameters mentioned above. In the only case I spotted this element, the codec itself (opus) set this field within libavcodec. And I think that's actually how it should be. On the other hand, a file could in theory set this field via mkv headers if the codec is too stupid to have such a field internally. But I don't really care until I see such a file. The end trimming is still sort of needed (though not sure if anything uses it, other than the opus/mkv test sample I was using). The decoder can't know whether something is the last packet, until it's too late. The codec_delay field is still needed to offset timestamps.
* 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.
* demux_raw: fix operation with demuxer cache and backward playbackwm42019-09-191-1/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Raw audio formats can be accessed sample-wise, and logically audio packets demuxed from it would contain only 1 sample. This is inefficient, so raw audio demuxers typically "bundle" multiple samples in one packet. The problem for the demuxer cache and backward playback is that they need properly aligned packets to make seeking "deterministic". The requirement is that if you read some packets, and then seek back, you eventually see the same packets again. demux_raw basically allowed to seek into the middle of a previously returned packet, which makes it impossible to make the transition seamless. (Unless you'd be aware of the packet data format and cut them to make it seamless, which is too complex for such a use case.) Solve this by always aligning seeks to packet boundaries. This reduces the seek accuracy to the arbitrarily chosen packet size. But you can use hr-seek to fix this. The gain from not making raw audio an awful special case pays in exchange for this "stupid" suggestion to use hr-seek. It appears this also fixes that it could and did seek into the middle of the frame (not sure if this code was ever tested - it goes back to removing the code duplication between the former demux_rawaudio.c and demux_rawvideo.c). If you really cared, you could introduce a seek flag that controls whether the seek is aligned or not. Then code which requires "deterministic" demuxing could set it. But this isn't really useful for us, and we'd always set the flag anyway, unless maybe the caching were forced disabled. libavformat's wav demuxer exhibits the same issue. We can't fix it (it would require the unpleasant experience of contributing to FFmpeg), so document this in otions.rst. In theory, this also affects seek range joining, but the only bad effect should be that cached data is discarded.
* demux_raw: set keyframe flagwm42019-09-191-0/+1
| | | | | | This is for uncompressed data, so every frame is a "keyframe". This is part of making this demuxer work with the demuxer layer caching and backward playback.
* Implement backwards playbackwm42019-09-194-23/+409
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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-192-0/+3
| | | | | 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-192-2/+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-192-0/+12
|
* packet: reorder fieldswm42019-09-191-5/+6
| | | | Saves 8 bytes on 64 bit platforms.
* demux_edl: fix assertion failure on exit in obscure ytdl caseswm42019-09-191-0/+1
| | | | | | | | | | | | | | | | | | | | | | If a DASH-hack EDL has an init fragment is set, it opens the init fragment as such to get the track layout (including codec etc.) and avoids opening actual fragments until actual playback. It does not get added to the source array, so it leaks on exit, which triggers an obscure (but very justified) assertion in thread_tools.c:106. Fix the leak by adding the additional demuxer instance to the sources arrays, which gets it freed. This is a regression from when I rewrote some of the timeline handling. I decided that in order to make memory management slightly simpler, freeing a timeline should only free elements in the sources array. That is OK; I just didn't re-test with pseudo-DASH that has init fragments, and just hit a video that uses that by accidents. These videos are rather scarce (apparently) so it happened only now. The real solution would probably be adding demuxer reference counting. This EDL memory management is just too messy, and throwing refcounting at such problems is an effective and popular fix. Then you'd get debugging nightmares with incorrect refcounts too, though.
* demux_mkv: fix seeking in broken mjpeg fileswm42019-09-191-1/+3
|
* demux_timeline: add heuristic to fix shifted seeks with separate audiowm42019-09-191-11/+80
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If you have a EDL stream with separate sources for audio and video stream (like ytdl_hook now creates), you can get the problem that the video stream seeks to a different position than audio due to different key frame granularity. In particular, if you seek backward, the video might undershoot the seek target by a lot. Then video will resume from an earlier position than audio, and the player plays silence. This is annoying. Fix this by explicitly implementing a heuristic to detect separate audio/video streams, determining where a video seek ends up, and then seeking the audio stream to the video destination. This also makes sure to not seek audio with SEEK_FORWARD, so it will always seek before the video position. Non-precise seeks still skip audio to the video target, so this helps with ensuring that audio is present at the final seek target. The implementation is very annoying, because the only way to determine the seek target is to actually read a packet. Thus a 1-packet queue needs to be added. In theory, we could get the seek target from the index of the video file (especially if it's mp4), but libavformat does not have public API that exports this index, so we're stuck with this roundabout generic method. Note that this is only for non-precise seeks. If precise seeks are done, the problem is handled by the frontend by skipping unwanted video frames. But non-precise seeking should still work. (Personally I prefer non-precise seek mode by default because they're still significantly faster.) It also needs to be said that this is the 4th implementation of this seek adjustment thing in mpv. The 1st implementation is in the frontend (look for MPContext.seek_slave). This works only if the external audio stream is known as such on the frontend level. The 2nd implementation is in the demuxer level packet cache (top of execute_cache_seek()). This is similar to code that any demuxer needs to handle non-precise seeks sufficiently nicely. The 3rd is in demux_mkv.c. Since mkv is an interleaved format, this implementation mostly consists on trying to pick index entries for video packets if a video stream is selected. Maybe these "redundant" implementations could be avoided by exposing separate streams through the demuxer API (and making them individually seekable) or something like this, but this is messy and not without problems for multiple reasons. So for now this commit is the best way to fix the observed behavior.
* demux_edl, cue, mkv: slightly nicer file format indicationwm42019-09-196-6/+29
| | | | | | | | | | | | | Instead of just using "edl/" for the file format, report mkv_oc if it's generated from ordered chapters, "cue/" if from .cue, "multi/" if it's from EDL but only for adding separate streams, "dash/" if it's from EDL but only using the DASH hack, and "edl/" for everything else. The EDL variants are mostly special-cased to the variants the ytdl wrapper usually generates. This has no effect other than what the command.c file-format property returns.
* demux_edl, cue, mkv: clean up timeline stuff slightlywm42019-09-196-129/+158
| | | | | | | | | | | | | | | | | | | | | Remove the singly linked list hack, replace it with a slightly more proper data structure. This probably gets rid of a few minor bugs along the way, caused by the awkward nonsensical sharing/duplication of some fields. Another change (because I'm touching everything related to timeline anyway) is that I'm removing the special semantics for parts[num_parts]. This is now strictly out of bounds, and instead of using the start time of the next/beyond-last part, there is an end time field now. Unfortunately, this also requires touching the code for cue and mkv ordered chapters. From some superficial testing, they still seem to mostly work. One observable change is that the "no_chapters" header is per-stream now, which is arguably more correct, and getting the old behavior would require adding code to handle it as special-case, so just adjust ytdl_hook.lua to the new behavior.
* demux_edl: add no_clipwm42019-09-193-8/+12
| | | | | | Used by the next commit. It mostly exposes part of mp4_dash functionality. It actually makes little sense other than for ytdl special-use. See next commit.
* demux_timeline: include "dash" hint in reported file formatwm42019-09-191-1/+2
|
* demux_timeline: disable end-of-segment handling in DASH modewm42019-09-191-2/+2
| | | | | | | | 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.
* 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-193-1/+35
| | | | | | |