summaryrefslogtreecommitdiffstats
path: root/player/playloop.c
Commit message (Collapse)AuthorAgeFilesLines
* options: split m_config.c/hwm42020-03-131-1/+1
| | | | | | | | | | | | | | | | | Move the "old" mostly command line parsing and option management related code to m_config_frontend.c/h. Move the the code that enables other part of the player to access options to m_config_core.c/h. "frontend" is out of lack of creativity for a better name. Unfortunately, the separation isn't quite clean yet. m_config_frontend.c still references some m_config_core.c implementation details, and m_config_new() is even left in m_config_core.c for now. There some odd functions that should be removed as well (marked as "Bad functions"). Fixing these things requires more changes and will be done separately. struct m_config is left with the current name to reduce diff noise. Also, since there are a _lot_ source files that include m_config.h, add a replacement m_config.h that "redirects" to m_config_core.h.
* filter: minor cosmetic naming issuewm42020-03-081-1/+1
| | | | | Just putting some more lipstick on the pig, maybe it looks a bit nicer now.
* player: force update of cache properties even on inactive demuxer cachewm42020-03-051-1/+6
| | | | | | | | | | | | | | | | | | | | | | | | | When the demuxer cache read until the end of the stream, and was finished and completely inactive, the cache properties were not updated anymore via MP_EVENT_CACHE_UPDATE. Unfortunately, many cache properties depend on the current playback position, such as cache-duration or fw-bytes. This is especially visible on the OSC. If everything was cached, seeking around didn't update the displayed forward cache duration. That means checking demuxer_reader_state.idle is not enough. You also need to check whether the current playback position changed. Fix this by explicitly using the current playback position, and update the properties if it changed "enough". "Enough" is 1 second of media time in this example, which may or may not be appropriate. In general, this could probably be done better. There are many other triggers that change the cache state and that are not covered. For now I'm content with getting rid of the obvious problems. I think the OSC problem in particular was caused by changing it from polling to using property change notifications.
* options: make decoder options local to decoder wrapperwm42020-03-011-2/+1
| | | | | | | | | | | | | | | Instead of having f_decoder_wrapper create its own copy of the entire mpv option tree, create a struct local to that file and move all used options to there. movie_aspect is used by the "video-aspect" deprecated property code. I think it's probably better not to remove the property yet, but fortunately it's easy to work around without needing special handling for this option or so. correct_pts is used to prevent use of hr-seek in playloop.c. Ignore that, if you use --no-correct-pts you're asking for trouble anyway. This is the only behavior change.
* player: add optional separate video decoding threadwm42020-02-291-1/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | See manpage additions. This has been a topic in MPlayer/mplayer2/mpv since forever. But since libavcodec multi-threaded decoding was added, I've always considered this pointless. libavcodec requires you to "preload" it with packets, and then you can pretty much avoid blocking on it, if decoding is fast enough. But in some cases, a decoupled decoder thread _might_ help. Users have for example come up with cases where decoding video in a separate process and piping it as raw video to mpv helped. (Or my memory is false, and it was about vapoursynth filtering, who knows.) So let's just see whether this helps with anything. Note that this would have been _much_ easier if libavcodec had an asynchronous (or rather, non-blocking) API. It could probably have easily gained that with a small change to its multi-threading code and a small extension to its API, but I guess not. Unfortunately, this uglifies f_decoder_wrapper quite a lot. Part of this is due to annoying corner cases like legacy frame dropping and hardware decoder state. These could probably be prettified later on. There is also a change in playloop.c: this is because there is a need to coordinate playback resets between demuxer thread, decoder thread, and playback logic. I think this SEEK_BLOCK idea worked out reasonably well. There are still a number of problems. For example, if the demuxer cache is full, the decoder thread will simply block hard until the output queue is full, which interferes with seeking. Could also be improved later. Hardware decoding will probably die in a fire, because it will run out of surfaces quickly. We could reduce the queue to size 1... maybe later. We could update the queue options at runtime easily, but currently I'm not going to bother. I could only have put the lavc wrapper itself on a separate thread. But there is some annoying interaction with EDL and backward playback shit, and also you would have had to loop demuxer packets through the playloop, so this sounded less annoying. The food my mother made for us today was delicious. Because audio uses the same code, also for audio (even if completely pointless). Fixes: #6926
* f_decoder_wrapper: replace most public fields with setters/getterswm42020-02-291-1/+1
| | | | | | | | | | | | | | | | | | | I may (optionally) move decoding to a separate thread in a future change. It's a bit attractive to move the entire decoder wrapper to there, so if the demuxer has a new packet, it doesn't have to wake up the main thread, and can directly wake up the decoder. (Although that's bullshit, since there's a queue in between, and libavcodec's multi-threaded decoding plays cross-threads ping pong with packets anyway. On the other hand, the main thread would still have to shuffle the packets around, so whatever, just seems like better design.) As preparation, there shouldn't be any mutable state exposed by the wrapper. But there's still a large number of corner-caseish crap, so just use setters/getters for them. This recorder thing will inherently not work, so it'll have to be disabled if threads are used. This is a bit painful, but probably still the right thing. Like speculatively pulling teeth.
* player: remove delayed audio seek thingwm42020-02-291-41/+0
| | | | | | | | | | | | | | | | | | | | | | | | This was a hack that attempted to line up external audio tracks with video. The problem is that if you do a keyframe seek backwards, video will usually seek much farther back than audio (due to much higher keyframe aka seek point distances). The hack somehow made seeking a 2 step process. This existed in 4 different forms in the history of this code base, and it was always very cumbersome. We mostly needed this for ytdl_hook (I think?), which uses the 4th form, which is nicely confined to demux_timeline and is unrelated to the "external" audio tracks in the high level player. Since this is (probably) not really widely needed anymore, get rid of it. Better do this now, than when somehow rewriting all the seeking code (which might happen in this decade or the next or so) and when it wouldn't be easily revertable anymore in case we find we "really" need it unlike expected. There is no issue if hr-seeks are used. Also, you can still use edl files to "bundle" multiple streams as if it was a single stream (this is what ytdl_hook does now).
* player: dumb seeking related stuff, make audio hr-seek defaultwm42020-02-281-21/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | Try to deal with various corner cases. But when I fix one thing, another thing breaks. (And it's 50/50 whether I find the breakage immediately or a few months later.) So results may vary. The default for--hr-seek is changed to "default" (not creative enough to find a better name). In this mode, audio seeking is exact if there is no video, or if the video has only a single frame. This change is actually pretty dumb, since audio frames are usually small enough that exact seeking does not really add much. But it gets rid of some weird special cases. Internally, the most important change is that is_coverart and is_sparse handling is merged. is_sparse was originally just a special case for weird .ts streams that have the corresponding low-level flag set. The idea is that they're pretty similar anyway, so this would reduce the number of corner cases. But I'm not sure if this doesn't break the original intended use case for it (I don't have a sample anyway). This changes last-frame handling, and respects the duration of the last frame only if audio is disabled. This is mostly "coincidental" due to the need to make seeking past EOF trigger player exit, and is caused by setting STATUS_EOF early. On the other hand, this might have been this way before (see removed chunk close to it).
* player: attempt to fix playback end on hr-seeking past EOF againwm42020-02-281-3/+6
| | | | | | | | | | This tries to fix #7206 (hr-seeking past EOF does not stop playback) again. Commit 57fbc9cd76f7 should have fixed this, but trying it again (using that git revision), it often did not work. Whatever the fuck. So add another dumb special case that will break within weeks. Note that the check in handle_eof() had no effect, since execute_queued_seek() is called later, which cancels EOF in the same case.
* player: set playback_pts in hr-seek past EOF casewm42020-02-281-1/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Hr-seek past the last frame instantly enters EOF, which means handle_playback_time() will not set playback_pts to the video PTS (as all video frames are skipped), which leads to the playback time being taken from the last seek target. This results in confusing behavior, especially since the seek time will be clipped to the file duration for display, but not for further relative seeks. Obviously, the time should be set to the last video frame, so use the last video frame as fallback if both audio and video have ended. Also, since the same problem exists with audio-only playback, add a fallback for audio PTS too. We don't know which was the "last" fragment of media played (to decide whether to use the audio or video PTS as the fallback), but it doesn't matter since the maximum works. This could lead to some undesired effects. In particular the audio PTS is basically a bad guess, and is for example not clipped against --end. (But the ridiculous way audio syncing and clamping currently works, I'm not going to touch that shit unless I rewrite it completely.) The cover art case is slightly broken: using --keep-open with keyframe seeks will result in 0 as playback PTS (the video PTS). OK, who cares, it got late. Also casually get rid of last_vo_pts, since that barely made any sense at all. Fixes: #7487
* player: consider audio buffer if AO driver does not report underrunswm42020-02-131-6/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | AOs can report audio underruns, but only ao_alsa and ao_sdl (???) currently do so. If the AO was marked as not reporting it, the cache state was used to determine whether playback was interrupted due to slow input. This caused problems in some cases, such as video with very low video frame rate: when a new frame is displayed, a new frame has to be decoded, and since there it's so much further into the file (long frame durations), the cache gets into an underrun state for a short moment, even though both audio and video are playing fine. Enlarging the audio buffer didn't help. Fix this by making all AOs report underruns. If the AO driver does not report underruns, fall back to using the buffer state. pull.c behavior is slightly changed. Pull AOs are normally intended to be used by pseudo-realtime audio APIs that fetch an audio buffer from the API user via callback. I think it makes no sense to consider a buffer underflow not an underrun in any situation, since we return silence to the reader. (OK, maybe the reader could check the return value? But let's not go there as long as there's no implementation.) Remove the flag from ao_sdl.c, since it just worked via the generic mechanism. Make the redundant underrun message verbose only. push.c seems to log a redundant underflow message when resuming (because somehow ao_play_data() is called when there's still no new data in the buffer). But since ao_alsa does its own underrun reporting, and I only use ao_alsa, I don't really care. Also in all my tests, there seemed to be a rather high delay until the underflow was logged (with audio only). I have no idea why this happened and didn't try to debug this, but there's probably something wrong somewhere. This commit may cause random regressions. See: #7440
* player: add ab-loop-count option/propertywm42020-02-081-0/+4
| | | | | | | | | | | | As requested I guess. It behaves quite similar to the --loop* options. Not quite happy with the idea that 1) the option is mutated on each operation (but at least it's consistent with --loop* and doesn't require more properties), and 2) the ab-loop command will do nothing once all loop iterations are done. As a concession, the OSD shows something about "disabled". Fixes: #7360
* player: make screenshot each-frame mode more accuratewm42020-02-071-0/+3
| | | | | | | | | | | | | | | | | | | | | | | Due to asynchronicity, we generally can't guarantee that a video frame matches up with other events such as playback time change exactly (since decoding, presentation, and property update all happen at different times). This is a complaint in the referenced bug report, where screenshot filenames in each-frame screenshot did not use the correct timestamp, and instead was lagging behind by 1 frame. But in this case, synchronicity was already pretty much forced with wait calls. The only problem was that the playback time was updated at a later time, which results in the observed 1 frame lag. Fix this by moving the place where the screenshot is triggered in this mode. Normal screenshots may still have the old problem. There is no effort made to guarantee the timestamps absolutely line up, same as with the OSD. (If you want a guarantee, you need to use a video filter, such as libavfilter's drawtext. These will obviously use the proper timestamp, instead of going through the somewhat asynchronous property etc. system in the player frontend.) Fixes: #7433
* player: partially fix backward playback display of cached text subtitleswm42020-02-041-0/+2
| | | | | | | | | | | | | | This simply didn't set the direction flag in most situations, which meant the timestamps used in the subtitle renderer were nonsense, leading to invisible subtitles. This works only for text subtitles that are cached in the ASS_Track state. Reading new subtitles is broken because the demuxer layer has trouble returning subtitle packets backwards, and I think for rendering bitmap subtitles, the pruning direction would have to be adjusted. (Not sure if reversing the timestamps before the subtitle renderer backend is even the right thing to do. At least for sd_ass.c, it seems to make sense, because it caches subtitles with "normal" timestamps.)
* Revert "options: move cursor autohiding opts to mp_vo_opts"dudemanguy2020-01-121-4/+4
| | | | This reverts commit 65a317436df05000366af2738bdbb834e95e33db.
* command, vo: add a mechanism for runtime DPI scale changeswm42020-01-091-0/+2
| | | | | Follow up to commit a58585d5e063. It turned out that the OSX backend needs this.
* player: make unpausing directly after seek work with --keep-openwm42019-12-301-0/+3
| | | | | | | | | | | | | | | When using --keep-open, and the end of the file is reached, the player's "pause" property is set to true. Attempting to set it to false reverts it back to true immediately. That's how it's designed, for better or worse. Running "seek -10 ; set pause no" did not work, because the seek is first queued and pause is unset, but then the decoding functions determine that EOF is still a thing, and "mpctx->stop_play = AT_END_OF_FILE;" is set again. handle_keep_open() then sets pause again. Only then the seek is actually run. Fix this by not setting stop_play if a seek is queued.
* client API: rewrite property observation (again)wm42019-12-191-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | I intend to rewrite this code approximately every 2 months. Last time, I did this in commit d66eb93e5d4 (and 065c307e8e7 and b2006eeb74f). It was intended to remove the roundabout synchronous thread "ping pong" when observing properties. At first, the original async. code was replaced with some nice mostly synchronous code. But then an async. code path had to be added for vo_libmpv, and finally the sync. code was dropped because it broke in other obscure cases (like the Objective-C Cocoa backend). Try again. This time, update properties entirely on the main thread. Updates get batched out on every playloop iteration. (At first I wanted it to make it every time the player goes to sleep, but that might starve API clients if the playloop get saturated.) One nice thing is that clients only get woken up once all changed events have been sent, which might reduce overhead. While this sounds simple, it's not. The main problem is that reading properties must not block the client API, i.e. no client API locks can be held while reading the property. Maybe eventually we can avoid this requirement, but currently it's just a fact. This means we have to iterate over all clients and then over all properties (of each client), all while releasing all locks when updating a property. Solve this by rechecking on each iteration whether the list changed, and if so, aborting the iteration and redo it "next time". High risk change, expect bugs such as crashes and missing property updates.
* command, vo: remove old option change notification mechanismswm42019-12-171-11/+0
| | | | | | | These all have been replaced recently. There was a leftover in window.swift. It couldn't have done anything useful in the current state of the code, so drop these lines.
* player: fix an outdated commentwm42019-12-141-2/+1
| | | | | The client API doesn't use input_ctx anymore, and the "wakeup" flag is gone (if it even existed at all).
* player: move point at which queued seeks are appliedwm42019-12-141-2/+3
| | | | | | | | | | | Do it after decoding etc., but before waiting for input. This seems to make more sense, because whether a queued seek can be applied depends on the playback state. So it sounds like a good idea to apply the seek first thing, but it's a bad idea to go to sleep if there's still a queued seek pending (that couldn't be processed earlier). Also add an empty line before mp_wait_events(); it doesn't really have to do with the filter bullshit.
* player: make repeated hr-seeks past EOF trigger EOF as expectedwm42019-12-141-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If you have a normal file with audio and video, and keep "spamming" forward hr-seeks, the player just kept showing the last video frame instead of exiting or playing the next file. This started happening since commit 6bcda94cb. Although not a bug per se, it was odd, and very user-noticable. The main problem was that the pending seek command was processed before the EOF was "noticed". Processing the command reset everything, so the player did not terminate playback, but repeated the seek. This commit restores the old behavior. For one, it makes video return the correct status (video.c). The parameter is a bit ugly, but better than duplicating the logic or having another MPContext field. (As a minor detail, setting r=VD_EOF makes sure have_new_frame() returns true, rather than going through another iteration or whatever the hell will happen instead, which would clobber logical_eof.) Another thing is making the seek logic actually wait until the seek outcome has been determined if audio is also active. Audio needs to wait for video in order to get the video seek target position. (Which in turn is because hr-seek still "snaps" to video frames. You can't seek in between two frames, so audio can't just use the seek target, but always has to wait on the timestamp of the video frame. This has other disadvantages and is a misdesign, but not something I'll fix today.) In theory, this might make hr-seeks less responsive, because it needs to fully decode/filter the audio too, but in practice most time is spent on video, which had to be fully decoded before this change. (In general, hr-seek could probably just show a random frame when a queued hr-seek overrides the current hr-seek, which would probably lead to a better user experience, but that's out of scope.) Fixes: #7206
* player: cosmetically restructure a small functionwm42019-12-141-7/+11
| | | | | No actual functional changes. Just preparation for the next commit, to reduce its diff.
* options: move cursor autohiding opts to mp_vo_optsdudemanguy2019-12-041-4/+4
| | | | | | Certain backends (i.e. wayland) will need to do special things with the mouse. It makes sense to expose the values of these options to them, so they can behave correctly.
* player: change m_config to use new option handling mechanismswm42019-11-291-7/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Instead of making m_config a special-case, it more or less uses the underlying m_config_cache/m_config_shadow APIs properly. This makes the player core a (relatively) equivalent user of the core option API. In particular, this means that other threads can change core options with m_config_cache_write_opt() calls (before this commit, this merely led to diverging option values). An important change is that before this commit, mpctx->opts contained the "master copy" of all option data. Now it's just another copy of the option data, and the shadow copy is considered the master. This is why whenever mpctx->opts is written, the change needs to be copied to the master (thus why this commits add a bunch of m_config_notify... calls). If another thread (e.g. a VO) changes an option, async_change_cb is now invoked, which funnels the change notification through the player's layers. The new self_notification parameter on mp_option_change_callback is so that m_config_notify... doesn't trigger recursion, and it's used in cases where the change was already "processed". It's still needed to trigger libmpv property updates. (I considered using an extra m_config_cache for that, but it'd only cause problems with no advantages.) I think the recent changes actually forgot to send libmpv property updates in some cases. This should fix this anyway. In some cases, property updates are reworked, and the potential for bugs should be lower (probably). The primary point of this change is to allow external updates, for example by a VO writing the fullscreen option if the window state is changed by the window manager (rather than mpv changing it). This is not used yet, but the following commits will.
* options: remove options-to-property bridgewm42019-11-251-1/+1
| | | | | | | | The previous bunch of commits made this unnecessary, so this should be a purely internal change with no user impact. This may or may not open the way to future improvements. Even if not, at least the property/option interaction should now be much less buggy.
* command: shuffle around even more crapwm42019-11-251-3/+6
| | | | | | | | | | | | | | | | | | Convert some remaining properties to work without the option-to-property bridge. Behavior shouldn't change (except for the corner case that it tries to reapply the new state when setting a property, while it used to ignore redundant sets). As it is the case with many of these changes, much of the code is not in its final proper state yet, but is rather a temporary workaround. For example, these "VO flag" properties should just be fully handled in the VO backend. (Currently, the config or VO layers don't provide enough mechanism yet as that all the backends like x11, win32, etc. could be changed yet, but that's another refactoring mess for another time.) Now nothing relies on this option-to-property bridge anymore, which opens the way to even more refactoring, which eventually may result in tiny improvements for the end user.
* player: remove some unnecessary coverart special caseswm42019-11-171-1/+0
| | | | | | | | These should not be needed, since video is in EOF mode in this case anyway. Not too sure about the video.c case to be honest, well, here goes nothing.
* player: enable "pause caching" code for local playback toowm42019-11-141-2/+1
| | | | | | | | There isn't really a need to disable this for local playback. I think originally I did this because I was afraid the code could mess up or be annoying on local mode, but that's not really a good argument. I'd rather test this code in local mode too. In this case, it shouldn't really happen that it runs out of cache in the first place.
* player: partially rework --cache-pausewm42019-10-111-6/+50
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The --cache-pause feature (enabled by default) will pause playback for a while if network runs out of data. If this is not done, then playback will go on frame-wise (as packets are slowly read from the network and then instantly decoded and displayed). This feature is actually useless, as you won't get nice playback no matter what if network is too slow, but I guess I still prefer this behavior for some reason. This commit changes this behavior from using the demuxer cache state only, to trying to use underrun information from the AO/VO. This means if you have a very large audio buffer, then cache-pausing will trigger once that buffer is depleted, which will be some time _after_ the demuxer cache has run out. This requires explicit support from the AO. Otherwise, the behavior should be mostly the same as before this commit. This does not care about the AO buffer. In theory, the AO may underrun, then the player will write some data to the AO buffer, then the AO will recover and play this bit of data, then the player will probably trigger the cache-pause behavior. The probability of this happening should be pretty low, so I will hold off fixing this until the next refactor of the AO chain (if ever). The VO underflow detection was devised and tested in 5 minutes, and may not be correct. At least I'm fairly sure that the combination of all the factors should make incorrect behavior relatively unlikely, but problems are possible. Also, the demux_reader_state.underrun field may be inaccurate. It's only the present state at the time demux_get_reader_state() was called, and may exclude past underruns. In theory, this could cause "close" cases to be missed. Then you might get an audio underrun without cache-pausing acting on it. If the stars align, this could happen multiple times in the row, effectively making this feature not work. The most user-visible consequence of this change is that the user will now see an AO underrun warning every time the cache runs out. Maybe this cache-pause feature should just be removed...
* playloop: don't read playback pos from byte streamDudemanguy9112019-09-211-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | If a file format supports PTS resets, get_current_pos_ratio calculates the ratio using the stored filepos in the demuxer struct instead of a standard query of the current time in the stream and its total length. This seems like a reasonable way to avoid weird PTS values, but in reality this just causes problems and results in inaccurate ratio values that can affect other parts of the player (most notably the osc seekbar). For libavformat formats, demux->filepos is obtained from the demux_lavf_fill_buffer function which is called on the next packet. The problem is that there is a slight delay between packets and in some cases, this delay can be relatively large. That means the obtained demuxer->filepos value will be very inaccurate since it obtains the pos from the end of the upcoming packet and not its actual current position. This is especially noticeable at the very beginning of playback where get_current_pos_ratio sometimes returns a value of well over 2% despite less than a second passing in the stream. Another telltale sign is to simply watch the osc seekbar as a stream progresses and observe how it loads in staggered steps as every packet is decoded. In contrast, the seekbar progresses smoothly on the playback of a format that does not support PTS resets. The simple solution is to instead use the query of the current time and length of a stream and calculate the ratio that way. get_current_pos_ratio will still fallback on using the byte stream position if the previous queries fail. However, get_current_time will be more accurate in the vast majority of cases and should be the preferred method of calculating the position ratio.
* player: ensure backward playback state is propagated on track switchingwm42019-09-191-2/+1
| | | | | |