There are two improvements here:
1) Correct the right-side padding on the title box. This was messed
up previously because I was passing the title box width when I
should be passing the x coordinate. I've also increased the
spacing to separate the title from the window controls more
clearly.
2) I'ved added a mouse tracking area over the title bar so that the
osc doesn't disappear if you hover over the title box. This didn't
work previously because the input area only covers the actual
window controls. The implementation here is simplified in that
it's only a mouse area and not an input area. This is enough to
keep the osc visible, but it won't stop the mouse pointer
disappearing. Fixing that requires a full input area which, for
now, I will say isn't worth the effort.
It's a bit unintuitive today when you use the un-maximise control
while fullscreened. Depending on the VO in use, this might silently
change the maximise state without any visible effect, or it might
do nothing. It's less surprising if the control exits the fullscreen
state.
Note that the exact behaviour is still VO dependent. If the window
was maximised before being fullscreened, it might exit fullscreen
back to maximised or back to regular window mode.
I thought about trying to explicitly control that behaviour but
it makes the osc code weird and probably wouldn't work all the time.
This code assumed that the function is only called from the playloop
itself (and since property notification is done at the end of it, i.e.
before sleeping, it obviously would not have needed to wake up the
core).
But this function is actually called from some comments (such as
playlist-move), so this assumption was incorrect. Use the same method as
the other function.
Untested.
Fixes: #7339 (probably)
This matches lua's 11b9315b but with the lagacy field names which the
js code used previously.
Currently the property always returns an object (with dummy/last/null
field values if there are no dimensions), but the code is ready for
a future case where it might return null if there are no dimensions - at
which case it will forward the null, breaking backward compatibility for
a better API.
The idea is that if the player is resized, we do not delay redrawing
(which is normally done to limit the redraw rate to something
reasonable).
Not sure if this even does anything. For one, reacting to osd-dimensions
changes is cleaner than just polling the screen size with the next tick
event, and hoping that resizes generate tick events for whatever
logically unrelated reasons.
check_obj_resize() in sub/osd.c calls mp_client_broadcast_event(), which
calls notify_property_events(). This is pretty unexpected, because
check_obj_resize() may be called from the VO thread. While that's sort
of awful, it seems to be OK locking-wise. But it breaks an assumption in
notify_property_events() that the core doesn't need to be woken up,
which could possibly lead to a missed/delayed property update (although
rather unlikely).
Fix this by explicitly waking up the core when it's called from the OSD
code.
This is a gross hack for the shitty design of how VO properties are
handled (which was fine with MPlayer, but became increasingly a shit tub
with mpv's VO thread).
The problem here is that console.lua reads display-hidpi-scale on every
render, but which may take a long time for video timing and vsync
blocking. It will also block the core, making osc.lua unable to react to
window resizing quickly enough.
This should be solved by not using the "classic" blocking VOCTRL
mechanism, and instead side-stepping it with something that doesn't
require any waiting (like for example the "fullscreen" property does).
But this require more thinking and work my "brain" can handle at the
moment. So for now add a shitty hack that will cause a lot of problems,
and which will have to be replaced later. Most importantly, it'll break
theoretic support for multiple screens with different DPI, or runtime
DPI changes. Possibly could affect the Cocoa backend; the X11 isn't
dynamic enough by nature, and other backends do not implement this.
See previous commit.
A nice side-effect is that mp.get_osd_margins() is not a special
Lua-only thing anymore. I didn't test whether this function still works
as expected, though.
This "bundles" all OSD properties. It also makes some previously
Lua-only values available (Lua has mp.get_osd_margins(), unsure if
anything uses it).
The main intention is actually to allow retrieving all fields in an
"atomic" way. (Could introduce a mechanism on the level of the mpv
client API to do this, but doing ti ad-hoc all the time like this commit
is easier.)
The change was not propagated to the OSD/subtitle code, since that still
uses an "old" method. Change it so that the propagation is actually
performed.
(One could argue the OSD/subtitle code should use other ways to update
the options, but that would probably be more effort for now.)
Currently, the activation and deactivation of input handling is done
inside the render() loop, but this does not run when the osc mode is
`never` - which does make sense.
That means that if you are cycling the visibility mode, the input
state will be whatever it was at the time of the mode change. And,
as our modes are ordered `auto` -> `always` -> `never`, the input
state will be enabled when you cycle to `never`.
There are various ways you can imagine fixing this, and in this
change I propose we reset the input state to disabled on a mode
change, and then let render() re-enable input if that's appropriate.
Fixes#7298.
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.
Although a linked list was ideal at first, there are cases where it
sucks, and became increasingly awkward (with the mpv command API
preferring integer indexes to access the list). In future, we probably
want to add more playlist-related functionality, so better change it to
an array now.
An array isn't always ideal either. Since playlist entries are still
separate objects (because in some cases you need a stable "iterator" to
it), but you still need to efficiently get the next/previous playlist
entry, there's a pl_index field, that needs to be maintained. E.g.
adding an entry at the start of the playlist => update the pl_index
field for all other entries. Well, it's not really worth to do something
more complicated to avoid these things.
This commit is probably buggy as shit. It's not like I bothered to test
everything. That's _your_ role.
It's not really great. But I think it's good enough to save someone
who's lost. Most importantly, it should become obvious _what_ the
console expects (input commands), and how to exit it.
Would be nice if we could show some documentation, or give a link to
documentation, but that's out of scope and/or not easy.
I considered implementing the "help" command as builtin command in
command.c. On the other hand, this could not show console.lua specific
help, so I implemented it in console.lua. The ad-hoc command parsing
(that sort-of mirrors mpv input command syntax) for the "help" command
is probably the worst part of this.
It's deprecated. The new solution works almost exactly the same way
(since the still existing internal tick event triggers vsync-jitter
change command), though as far as API usage goes, it's somewhat
questionable. (The comment is meant to discourage anyone trying to copy
the idea for external scripts.)
This affects behavior when using the "del" default key binding.
Sometimes, setting visibility to always did not draw it correctly. This
probably fixes it.
Implemented using one-time idle observer (i.e. setTimeout), to avoid
additional function call(back) every time the event loop enters idle.
The lua mp.flush_key_bindings() is also available, also undocumented.
A minority of users have expressed a dislike of hats, calling them
"cancer [that] don't belong in software" describing the people who add
them as "shitty circlejerks" and "chucklefuck."
While I personally disagree with those opinions, it's probably easier
to let them have it their way. For that reason this adds the option
`greenandgrumpy` to the osc, which allows users to disable the hat.
libass uses integers for PlayResX/Y, so the osd-overlay command also
does. Lua (pre-5.3) does not have an integer type, but the command
interface makes a difference anyway. If you pass a Lua number with a
fractional part to an integer parameter (using mp.command_native()), it
will result in an error and complain about incompatible types.
I think that's fine, but since this behavior extends to
mp.set_osd_ass(), this is a compatibility problem.
Fix this by explicitly coercing the resolution parameters to integer
numbers.
The main reason for this is just to make show the OSC always above
console.lua, instead of a random order.
(And this is also the only reason osc.lua was changed to the new API.
The old API could have been extended, but lets not.)
This tries to avoid the update() call if nothing changed. This brings it
more into line with the old code (the osd-overlay command simply does
not skip the update if nothing changed). I don't know whether this
matters; most likely not. Normally, code should try to avoid redundant
updates on its own, so it's not the job of the command. However, for the
OSC we simply want to reduce the differences.
Lua scripting has an undocumented mp.set_osd_ass() function, which is
used by osc.lua and console.lua. Apparently, 3rd party scripts also use
this. It's probably time to make this a public API.
The Lua implementation just bypassed the libmpv API. To make it usable
by any type of client, turn it into a command, "osd-overlay".
There's already a "overlay-add". Ignore it (although the manpage admits
guiltiness). I don't really want to deal with that old command. Its main
problem is that it uses global IDs, while I'd like to avoid that scripts
mess with each others overlays (whether that is accidentally or
intentionally). Maybe "overlay-add" can eventually be merged into
"osd-overlay", but I'm too lazy to do that now.
Scripting now uses the commands. There is a helper to manage OSD
overlays. The helper is very "thin"; I only want to force script authors
to use the ID allocation, which may help with putting multiple scripts
into a single .lua file without causing conflicts (basically, avoiding
singletons within a script's environment). The old set_osd_ass() is
emulated with the new API.
The JS scripting wrapper also provides a set_osd_ass() function, which
calls internal mpv API. Comment that part (to keep it compiling), but
I'm leaving it to @avih to finish the change.
Lua scripting implements key bindings by defining an input section with
all the bindings in it. Every add_key_binding() call ran a mpv command
to update this section. This caused a lot of spam at debug log levels.
Reduce the spam and more it efficient by batching updates into a single
mpv command when the script becomes inactive. This is pretty simple,
because there's already the concept of idle handlers.
This requires that the script actually goes to sleep, which might not
happen in various extremely bogus corner cases, such as polling the mpv
message queue with active waiting. Just don't do that.
During the 12th month (checked during script initialization), draw a Santa hat
on top of the idle message's logo.
Slightly refactors and optimizes the drawing process as well: reorder original
logo layers and remove redundant holes in them, use a shared line prefix
to clear the style and set start position.
Signed-off-by: wm4 <wm4@nowhere>
Now that 00af718a made the lua read_options behavior much more similar
to the js behavior, the main difference was that lua does not re-read
the config file at on_update (but it does re-apply its stored content)
while js did re-read it.
Now the js on_update also does not re-read the config file and instead
applies its stored original content.
This is slightly hacky by adding an undocumented optional 4th argument
to read_options which allows overriding the config file content.
Make sure it gets properly reinitialized when needed. This is especially
useful now that the OSC reacts to runtime option changes, which can
change the layout too.
This may call set_property_number() on the margin properties more often
now, but since redundant option changes are ignored now, this shouldn't
have any too bad effects.
Fuck it, just let's just reinit everything.
On a side note, the changelist parameter provided by read_options()
(here "list") is now unused. But it's not hard to provide and might be
useful for other stuff. So don't remove it from the generic
read_options() code.
As described in the manpage changes. This makes more sense than the
previous approach, where options could "unexpectedly" stick. Although
this is still a somewhat arbitrary policy (ask many people and you'd get
a number of different expectations on what should happen), I think that
it reflects what mpv's builtin stuff does.
All the copying is annoying, but let's just hope nobody is stupid enough
to change these properties per video frame or something equally
ridiculous.
This is a bit different than the lua code: on script-opts change it
simply re-applies the conf-file and script-opts to the options object,
and if this results in any changed value at options then on_update is
called with the changelist as argument.
This allows a value to revert back to the conf-file value if the
matching script-opts key had a different value and then got deleted.
It also guarantees to call back whenever the options object is
modified, which the lua code doesn't do (e.g. if the caller changed
a value and the observer changed it back - it won't detect a change).
With special attention to changing osc-visibility. Untested, although
osc-visibility works (it's pretty much equivalent to the key binding, so
there is not much interesting going on).
Somewhat inspired by code posted by github user CogentRedTester.
Fixes: #4513
The way how this modifies and backups/restores user option values is a
bit of a problem for runtime option changing.
Clean this up a little. Now cycling the visibility updates the user
option value, but always to "valid" values (unlike hidetimeout used to
be used). If the user option value is changed externally (enabled by a
later commit), it'll be cleanly overwritten.
I decided to factor this into the user's scale option (instead of
somehow using it as default if the user has not specified it), because
it makes the option handling simpler, and won't break things like
per-screen DPI if the user only wants to scale the console font by a
factor.
mpv has a very weak and very annoying policy that determines whether a
playlist should be used or not. For example, if you play a remote
playlist, you usually don't want it to be able to read local filesystem
entries. (Although for a media player the impact is small I guess.)
It's weak and annoying as in that it does not prevent certain cases
which could be interpreted as bad in some cases, such as allowing
playlists on the local filesystem to reference remote URLs. It probably
barely makes sense, but we just want to exclude some other "definitely
not a good idea" things, all while playlists generally just work, so
whatever.
The policy is:
- from the command line anything is played
- local playlists can reference anything except "unsafe" streams
("unsafe" means special stream inputs like libavfilter graphs)
- remote playlists can reference only remote URLs
- things like "memory://" and archives are "transparent" to this
This commit does... something. It replaces the weird stream flags with a
slightly clearer "origin" value, which is now consequently passed down
and used everywhere. It fixes some deviations from the described policy.
I wanted to force archives to reference only content within them, but
this would probably have been more complicated (or required different
abstractions), and I'm too lazy to figure it out, so archives are now
"transparent" (playlists within archives behave the same outside).
There may be a lot of bugs in this.
This is unfortunately a very noisy commit because:
- every stream open call now needs to pass the origin
- so does every demuxer open call (=> params param. gets mandatory)
- most stream were changed to provide the "origin" value
- the origin value needed to be passed along in a lot of places
- I was too lazy to split the commit
Fixes: #7274
For some inexplicable reason, the OSC runs the expand-text command a
_lot_. This command is logged at the log file default log level, so the
log file can quickly fill up with these messages. It directly violates
the mpv logging policy: per-frame (or similarly common) log messages
should not be enabled by default for the log file.
stats.lua uses the show-text command for some reason (instead of
creating its own OSD layer).
Explicitly reduce the log level for expand-text and some other commands.
Also reduce the log level for commands triggered by mouse movement.
The previous commit also contributed some to reduce log spam.
Fixes: #4771
Traditionally, the OSC used mpv's "tick" event, which was approximately
sent once per video frame. It didn't try to track any other state, and
just updated everything.
This is sort of a problem in many corner cases and non-corner cases. For
example, it would eat CPU in the paused state (probably to some degree
also the mpv core's fault), or would waste power or even throw errors
("event queue overflows") on high FPS video.
Change this to not using the tick event. Instead, react to a number of
property change events. Rate-limit actual redrawing with a timer; the
next update cannot happen sooner than the hardcoded 30ms OSC frame
duration. This has also the effect that multiple successive updates are
(mostly) coalesced.
This means the OSC won't eat your CPU when the player is fucking paused.
(It'll still update if e.g. the cache is growing, though.) There is some
potential for bugs whenever it uses properties that are not explicitly
observed. (In theory we could easily change this to a reactive concept
to avoid such things, but whatever.)
I intend to rewrite this code approximately every 2 months.
Last time, I did this in commit d66eb93e5d (and 065c307e8e and
b2006eeb74). 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.
This is for console.lua (see next commit). The idea is that console.lua
can adjust its offset to the bottom of the window by the height of the
OSC.
If the OSC is not set to permanently visible, export no margins, because
it would look weird to move the console depending on the mouse movement.
Very primitive and dumb, but fulfils its purpose for the next commits.
I chose this specific implementation because it has the lowest footprint
in command.c, without resorting to crazy hacks such as sending messages
between scripts (which would be hard to coordinate especially on
startup).
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.
The generic change detection now handles this just as well.
The way how this function is manually called at init is slightly gross.
Make that part slightly more explicit to hopefully avoid confusion.
This is similar to the "edition" change.
I considered making this go through deprecation, but didn't have a good
idea how to do that. Maybe it's fine, because this is pretty obscure.
But it might break some API users/scripts (it certainly broke
stats.lua), and all I have to say is sorry for that.
See manpage/changelog changes.
The purpose of this change is to removes another case of inconsistent
property behavior. At first I wanted to make this go through deprecation
before making a technically incompatible change, but then I considered
this feature too obscure as that anyone would care.
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
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.
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
I missed adding this when defining the style used for the video
title in the window control bar. The default behaviour is to wrap,
but we want to cut the title off when we run out of space.
I was recently informed that unicode has official symbols for
window controls, and I put together a change to use them, which
worked, as long as a suitable font was installed. However, it's
not that hard to get a normal system that lacks an appropriate
font, and libass wants to print warnings if the symbols aren't
in the default font, which will almost always be true.
So, I gave up and added the symbols to the custom osd font that
we already have. This ensures they are always available, and
that they are aligned consistently on all platforms.
I took the symbols from the `symbola` font, as this has a suitable
licence and the symbols look nice enough.
Symbola Licence:
Fonts are free for any use; they may be opened, edited,
modified, regenerated, packaged and redistributed.
Finally, as we now have access to an un-maximize symbol, I added
logic to use it when the window is maximized.
I had previously wondered whether to do this, but in my testing
with x11 and wayland, the osc was being re-inited on a border
toggle already so I didn't add it.
However, on win32, things are different and there is no re-init
when toggling borders. I belive this is because the active window
size doesn't change in anyway, while on x11/wayland, toggling the
border actually changes the window size - and that trigger a re-init.
So, let's just be explicit and request a re-init when the border
is toggled.
Merged from mpv-repl git repo commit 5ea2bf64f9c239f0326b02. Some
changes were made on top of it:
- Tabs were converted to 4 spaces indentation (plus some manual
indentation fixes in some places).
- All user-visible mentions of "repl" were renamed to "console".
- The README was converted to a manpage (with heavy changes, some
additions taken from stats.rst; rossy converted the key bindings
table to RST).
- The method to change the default key binding was changed.
- Change minor detail about "font" default value setting (not a
functional change).
- Integrate into the player as builtin script, including an option to
prevent loading it.
Above changes and commit message done by wm4.
Signed-off-by: wm4 <wm4@nowhere>
Later calls to mp.add_key_binding() should take priority over previous
calls with the same key. Until now, the order was random (due to using
table pairs() iteration order).
Do this by simply sorting by a counter that is never reset. Since
input.c also gives later bindings priority, this works out.
Calling mp.remove_key_binding() on a newer binding makes an older still
existing binding with the same key active again. New bindings override
older ones, but do not overwrite them. I think these are good semantics
for most use cases.
(Note that the Lua code cannot determine whether two bindings use the
same key. Keys are strings, and two different strings could refer to the
same key. The code does not have access to input.c's key name
normalization, so it cannot compare them.)
Since the recent option changes (probably b16cea750f), using the "vf"
or "af" commands to change the filter chain did not write the option
value correctly. This led to the option value being reset the next time
an option changed.
This happened because the new option value was not copied to the
m_config_cache's internal storage. So on the next option update, it
looked like the option value changed, because the user-side value was
different from the internal value. It was copied back, which meant the
original option value was reinstated, and the previous "vf"/"af" command
was undone.
Fix this by using the correct way to store the option value. This also
takes care of property change notification (because the function is
specifically separate from m_config_cache_write_opt() to do that), so
remove the old call.
Fixes: #7220
Both the "stop" and "loadfile" commands are asynchronous. "stop" starts
terminating playback, which used to be done in the same playloop
iteration, but now it may take longer, so a "loadfile" command can be
received while this is going on. (Possible that it used to work if the
second command was issued at least in the next playloop iteration.)
Make the "loadfile" override the "stop" mode, so the next file will be
played, instead of quitting or going into idle mode.
Unlike the referenced bug report claims, this has nothing to do with
IPC.
Fixes: #7225
To aid in discoverability, and to address the most common case
directly, I'm adding an 'auto' mode for the window controls. In
this case, we will show the controls if there is no window border
and hide them if there are borders. This also respects the option
being toggled at runtime.
To ensure that it works in the wayland case, I've also made sure
that the wayland code explicitly forces the option to false if
decoration support is missing.
Based on feedback, I've split the config in two, with one option
for whether controls are active, and one for alignment. These are
new enough that we can get away with ignoring compatibility.
As preparation for adding the auto mode for window controls, we need
to make sure that the controls can be successfully toggled at runtime,
rather than only being able to configure them once at startup. Right
now, there is a problem with the handling of the show/hide zone for
the window controls.
The previous fix for #7212 was to avoid registering the input mapping
for the window control show/hide zone. If there is no input mapping,
then there is no input, and the zone is a no-op, even if it exists.
But this only happens at startup. After that point, the input mapping
doesn't exist and cannot be turned on.
In this change, I'm switching the approach; we now go back to always
registering the input mapping, and instead, we zero out the show/hide
zone if window controls are disabled, and set its size appropriately
if they are enabled.
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.
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.
I always intended for this to be accepted and mean "right" but I
made it show an error for any value that's not explicitly
recognised (while considering all unrecognised values to mean "right").
So let's explicitly recognise "yes".
I wanted to get this done quickly as I introduced the new VOCTRL
behaviour for minimize and maximize and it was immediately made
legacy, so best to purge it before anyone gets confused.
I did not sort out fullscreen as that's more involved and not something
I've educated myself about yet. But I did replace the VOCTRL_FULLSCREEN
usage with the new option change mechanism as that seemed simple
enough.
This is necessary to avoid breaking input behaviour in the 'idle'
state when not playing a video. Otherwise, the mouse area starts off
covering the whole window and blocks normal input.
Commit 311cc5b6 added the ability use flags while omitting name, but
broke the case where both name and flags are omitted.
Now omitting either name or flags or both works as documented.
It seems logical to account for the window controls if `boxvideo`
is in use (which has the effect of reducing the size of the video
so that the osc is not covering the video).
Properties should handle this themselves. This basically sent redundant
notifications. I found only two places where the "proper" notification
was missing.
Now that the option-to-property bridge is gone, this is not needed
anymore. It always took the "silent" path.
Also, at least as of before this commit, this didn't correctly print a
warning when accessing a deprecated option as property. This was because
m_config_get_co_raw() was used, which intentionally does not print any
warnings, so switch to the non-raw one. (Affects only options that have
.deprecation_message set.)
I missed these due to only testing with my personal osc config.
The deadzone needs to be correctly handled for the window controls,
or they will fail to appear when the mouse is close to or over them.
In the process of doing that, I realised that the controls should
respect the barmargin, if set. This is because the controls should
remain aligned when layout=topbar and as the control bar is top
aligned, it should be equally affected if the user needs to set
the barmargin.
I also fixed a mistake in trying to the use the mpv-osd-symbols font
for the window controls.
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.
Just an implementation detail that can be cleaned up now. Internally,
m_config maintains a tree of m_sub_options structs, except for the root
it was not defined explicitly. GLOBAL_CONFIG was a hack to get access to
it anyway. Define it explicitly instead.
Today, if window decorations are not present, either because they were
disabled, or because the platform doesn't support them
(eg: gnome-shell on wayland), there are no window controls, meaning it
is not possible to minimize/maximize/close a window without knowing
keyboard shortcuts.
While you can imagine various ways of offering client side decorations,
it is attractive to consider using OSC because that is functionality
that we already have.
The main work here is defining a separate input area from the main
OSC box with its own buttons, etc.
While we could probably handle auto-detection based on whether
decorations are present or not, it's manually controlled for now.
The window control logic is mostly disconnected from the OSC itself,
except in the case of the `topbar` layout, where there has to be
coordination so that the controls don't get drawn on top of each other.
I had to do fine-positioning of the buttons based on the font on
my system, so don't be surprised if it looks wrong elsewhere.
You could also argue that window controls should be unscaled, even
if the main OSC box is scaled, but I've not tried to do this.
If we want to implement window pseudo-decorations via OSC, we need a
way to tell the vo to minimize and maximize the window. Today, we have
minimized as a read-only property, and no property for maximized.
Let's made minimized settable and add a maximized property to go with
it. In turn, that requires us to add VOCTRLs for minimizing or
maximizing a window, and an additional WIN_STATE to indicate a
maximized window.
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.
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.
The behavior is slightly different in a messy way. The change is in line
with the option-to-property bridge removal mentioned some commits ago
and thus is deemed necessary.
This attempted to restore the old filter chain if setting a new one at
runtime failed. This is not needed anymore, because changing the filter
chain is done in a "transactional" way now.
This is preparation to get rid of the option-to-property bridge
(mp_on_set_option). This is a pretty insane thing that redirects
accesses to options to properties. It was needed in the ever ongoing
transition from something to... something else.
A good example for the need of this bridge is applying profiles at
runtime. This obviously goes through the config parser, but should also
make all changes effective, for which traditionally the property layer
is used.
There isn't much left that needs this bridge. This commit changes a
bunch of options (which also have a property implementation) to use
option change notifications instead. Many of the properties are still
left, but perform unrelated functions like OSD formatting.
This should be mostly compatible. There may be some subtle behavior
changes. For example, "hwdec" and "record-file" do not check for changes
anymore before applying them, so writing the current value to them
suddenly does something, while it was ignored before.
DVB changes untested, but should work.
add_key_binding() makes the name argument optional (in weird Lua
fashion), which did not work if there were additional arguments. So
there is no way to avoid specifying a name while passing a rp argument.
Fix this, declare this way of skipping the argument as deprecated, and
allow passing name=nil as the preferred way to skip the name argument.
Read-only information about all bindings. Somewhat hoping someone can
make a nice GUI-like overlay thing for it, which provides information
about mapped keys.
No reason to have this as bstr, just makes everything more complex.
Also clear mp_cmd.sender when it's copied. Otherwise it would be a
dangling pointer. Apparently it's never set to non-NULL in this
situation, but this is cleaner anyway.
Particularly for "any_unicode" mappings, so they don't have to
special-case keys like '#' and ' ', which are normally mapped to
symbolic names for input.conf reasons. (Though admittedly, this is a
pretty minor thing, since API users could map these manually.)
I often watch sporting events. On many occasions I get files with the
same filename for each session. For example, for F1 I might have the
following directory structure:
F1/
FP1.mkv
FP2.mkv
FP3.mkv
Qualification.mkv
Race.mkv
Since usually one simply watches one race after the other, I usually
just rsync the new event's files over the old ones, so, for example,
Race.mkv will be replaced from the file for the last event with the file
from the new event.
One problem with this is that I like to use --resume-playback for other
kinds of media, so I have it on by default. That works great for, say, a
movie, but doesn't work so well with this scheme, because you can
trivially forget to pass --no-resume-playback on the command line and
end up 2 hours in, watching spoilers as the race results scroll down the
screen :-)
This patch adds a new option, --resume-playback-check-mtime, which
validates that the file's mtime hasn't changed since the watch_later
configuration was saved. It does this by setting the watch_later
configuration to have the same mtime as the file after it is saved.
Switching back and forth between checking mtime and not checking mtime
works fine, as we only choose whether to compare based on it, but we
update the watch_later configuration mtime regardless of its value.
As preparation for making repl.lua part of the core (maybe), add some
mechanisms which are supposed to improve its behavior.
Add a silent mode. Calling mpv_request_log_messages() with the log level
name prefixed with "silent:" will disable logging from the API user's
perspective. But it will keep the log buffer, and record new messages,
without returning them to the user. If logging is enabled again by
requesting the same log level without "silent:" prefix, the buffered log
messages are returned to the user at once. This is not documented,
because it's far too messy and special as that I'd want anyone to rely
on this behavior, but it will be perfectly fine for an internal script.
Another thing is that we record early startup messages. The goal is to
make the repl.lua script show option and config parsing file errors.
This works only with the special "terminal-default" log level.
In addition, reduce the "terminal-default" capacity to only 100 log
messages. If this is going to be enabled by default, it shouldn't use
too much resources.
This will just make it not work if mpv_request_log_messages() gets
extended to accept more names. Pass the argument without checking.
To keep the behavior the same (for whatever reasons, probably not
important), still raise an error if the libmpv API function returns an
error that the argument was bad.
(The check_loglevel() function is still used when the script _emits_ log
messages, which is different, and for which there is no API anyway.)
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's too easy to introduce unintended circular lock dependencies. Just
now we found that the (old) cocoa vo_gpu backend is also affected by
this, because it waits on the Cocoa main thread, which in turn uses
libmpv API for OSX... stuff.
Also fix a missing initial property update after observe.
This leaves me unhappy, because it just leads to a stupid thread ping
pong. Will probably rewrite this later.
It appears commit 4ad68d9452 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
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.
Used to contain flags for "save" setting of options at runtime. Now
there is nothing special needed anymore and it's 0. So drop it
completely, and remove anything that distinguishes between runtime and
initialization time.
Until now, each .c file in test/ was built as separate, self-contained
binary. Each binary could be run to execute the tests it contained.
Change this and make them part of the normal mpv binary. Now the tests
have to be invoked via the --unittest option. Do this for two reasons:
- Tests now run within a "properly" initialized mpv instance, so all
services are available.
- Possibly simplifying the situation for future build systems.
The first point is the main motivation. The mpv code is entangled with
mp_log and the option system. It feels like a bad idea to duplicate some
of the initialization of this just so you can call code using them.
I'm also getting rid of cmocka. There wouldn't be any problem to keep it
(it's a perfectly sane set of helpers), but NIH calls. I would have had
to aggregate all tests into a CMUnitTest list, and I don't see how I'd
get different types of entry points easily. Probably easily solvable,
but since we made only pretty basic use of this library, NIH-ing this is
actually easier (I needed a list of tests with custom metadata anyway,
so all what was left was reimplement the assert_* helpers).
Unit tests now don't output anything, and if they fail, they'll simply
crash and leave a message that typically requires inspecting the test
code to figure out what went wrong (and probably editing the test code
to get more information). I even merged the various test functions into
single ones. Sucks, but here you go.
chmap_sel.c is merged into chmap.c, because I didn't see the point of
this being separate. json.c drops the print_message() to go along with
the new silent-by-default idea, also there's a memory leak fix unrelated
to the rest of this commit.
The new code is enabled with --enable-tests (--enable-test goes away).
Due to waf's option parser, --enable-test still works, because it's a
unique prefix to --enable-tests.
They were used at some point, but then fell into disuse. In general,
these old flags are all a bit fuzzy, so it's a good idea to remove them
as much as possible.
The comment about MP_IMGFLAG_PAL isn't true anymore. The old meaning was
deprecated at some point, and the flag was removed from "pseudo
paletted" formats. I think mpv at one point changed its own flag from
AV_PIX_FMT_FLAG_PSEUDOPAL to AV_PIX_FMT_FLAG_PAL, when the former was
deprecated, and it became unnecessary to allocate a palette for
non-paletted formats. (The one who deprecated in FFmpeg was me, if you
wonder.)
MP_IMGFLAG_PLANAR was used in command.c, use a relatively similar flag
as replacement.
Make the existing "not found" messages debug only, and add a new verbose
message if a config file was opened. The idea is that logging should
make it apparent whether or not config files are loaded, and it's more
common to use scripts without config files, leading to fewer log
messages in verbose mode.
Lots of dumb crap to do... something. Instead of adding yet another dumb
helper, just use the main" sws_utils API in both callers. (Which,
unfortunately, has been duplicated for glorious webp screenshots,
despite the fact that webp is crap.)
Good part: can enable zimg for screenshots (as far as needed).
Bad part: uses "default" swscale parameters instead of HQ now.
In theory, it's better to keep the old value, because that's more
consistent with the logic of using change timestamps. With the current
code, the old value will probably never be used (instead it will fetch a
new value on every change), so this shouldn't make a difference in
practice.
In commit 065c307e8e, I broke everything. It seemed like a nice idea,
but it explicitly broke an assumption vo_libmpv were explicitly allowed
to make: that observing properties does not lock the core. The commit
did just that and locked the core for property updates. This made for
example mpv's own OSX backend freeze (it uses vo_libmpv for convenience
to make up for Apple's incredibly broken OpenGL shit).
I don't want to revert that commit just because vo_libmpv's design is
horrible. So instead add an optional asynchronous path, that is only
used if vo_libmpv is in use (best idea ever?).
Interestingly, this isn't so hard. It adds about 90 lines of code, which
are only run on OSX and libmpv users, so I don't have to care about the
crashes and weird behavior this might cause. It even worked on the first
try except for a quickly fixed memory leak. The code path can be tested
anywhere by just turning the uses_vo_libmpv condition into always true.
The atomic is out of laziness. Saves some thinking how to get around the
locking order.
The commit linked below added temporary unlocking to update_prop(),
which is indirectly called by mpv_wait_event(). If an unlock happens,
and no property change event is returned, we must re-poll the event
queue. Rechecking the state on unlocks is basically a standard
requirement for code using condition variables.
Untested beyond a simple test.
Fixes: 065c307e8e
Property change notification works by having the mpv core wake up all
clients observing a property when the property potentially changes. The
clients then read the property's value, and determine if there was an
actual change. (The latter part depends what the property returned for
the previous change notification, so it depends on the client, and
cannot be generated by the core itself.)
Until now, reading the property value was done in a pseudo-async way by
queuing a callback back to the core, running it there, and then waking
up the client thread again. I cannot comprehend why this was done in
such a complicated, fragile way. Maybe it's a leftover from times when
client.c had to do this (in short, because properties could access
vo_opengl, which has thread-local state).
One past idea was to make the implementation of true async properties
easier (for which you would need such a state machine anyway). But they
don't exist yet, and I doubt the current mess would be really helpful
when actually implementing them.
Simplify this, and run the update in the client's thread directly. In
addition to the fundamental change, many roundabout things can be
removed as a consequence.
Unfortunately, I noticed that lock order issues force you to release
ctx->lock before doing so, which makes things more complex due to
possible concurrent mpv_unobserve_property() calls. Solve this by
removing properties lazily, which means you may have to do multiple
mpv_wait_event() calls before the property entry is actually destroyed.
This should not matter in practice, and does not affect the semantics.
It could also cause "leaks" by observing/unobserving properties in a
loop, without ever calling mpv_wait_event(). Just don't do this, duh.
(I considered making this dependent on whether the previous
mpv_wait_event() call returned the property being removed, but a
separate code path seemed too complicated. I also considered copying the
name and property data when returning a MPV_EVENT_PROPERTY_CHANGE, but
actually this doesn't solve the problem of update_prop() being
interrupted by mpv_unobserve_property(); there are ways around it, but I
just said no.)
This was made using the cowboy coding software engineering methodology.
If you find any bugs, keep them yourself.
Apparently this was only added and used for cache update stuff, which
was changed in commit 8dbc93a94c. Now it's unused, messy, ugly, and
is in the way, so get rid of it.
Since a track may not be selected twice, it makes sense e.g. for
secondary subtitles to select the next best match and avoid the
duplicate selection.
This allows for example `--slang=en,ja --secondary-sid=auto` to select
'en' as primary and 'ja' as secondary without needing to know the actual
sid for 'ja'.
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
Some failures by youtube-dl prompt the user to submit a bug report.
If such a failure occurs, we can compare youtube-dl's version to the
current calendar date to see how old it is. We don't make this check
on every youtube-dl failure, as failing to extract an URL is quite
common, and waiting for a second blocking python interpreter startup
for every such case would be a bit unpleasant.
Here the assumption is made that any youtube-dl version older than
3 months is probably severely out of date. Users will be warned about
this.
We also output the trimmed stderr of youtube-dl with msg.error, as this
appeared to have been the behaviour of utils.subprocess without stderr
capturing. Since this uses mp.command_native now, we'll have to do this
ourselves where appropriate.
mpv warned if the FFmpeg runtime library version was not exactly the
same as the build version. This seemed to cause frequent conflicts. At
this point, most mpv code probably adheres to the FFmpeg ABI rules, and
FFmpeg stopped breaking ABI "accidentally". Another source of problems
were mixed FFmpeg/Libav installations, something which nobody does
anymore. It's not "our" job to check and enforce ABI compatibility
either. So I guess this behavior can be removed.
OK, still check for incompatible libraries (according to FFmpeg
versioning rules), i.e. different major versions, or if the build
version is newer than the runtime version. For now.
The comment about ABI problems is still true. In particular, the
bytes_read field mentioned in the removed comment is still accessed, and
is still an ABI violation. Have fun.
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...
AOs can now call ao_underrun_event() (in any context) if an underrun has
happened. It will print a message.
This will be used in the following commits. But for now, audio.c only
clears the underrun bit, so that subsequent underruns still print the
warning message.
Since the underrun flag will be used in fragile ways by the playback
state machine, there is the "reports_underruns" field that signals
strong support for underrun reporting. (Otherwise, underrun events will
not be used by it.)
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
In this case, gapless will most likely not work. It will result in (very
slight) desync, or (more commonly with small buffer sizes), in an
underflow.
I think it would be legitimate to disable gapless at end of playback
completely if video is enabled at all. But this would need an exception
for cover art mode, so I guess the current solution is OK as well.
The justification for this is the fact that the `video-aspect` property
doesn't work well with `cycle_values` commands that include the value
"-1".
The "video-aspect" property has effectively no change in behavior, but
we may want to make it read-only in the future. I think it's probably
fine to leave as-is, though.
Fixes#6068.
The description of the "playback_only" field in the "subprocess" command
says "you can't start it outside of playback". This did not work
correctly: if the player was started in idle mode in the first place,
the subprocess was allowed to run even with playback_only=yes.
This is a bug, and this change fixes it. Add a test for this to
command-test.lua.
For #7025.
This is realized by dvbin-channel-switch-offset,
which is a numeric offset on the channel initially tuned to.
Since the channel list is kept in the stream alone
depending on detected hardware and chosen card,
and no available backchannel to the player, there's no direct
property which could be switched.
Using input.conf like:
H cycle dvbin-channel-switch-offset up
K cycle dvbin-channel-switch-offset down
Q set dvbin-prog "ZDF HD"
allow fast and reliable channel switching again.
Reinitializes the player as is needed when
tuning to a new DVB channel.
Currently triggered when dvbin-prog is written to,
i.e. when the user explicity switches to a channel by name.
Looks like this didn't actually work. Prefetching will do nothing if
there isn't a thread to "drive" it, and the demuxer thread needs to be
explicitly enabled. (I guess I did the worst possible job in verifying
whether this actually worked when I implemented it. On the other hand,
the user didn't confirm back whether it worked, so who cares.)
Like in the previous commit, bad factoring makes everything worse. It
duplicates logic and implementation of enable_demux_thread(), since the
opener thread cannot access the mpctx->opts field freely. But it's deep
night, so fuck it.
Fixes: c1f1a0845eFixes: #6753
demux_start_prefetch() was called unconditionally in two cases. This is
completely wrong. I'm not sure what part of my brain died off that
something this obviously wrong went in.
The prefetch case is a bit more complicated. It's a different thread, so
you can't access just access mpctx->opts there. So add an explicit field
for this, which is the simplest way to get this done. (Even if it's bad
factoring.)
Fixes: c1f1a0845e
Fixes: 556e204a11
Although this was sort of elegant, it just seems to complicate things
slightly. Originally, the API meant that you cache mp_recorder_sink
yourself (which would avoid the mess of passing an index around), but
that too seems slightly roundabout.
In a later change, I want to change the set of streams passed to
mp_recorder_create(), and then I'd have to keep track of the index for
each stream, which would suck. With this commit, I can just pass the
unambiguous sh_stream to it, and it will be guaranteed to match the
correct stream.
The disadvantages are barely worth discussing. It's a new linear search
per packet, but usually only 2 to 4 streams are active at a time. Also,
in theory a user could want to write 2 streams using the same sh_stream
(same metadata, just writing different packets or so), but in practice
this is never done.
That's just a single one. It used to be more, when FFmpeg still required
using pointless accessors for tons of fields, which historically broke
compatibility with Libav. (I think I wrote the patch to deprecate that
crap and to allow direct access myself.)
There may be more exceptions, but I forgot about them. Another point is
that we don't really trust FFmpeg ABI stability, though.
In spdif mode, there are hacks that try to cut audio on frame boundaries
(blame spdif, which is a hack in itself). The "alignment" is used in a
bunch of places, but --end does not respect it. This leads to some audio
that can't be pushed because the alignment is off (I don't know why, not
do I care), which puts audio into an underrun state forever.
Fix this by discarding unusable extra samples if no new data can be
expected.
Fixes: #6935
When the (float) bitrate is returned, it is implicitely converted to an
int64 value, merely discarding the fractional part.
However the bitrate of a CBR track can vary a bit due to timestamp
precision loss after clock conversion (this can affect MPEG-TS audio
tracks). So a bitrate like 191999.999... results in 191999 when
being returned - instead of 192000.
To fix this, apply proper rounding, as already done for the "old" case.
Hereby refactoring the "old" case to also use `llrint`.
The question came up on how a client would figure out where
screenshot-directory saved its screenshots if it contained
mpv-specific expansions. This command should remedy the situation
by providing a way for the client to ask mpv to do an expansion.
reinit_audio_filters_and_output() can fully shutdown the audio chain on
failure. Specifically, it will deallocate mpctx->ao_chain. The value of
that field was cached in ao_c. The code after the call did not account
that the audio chain can be shutdown, and used the stale ao_c value.
Fixes: #6808
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.
This change adds a version of `mpv_command` that also returns a result.
The main rationale behind this is `mpv_command_node` requires defining
multiple structs before you can even use it, which results in a pretty
painful to use interface just to get the result from a command.
There isn't really a good name for this function, so I'm open to
suggestions on a better name for it.
Replace the "+" with "/". The "+" was supposed to imply that the cache
is the sum of the time (demuxer cache) and the size in bytes (stream
cache). We could not provide something nicer, because we had no idea how
many seconds of media was buffered in the stream cache.
Now the stream cache is done, and both the duration and byte size show
the amount buffered in the demuxer cache. Hopefully "/" is better to
imply this properly. Update the manpage explanations too.
When update_prop() successfully fetched a changed property value, it
set prop->changed to true to indicate the success.
mark_property_changed() also always set
prop->changed to true and additionally prop->need_new_value to true
This is the case since 6ac0ef78
If the observed property changes every frame and then due to timing
the next mark_property_changed() is called before
gen_property_change_event() and therefore directly after update_prop(),
prop->need_new_value was again true and indicated that a new value
has to be retrieved with update_prop(). As a result the event for the
last successful update_prop() was never triggered. This meant that
a property change event were never generated for frame-based properties
only for properties that were observed with MPV_FORMAT_NONE or when the
timing was different and gen_property_change_event() was called after
update_prop().
To fix this, mark_property_change() and update_prop() should not use the
same flag to indicate different things and therefore a new flag for
successfully update a property is introduced. But with the now decoupled property
changed and updated the need_new_value flag is redundant and removed completely.
Fixes#4195
With the stream cache gone, this function had almost no use anymore
(other than opening the stream). Improve this by triggering demuxer
cache readahead.
This enables all streams. At this point we can't know yet what streams
the user's options would select (at least not without great additional
effort). Generally this is what you want, and the stream cache would
have read the same amount of data.
In addition, this will work much better for files that e.g. need to seek
to the end when opening (typically mp4, and mkv files produced by newer
mkvmerge versions).
Remove the deselection call from add_stream_track(). This should be
fine, as streams normally start out as deselected anyway. In the
prefetch case, some code in play_current_file() actually deselects it.
Streams that appear during demuxing are disabled by default, so this
doesn't break this logic either.
Fixes: #6753
render api needs to wait for vo to be destroyed before frees the context.
The purpose of kill_cb is to wake up render api after vo is destroyed,
but uninit did that before kill_cb, so kill_cb tries using the freed
memory. Remove kill_cb to fix the issue as uninit is able to do the
work.
Until now they weren't observable and never reported any updates. Apply
a shitty hack to make them mostly-observable. It relies on the "idle"
event, which is basically triggered on every frame displayed, or
similar. This can lead to property change notifications not being sent
quickly enough.
The cleaner solution would be adding a notification mechanisms from
filters, but I'm too lazy for that.
For simplicity, these properties usually query the metadata from the
filter twice, even if it's not technically needed at all. The reason for
this is mostly the horrible (and legacy) sub-path access (which is why
tag_property() is so complex).
But for simple cases, we can easily avoid double querying, so do that.
The benefit is performance (well, won't matter), and supporting filters
that reset information on query (for later).
A dumb thing that the cursed property-option bridge accidentally did.
Normal deprecated options on the other hand are fine in the property
list, because they're wanted for compatibility.
A previous commit changed m_config so that it always creates the shadow
thing, and the function's only remaining purpose was to initialize
mpv_global. It makes much more sense to do that at the caller, and it's
only 1 line of code too.
Helper for the ab-loop-dump-cache command, see manpage additions.
This is kind of shit. Not only is this a very "special" feature, but it
also vomits more messy code into the big and already bloated demux.c,
and the implementation is sort of duplicated with the dump-cache code.
(Except it's different.) In addition, the results sort of depend what a
video player would do with the dump-cache output, or what the user wants
(for example, a user might be more interested in the range of output
audio, instead of the video).
But hey, I don't actually need to justify it. I'm only justifying it for
fun.
That's right, and it's probably not the end of it. I'll just claim that
I have no idea how to create a proper user interface for this, so I'm
creating multiple partially-orthogonal, of which some may work better in
each of its special use cases.
Until now, there was --record-file. You get relatively good control
about what is muxed, and it can use the cache. But it sucks that it's
bound to playback. If you pause while it's set, muxing stops. If you
seek while it's set, the output will be sort-of trashed, and that's by
design.
Then --stream-record was added. This is a bit better (especially for
live streams), but you can't really control well when muxing stops or
ends. In particular, it can't use the cache (it just dumps whatever the
underlying demuxer returns).
Today, the idea is that the user should just be able to select a time
range to dump to a file, and it should not affected by the user seeking
around in the cache. In addition, the stream may still be running, so
there's some need to continue dumping, even if it's redundant to
--stream-record.
One notable thing is that it uses the async command shit. Not sure
whether this is a good idea. Maybe not, but whatever. Also, a user can
always use the "async" prefix to pretend it doesn't.
Much of this was barely tested (especially the reinterleaving crap),
let's just hope it mostly works. I'm sure you can tolerate the one or
other crash?
The screenshot command has this weird behavior that it shows messages
both on terminal and OSD by default, but that a command prefix can be
used to disable the OSD message.
Move this mechanism to common code, and make this available to other
commands too (although as of this commit only the screenshot commands
use it).
This gets rid of the weird screenshot_ctx.osd field too, which was sort
of set on a command, and sometimes inconsistently restored after the
command.
The readahead time should be interesting for latency vs. underruns
(which idiot protocols like HLS suffer from).
The total byte usage is less interesting than I hoped; maybe the
frequency at which it samples should be reduced. (Kind of dumb - you
want high frequency for the readahead field, but much lower for byte
usage.)
Of course, the code was copy&pasted from the DS ratio/jitter stuff. Some
of the choices may not make any sense for the new code.
Normally I use the OSC like this: not at all, but have a key binding
that does "cycle osc" to show it. And in that case, I don't really want
it to overlap the damn video.
I could use the zoom/pan options to move the video out of the way, but
this is also sort of annoying. Likewise, you could write a script or so
which does this automatically if the OSC appears, but that's still
annoying, and computing values for these options such that the video is
moved correctly is tricky.
So I added a bunch of options that set explicit video borders (previous
commit), and a option for the OSC to use them (this commit).
Disabled by default, since I'm afraid this is too awkward and
unpolished, especially with OSC default settings.
I'm also using "osc-visibility=always". Effectively, making the OSC
appear will box the video, and making it disappear (by unloading
osc.lua) will restore the video back to normal.
Somewhat similar to the old --cache-file, except for the demuxer cache.
Instead of keeping packet data in memory, it's written to disk and read
back when needed.
The idea is to reduce main memory usage, while allowing fast seeking in
large cached network streams (especially live streams). Keeping the
packet metadata on disk would be rather hard (would use mmap or so, or
rewrite the entire demux.c packet queue handling), and since it's
relatively small, just keep it in memory.
Also for simplicity, the disk cache is append-only. If you're watching
really long livestreams, and need pruning, you're probably out of luck.
This still could be improved by trying to free unused blocks with
fallocate(), but since we're writing multiple streams in an interleaved
manner, this is slightly hard.
Some rather gross ugliness in packet.h: we want to store the file
position of the cached data somewhere, but on 32 bit architectures, we
don't have any usable 64 bit members for this, just the buf/len fields,
which add up to 64 bit - so the shitty union aliases this memory.
Error paths untested. Side data (the complicated part of trying to
serialize ffmpeg packets) untested.
Stream recording had to be adjusted. Some minor details change due to
this, but probably nothing important.
The change in attempt_range_joining() is because packets in cache
have no valid len field. It was a useful check (heuristically
finding broken cases), but not a necessary one.
Various other approaches were tried. It would be interesting to list
them and to mention the pros and cons, but I don't feel like it.
The old implementation didn't work for the OGG case. Discard the old
shit code (instead of fixing it), and write new shit code. The old code
was already over a year old, so it's about time to rewrite it for no
reason anyway.
While it's true that the old code appears to be broken, the main reason
to rewrite this is to make it simpler. While the amount of code seems to
be about the same, both the concept and the actual tag handling are
simpler. The result is probably a bit more correct.
The packet struct shrinks by 8 byte. That fact that it wasted 8 bytes
per packet for a rather obscure use case was the reason I started this
at all (and when I found that OGG updates didn't work). While these 8
bytes aren't going to hurt, the packet struct was getting too bloated.
If you buffer a lot of data, these extra fields will add up. Still quite
some effort for 8 bytes. Fortunately, it's not like there are any
managers that need to be convinced whether it's worth doing. The freedom
to waste time on dumb shit.
The old implementation attached the current metadata to each packet.
When the decoder read the packet, the packet's metadata was made
current. The new implementation stores metadata as separate list, and
requires that the player frontend tells it the current playback time,
which will be used to find the currently valid metadata. In both cases,
the objective was to correctly update metadata even if a lot of data is
buffered ahead (and to update them correctly when seeking within the
demuxer cache).
The new implementation is actually slightly more correct, because it
uses the playback time for the metadata lookup. Consider if you have an
audio filter which buffers 15 seconds (unfortunately such a filter
exists), then the old code would update the current title 15 seconds too
early, while the new one does it correctly.
The new code also simplifies mixing the 3 metadata sources (global, per
stream, ICY). We assume these aren't mixed in a meaningful way. The old
code tried to be a bit more "exact". I didn't bother to look how the old
code did this, but the new code simply always "merges" with the previous
metadata, so if a newer tag removes a field, it's going to stick around
anyway.
I tried to keep it simple. Other approaches include making metadata a
special sh_stream with metadata packets. This would have been
conceptually clean, but the implementation would probably have been
unnatural (and doesn't match well with libavformat's API anyway). It
would have been nice to make the metadata updates chapter points (makes
a lot of sense for the intended use case, web radio current song
information), but I don't think it would have been a good idea to make
chapters suddenly so dynamic. (Still an idea to keep in mind; the new
code actually makes it easier to work towards this.)
You could mention how subtitles are timed metadata, and actually are
implemented as sparse packet streams in some formats. mp4 implements
chapters as special subtitle stream, AFAIK. (Ironically, this is very
not-ideal for files. It would be useful for streaming like web radio,
but mp4 is extremely bad for streaming by design for other reasons.)
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla
It seems the so called demuxer cache wasn't really disabled for
sub-demuxers (timeline stuff). This was relatively harmless, since the
actual packet data was shared anyway via refcounting. But with the
addition of a mmap cache backend, this may change a lot.
So strictly disable any caching for sub-demuxers. This assumes that
users of sub-demuxers (only demux_timeline.c by now?) strictly use
demux_read_any_packet(), since demux_read_packet_async() will require
some minor read-ahead if a low level packet read returned a packet for a
different stream.
This requires some awkward messing with this fucking heap of trash. The
thing that is really wrong here is that the demuxer API mixes different
concepts, and sub-demuxers get the same API as decoders, and use the
cache code.
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.
And add simpler aliases for the modes.
I'm not sure how to name things, and the option list is in general full
of different conventions. Some names are shortened, some are explicit
and long.
I guess options that have a chance to be used normally (i.e. not obscure
tuning or debugging) should have a short and convenient names.
In this specific case, play-direction is like a mixture of both. It
should be either playback-direction or play-dir, not shorten one word
but not the other.
The convenience aliases are because I got sick of typing out "backward".
I guess "back" would also do it, but there's no proper antonym (and
maybe it's "wrong" in the strict sense of the word).
Another shitty obscure feature that usually nobody notices.
Unsurprisingly, it doesn't go well with backward playback mode.
If you use --keep-open in forward playback mode, and seek past the end
of the file, it tries to seek to the very last frame. The demuxer will
seek to the last "keyframe" before the end (i.e. some frames to go in
most cases), and trying to hr-seek to the file duration often won't cut
it, so this requires some special code. The function at hand seeks
"close" to the end, and then stops hr-seek when the last frame us
encountered (simple enough and very effective).
In backward playback mode, start and end are reversed, and we need to
seek "close" to the start of the file instead. Simple enough to do, and
it works.
One problem is that command.c has some weird logic to make going beyond
the last chapter either end playback (--keep-open=no), or jump to the
last frame. Now this will jump to the first frame, which is weird, but
let's ignore this.
Another problem is that seeking before playback start position hits EOF
in backward playback mode, which is a demuxer bug, and has nothing to do
with this code. But it triggers this code, so seeking before the start
will show the "last" frame. (My description is a mess with directions.
Figure it out yourself.)
Obviously should seek back to the end of the file when it loops.
Also remove some minor code duplication around start times. This isn't
the correct solution by the way. Rather than hoping we know a reasonable
start/end time, this stuff should instruct the demuxer to seek to the
exact location. It'll work with 99% of all normal files, but add an
appropriate comment (that basically says the function is bullshit) to
get_start_time() anyway.
This changes the behavior of the --ab-loop-a/b options. In addition, it
makes it work with backward playback mode.
The most obvious change is that the both the A and B point need to be
set now before any looping happens. Unlike before, unset points don't
implicitly use the start or end of the file. I think the old behavior
was a feature that was explicitly added/wanted. Well, it's gone now.
This is because of 2 reasons:
1. I never liked this feature, and it always got in my way (as user).
2. It's inherently annoying with backward playback mode.
In backward playback mode, the user wants to set A/B in the wrong order.
The ab-loop command will first set A, then B, so if you use this command
during backward playback, A will be set to a higher timestamps than B.
If you switch back to forward playback mode, the loop would stop
working. I want the loop to just continue to work, and the chosen
solution conflicts with the removed feature.
The order issue above _could_ be fixed by also switching the AB-loop
user option values around on direction switch. But there are no other
instances of option changes magically affecting other options, and doing
this would probably lead to unexpected misery (dying from corner cases
and such).
Another solution is sorting the A/B points by timestamps after copying
them from the user options. Then A/B options set in backward mode will
work in forward mode. This is the chosen solution. If you sort the
points, you don't know anymore whether the unset point is supposed to
signify the end or the start of the file.
The AB-loop code is slightly better abstracted now, so it should be easy
to restore the removed feature. It would still require coming up with a
solution for backwards playback, though.
A minor change is that if one point is set and the other is unset, I'm
rendering both the chapter markers and the marker for the set point.
Why? I don't know. My test file had chapters, and I guess I decided this
looked better.
This commit also fixes some subtle and obvious issues that I already
forgot about when I wrote this commit message. It cleans up some minor
code duplication and nonsense too.
Regarding backward playback, the code uses an unsanitary mix of internal
("transformed") and user timestamps. So the play_dir variable appears
more than usual.
To mention one unfixed issue: if you set an AB-loop that is completely
past the end of the file, it will get stuck in an infinite seeking loop
once playback reaches the end of the file. Fixing this reliably seemed
annoying, so the fix is "just don't do this". It's not a hard freeze
anyway.
This code attempts to seek to the last frame by seeking close to the
end, and then decoding until the last frame has been reached. To do so
it sets hrseek_lastframe, which for video enables some logic to "catch"
this last frame, and completely ignores hrseek_pts. But audio still may
use hrseek_pts
I don't know if the original author (me) was thinking, if anything, when
setting this variable to 1e99, essentially a random, number. It's very
large, and a timestamp like this will never happen, so it does its job.
But it's random.
Use INFINITY instead. It will skip all audio samples in the audio code
correctly. This change doesn't fix anything, but it does get rid of the
random looking number.
The get_play_start_pts() function was supposed to return "rebased"
(relative to 0) timestamps. This was roundabout, because one of 2
callers just added the offset back, and the other caller actually
expected an absolute timestamp.
Change rel_time_to_abs() (whose return value get_play_start_pts()
returns without further changes) to return absolute times.
This should fix that absolute and relative times passed to --start and
--end were treated the same, which can't be right. It probably also
fixes --end if --rebase-start-time=no is used (which can't have been
correct either).
All in all I'm not sure why --rebase-start-time=no or absolute vs.
relative times in --start/--end even exist, when they were incorrectly
implemented for years.
Untested, because no sample file and I don't care. However, if anyone
cares, and I got it wrong, I hope it's simple to fix.
Has been deprecated for almost 3 years. Manpage didn't mention the
deprecation, but CLI and release notes did. It wouldn't be much effort
to keep this option working, but I just don't see the damn point.
--start/--end can specify chapters using special syntax, which is
equivalent.
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.
This adds the stops using the same logic get_play_end_pts() and
handle_loop_file(). It did that before, it just looks slightly different
now. It also won't try to add MP_NOPTS_VALUE as stop value.
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.
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.
This is a minor benign hack that reorders the MPV_FORMAT_NODE output.
The order of members is not supposed to matter, but it's how the OSD
renders them as raw output. Normally this isn't used, but
demuxer-cache-state is a "prominent" case. Moving the seek ranges to the
end avoids that the more important other fields are not cut off by going
out of the screen on the bottom.
Also output the seek ranges in reverse. The order doesn't matter either
(as declared by input.rst). Currently, the demuxer orders them by least
recent use. Reversing it makes the most recently used range (the current
range) show up on top.
In other words, this commit does basically nothing but fudge stuff in a
cosmetic way to make debugging easier for me, and you've wasted your
time reading this commit message and the diff. Good.
This will properly notify observed properties if the player hasn't
started actual playback yet, such as with --demuxer-cache-wait.
This also happens to cause the main loop more often, which triggers
MPV_EVENT_IDLE, and fixes the OSC display. (See previous commit
message.)
The OSC's (osc.lua) event handling is fundamentally broken. It waits for
MPV_EVENT_TICK to update the UI, and MPV_EVENT_TICK has become entirely
meaningless, except as a hack for the OSC. There are many situations
where the OSC doesn't properly update because the TICK event it expects
isn't sent.
Fix one of them: it doesn't update the cache state if the VO window is
forced and --demuxer-cache-wait is used. Make it so that the tick event
is sent even if playback initialization is taking time.
This is still slightly broken, because it works only if the mainloop is
actually run, which depends on random circumstances (such as moving the
mouse over the VO window). The next commit will add another such
circumstance which will make it appear to work, although it's still
conceptually broken. If we "fixed" it and strictly woke up the player
if the idle timer ran out, we'd send tick events all the time, even
if nothing is going on, which we don't want. Fucking shitshow.
This is just redundant and slightly annoying, at least for normal
command line usage. If there are multiple entries, still print it
(because you want to know where you are). Also still print it if the
player was redirected (because you want to know where you got redirected
to).
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.
I noticed that some ytdl streams have a start time other than 0. There's
currently no mechanism inside of the EDL stuff that determines this
start time correctly, so it can happen that if the start time is high,
demux_timeline.c tries to clip off the entire video and audio, resulting
in failure of playback.
As a counter measure, use the no_clip header, which entirely disables
clipping against time ranges in demux_timeline.c. (It's basically a
hack.)
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.
Init fragments are not a necessity for DASH, but this code assumed so.
Maybe the check was to prevent worse. But using normal EDL here leads to
very shitty behavior where it tries to open hundreds or thousands of
fragments, each with its own demuxer and HTTP connection. (This behavior
is fine for normal uses of EDLs, but completely unacceptable when
emulating fragmented streaming protocols. I'm not sure why the normal
EDL code is needed here, but I think someone claimed some obscure sites
just need it.)
This happens in the same situation as the one described in the previous
commit.
Otherwise we'd just use the base URL as media URL, which would fail with
a 404 error.
Not sure if there's a deeper reason why the audio path was explicitly
different from the video one. But this actually works now for a video
that returned fragmented DASH audio with the default format selection.
(This affects streams on that well known site of a big evil Silicon
Valley company. Typically happens after live stream gets converted to a
normal video, though after some time passes, this fragmented version is
deleted, and replaced by a non-fragmented one. I've observed this
several times and this seems to be the "normal" behavior.)
This merges separate audio and video tracks into one virtual stream,
which helps the mpv caching layer. See previous EDL commit for details.
It's apparently active for most of evil Silicon Valley giant's streaming
videos.
Initial tests seem to work fine, except it happens pretty often that
playback goes into buffering immediately even when seeking within a
cached range, because there is not enough forward cache data yet to
fully restart playback. (Or something like this.)
The audio stream title used to be derived from track.format_note; this
commit stops doing so. It seemed pointless anyway. If really necessary,
it could be restored by adding new EDL headers.
Note that we explicitly don't do this with subtitle tracks. Subtitle
tracks still have a chance with on-demand loading or loading in the
background while video is already playing; merging them with EDL would
prevent this. Currently, subtitles are still added in a "blocking"
manner, but in theory this could be loosened. For example, the Lua API
already provides a way to run processes asynchronously, which could be
used to add subtitles during playback. EDL will probably be never
flexible enough to provide this. Also, subtitles are downloaded at
once, rather than streamed like audio and video.
Still missing: disabling EDL's pointless chapter generation, and
propagating download speed statistics through the EDL wrapper.
The ytdl wrapper can resolve web links to playlists. This playlist is
passed as big memory:// blob, and will contain further quite normal web
links. When playback of one of these playlist entries starts, ytdl is
called again and will resolve the web link to a media URL again.
This didn't work if playlist entries resolved to EDL URLs. Playback was
rejected with a "potentially unsafe URL from playlist" error. This was
completely weird and unexpected: using the playlist entry directly on
the command line worked fine, and there isn't a reason why it should be
different for a playlist entry (both are resolved by the ytdl wrapper
anyway). Also, if the only EDL URL was added via audio-add or sub-add,
the URL was accessed successfully.
The reason this happened is because the playlist entries were marked as
STREAM_SAFE_ONLY, and edl:// is not marked as "safe". Playlist entries
passed via command line directly are not marked, so resolving them to
EDL worked.
Fix this by making the ytdl hook set load-unsafe-playlists while the
playlist is parsed. (After the playlist is parsed, and before the first
playlist entry is played, file-local options are reset again.) Further,
extend the load-unsafe-playlists option so that the playlist entries are
not marked while the playlist is loaded.
Since playlist entries are already verified, this should change nothing
about the actual security situation.
There are now 2 locations which check load_unsafe_playlists. The old one
is a bit redundant now. In theory, the playlist loading code might not
be the only code which sets these flags, so keeping the old code is
somewhat justified (and in any case it doesn't hurt to keep it).
In general, the security concept sucks (and always did). I can for
example not answer the question whether you can "break" this mechanism
with various combinations of archives, EDL files, playlists files,
compromised sites, and so on. You probably can, and I'm fully aware that
it's probably possible, so don't blame me.
struct stream used to include the stream buffer, including peek buffer,
inline in the struct. It could not be resized, which means the maximum
peek size was set in stone. This meant demux_lavf.c could peek only so
much data.
Change it to use a dynamic buffer. Because it's possible, keep the
inline buffer for default buffer sizes (which are basically always used
outside of file opening). It's unknown whether it really helps with
anything. Probably not.
This is also the fallback plan in case we need something like the old
stream cache in order to deal with mp4 + unseekable http: the code can
now be easily changed to use any buffer size.
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.
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.
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.