| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Essentially, this lets video.c decide whether to consider a video track
cover art, instead of having the decoder wrapper use the lower level
sh_stream flag.
Some pain because of the dumb threading shit. Moving the code further
down to make some of it part of the lock should not change behavior,
although it could (framedrop nonsense).
This commit should not change actual behavior, and is only preparation
for the following commit.
|
|
|
|
|
|
|
| |
I don't see the point of this. Not doing it may defer an error to later.
That's OK? For now, it seems better to reduce the encoding internal API.
If someone can demonstrate that this is needed, I might reimplement it
in a different way.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This replaces the two buffers (ao_chain.ao_buffer in the core, and
buffer_state.buffers in the AO) with a single queue. Instead of having a
byte based buffer, the queue is simply a list of audio frames, as output
by the decoder. This should make dataflow simpler and reduce copying.
It also attempts to simplify fill_audio_out_buffers(), the function I
always hated most, because it's full of subtle and buggy logic.
Unfortunately, I got assaulted by corner cases, dumb features (attempt
at seamless looping, really?), and other crap, so it got pretty
complicated again. fill_audio_out_buffers() is still full of subtle and
buggy logic. Maybe it got worse. On the other hand, maybe there really
is some progress. Who knows.
Originally, the data flow parts was meant to be in f_output_chain, but
due to tricky interactions with the playloop code, it's now in the dummy
filter in audio.c.
At least this improves the way the audio PTS is passed to the encoder in
encoding mode. Now it attempts to pass frames directly, along with the
pts, which should minimize timestamp problems. But to be honest, encoder
mode is one big kludge that shouldn't exist in this way.
This commit should be considered pre-alpha code. There are lots of bugs
still hiding.
|
|
|
|
|
| |
Doesn't take paused_for_cache into account. For consistency; unlikely to
matter at all in practice.
|
|
|
|
|
| |
Forgotten in one of the previous commits. Also undeprecates
display-adrop since it's out of sight now.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This mode drops or repeats audio data to adapt to video speed, instead
of resampling it or such. It was added to deal with SPDIF. The
implementation was part of fill_audio_out_buffers() - the entire
function is something whose complexity exploded in my face, and which I
want to clean up, and this is hopefully a first step.
Put it in a filter, and mess with the shitty glue code. It's all sort of
roundabout and illogical, but that can be rectified later. The important
part is that it works much like the resample or scaletempo filters.
For PCM audio, this does not work on samples anymore. This makes it much
worse. But for PCM you can use saner mechanisms that sound better. Also,
something about PTS tracking is wrong. But not wasting more time on
this.
|
|
|
|
|
|
|
|
| |
Can be useful to force it to adapt to extreme speed changes, while a
higher limit would just use a fraction closer to the original video
speed.
Probably useful for testing only.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The wakeup at the end of VO frame rendering seems redundant, because
after rendering almost no state changes. The player core can queue a new
frame once frame rendering begins, and there's a separate wakeup for
this. The only thing that actually changes is in->rendering. The only
thing that seems to depend on it and can trigger a wakeup is the
vo_still_displaying() function. Change it so that it needs an explicit
call to a new API function, so we can avoid wakeups in the common case.
The vo_still_displaying() code is mostly just moved around due to
locking and for avoiding forward declarations.
Also a somewhat risky change (tasty new bugs).
|
|
|
|
|
|
|
|
|
| |
This should be unnecessary, since the VO itself performs wakeups once a
new frame can be queued. The only situation I can think of where this
might be required are EOF situations (which are always strange).
If I'm wrong, there'll be fun new bugs, probably causing frame drops or
temporary stalls.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The seeking logic saves the last video frame it has seen (for example
for being able to seek to the last frame, or backstepping).
Unfortunately, the frame was fed back to the filtering pipeline in
situations when it shouldn't have. Then it's an out of order frame,
because it really saves the last _discarded_ frame.
For example, seeking to the end of a file with --keep-open, shift+up,
shift+down => invalid video pts warning due to saved_frame being fed
back.
Explicitly discard saved_frame when it's obviously not needed anymore.
The removed accesses to "r" are strictly speaking unrelated (just
const-propagating them).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The VO underrun detection (just a weak heuristic) added in commit f26dfb
flagged the underrun state every time it was checked, and since the
check happened in every playloop iteration, this caused the playloop to
wake up itself on every iteration. It burned an entire core while in
this state.
Fix this by flagging this condition only once (as it should be), and
requiring that a frame is displayed to trigger it again. This makes it
work similar as the audio underrun check.
The bug report referenced below says --demuxer-thread=no avoided this.
This is because the demuxer layer doesn't do proper underrun reporting
if the reader thread is disabled.
Fixes: #7259
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Hr-seek has some sort of tolerance against timestamps, where it allows
for up to 5ms deviation. This means it can work only for videos with up
to 200 FPS framerate. There were complains about how it doesn't work
with videos beyond some high fps. (1000 was mentioned, although that
sounds more like it's about the limit that .mkv has.)
I suspect this is because otherwise, it might be hard to hit a timestamp
with --start, which specifies timestamps as integer, and thus will most
likely never represent a timestamp exactly. Another part of the problem
is that mpv uses 64 bit floats for timestamps, so fractional parts are
never represented exactly. (Both the "tolerance" and using floats for
timestamps were things introduced before my time.)
Anyway, in the backstep case, we can be relatively sure that the
timestamp will be exact (as in, the same unmodified value that was
returned by the filter chain), so we can make an exception for that, in
order to fix backstep.
Untested. (For that you have users.)
May help with #7208.
|
|
|
|
| |
A stupid thing that will probably be in the way.
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
| |
Until now, this didn't work, since the external image had pts 0; so
enabling video at a later time did nothing, because the image was
discarded. Since hrseek now ends on the last frame (instead of nothing),
reusing the hrseek mechanism solves this, and we don't even need to
treat the cursed coverart case separately.
|
|
|
|
|
|
|
|
|
|
|
|
| |
See what the added code comment says. Normally when this is needed, it's
the cover art case. But this flag is not set when using an external
image. This gives weird seek behavior, because the frame will be
"normally" displayed for its determined duration, and during normal
video playback, the video pts will be used - which is always 0 here.
This should happen only if audio is active. Otherwise, we're more or
less in image viewer mode, where the image should be displayed for a
configured duration.
|
|
|
|
|
|
|
|
|
|
|
|
| |
This gives much better behavior in general, and is what we want if video
somehow ends earlier than audio.
A common special is using an audio file with an external image file.
This commit makes things like switching aspect ratio work (provided the
demuxer for the image behaves correctly, which currently isn't the case
with demux_mf.c). Since the image file had timestamp 0, it was usually
skipped by hr-seek, and changed properties weren't applied to it at the
start of the filter chain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It appears commit 4ad68d94523c3d101a broke handling the first video
frame duration through roundabout ways (I think because the duration of
the first frame was now available at all in the normal case). The first
frame was cut short, which showed up especially with looping, or if the
file had a low FPS.
This questionable change seems to fix it without breaking any other
known cases => push and call it a day.
The display-sync mode did not have this problem.
Fixes: #7150
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
On a audio/video desync by more than 0.5 seconds, display-sync mode was
disabled, and not enabled again (until playback restart, e.g. a seek).
The idea was that it this only happens when this playback mode is broken
and can't perform well anyway (A/V desync is a clear indication that
something is very wrong). Instead of behaving like a god damn POS, it
should revert to the more robust audio-sync mode.
Unfortunately, this could happen sporadically due to temporary system
performance problems, such as toggling fullscreen. Users didn't like
this, and asked for a function to disable it, or to recover in some
other way.
This mechanism is questionable anyway. If an ignorant user enables
display-sync, and encounters problems with it (without being able to
determine that display-sync is messing up), the player will still behave
like a POS on every playback, and even after every seek. It might
actually be helpful to fail more consistently. Also, I've found that
it's sill relatively reliable anyway even without this mechanism.
So just remove the fallback.
Fixes: #7048
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Unless --video-latency-hacks, always decode 2 frames on playback
restart. This in turn will always compute the correct frame duration
(even for the first frame), which in turn happens to fix that playback
with an image at the beginning breaks display.
If a still image precedes video, and the size/format of the frame is
different from that of the video following it, the incorrect frame
duration caused vo_reconfig2() to be called early, causing the window to
resize, and the renderer to clear the image to black. Specifically, it
hit the default value of 1 second duration (for still images), so the
image was displayed for 1 second, and changed to black until the next
proper video frame was displayed.
Normally this does not happen. Even if a video file displays still
images, it normally repeats the still image at the video's FPS (which is
sane). But you can construct such files, or use EDL to construct
something similarly behaving.
This change may increase seek latency a bit in audio video-sync mode
(the default). It needs to wait until 2 frames are decoded, before it
bothers to display the first frame. This is done even when seeking. In
theory it might be good to introduce a "seek preview" mode, which shows
the target image without all the preparations needed for starting
playback. (For example, it could not decode audio.) But since I'm using
video-sync=display-resample, which already needed to always decode 2
frames, I don't think this is a terribly high priority, nor do I
consider the slightly slower seeking a regression.
Fixes: #6765
|
|
|
|
|
|
|
|
| |
Track switching doesn't run reset_playback_state(), so a track enabled
at runtime during backward playback would lead to a messed up state.
This commit just does a bad code monkey fix to this. It feels like there
needs to be a much better way to propagate this state.
|
|
|
|
|
|
|
|
| |
We need to transform the timestamp returned by get_play_end_pts().
I considered making it return the transformed timestamp directly. There
are 4 callers; 2 need a transformed timestamps, 2 don't. So I guess it
doesn't matter.
|
|
|
|
|
|
|
|
|
|
|
|
| |
E.g. "mpv null:// --demuxer=rawvideo" will "hang" by waiting for video
EOF forever. It's not signalled correctly because of the last-frame
corner case, which attempts to wait until the current frame is finally
displayed (which is signalled by whether a new frame can be queued, see
commit 1a339fa09d for some details). If no frame was ever queued, the VO
is not configured, and vo_is_ready_for_frame() never returns true.
Fix this by using vo_has_frame(), which seems to be exactly the correct
thing we need.
|
|
|
|
|
| |
If the container FPS is correct, this can help getting ideal mix factors
for vo_gpu interpolation mode. Otherwise, it doesn't matter.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Basically reimplement the async behavior on top of the async command
code. With this, all screenshot commands are async, and the "async"
prefix basically does nothing. The prefix now behaves exactly like with
other commands that use spawn_thread.
This also means using the prefix in the preset input.conf is pointless
(without effect) and misleading, so remove that.
The each_frame mode was actually particularly painful in making this
change, since the player wants to block for it when writing a
screenshot, and generally doesn't fit into the new infrastructure. It
was still relatively easy to reimplement by copying the original command
and then repeating it on each frame. The waiting is reentrant now, so
move the call in video.c to a "safer" spot.
One way to observe how the new semantics interact with everything is
using the mpv repl script and sending a screenshot command through it.
Without async flag, the script will freeze while writing the screenshot
(while playback continues), while with async flag it continues.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fixes several issues playing back mpegts with video streams marked
as having "still images". For example, see this video which has
frames only every 6s: https://s3.amazonaws.com/tmm1/music-choice.ts
Changes include:
- start playback right away, without waiting for first video frame
- do not consider the sparse video stream in demuxer underrun detection
- do not require multiple video frames for the VO
- use audio as the master stream for demuxer metadata events
- use audio stream for playback time
Signed-off-by: Aman Gupta <aman@tmm1.net>
|
|
|
|
|
|
|
|
|
|
|
|
| |
Until recently, ao_lavc and vo_lavc started encoding whenever the core
happened to send them data. Since audio and video are not initialized at
the same time, and the muxer was not necessarily opened when the first
encoder started to produce data, the resulting packets were put into a
queue. As soon as the muxer was opened, the queue was flushed.
Change this to make the core wait with sending data until all encoders
are initialized. This has the advantage that we don't need to queue up
the packets.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The video timing code could just decide that EOF was reached before it
was displayed. This is not really a problem for normal playback (if you
use something like --keep-open it'd show the last frame anyway,
otherwise it'd at best flash it on screen before destroying the window).
But in encode mode, it really matters, and makes the difference between
having one frame more or less in the output file.
Fix this by waiting for the VO before starting the real EOF.
vo_is_ready_for_frame() is normally used to determine when the VO frame
queue has enough space to send a new frame. Since the VO frame queue is
currently at most 1 frame, it being signaled means the remaining frame
was consumed and thus sent to the VO driver. If it returns false, it
will wake up the playloop as soon as the state changes.
I also considered using vo_still_displaying(), but it's not reliable,
because it checks the realtime of the frame end display time.
|
|
|
|
|
| |
This code makes the player wait using real time, which makes sense for
normal playback, but not encode mode.
|
|
|
|
|
|
|
|