Currently using mpv --msg-level=help, shows an instance of --msglevel
(missing dash). Seems like the help message was only partially updated
with the -msglevel -> --msg-level transition.
Signed-off-by: Emil Velikov <emil.l.velikov@gmail.com>
Using --sub-filter-regex-plain (default:no)
The ass-to-plaintext functionality already existed at sd_ass.c, but
it's internal and uses a private buffer type, so a trivial utility
wrapper was added with standard char*/bstr interface.
The plaintext can be multi-line, and the multi-line regexp flag is now
always set, but only affects plaintext (the ASS source is one line).
Pretty much identical to filter-regex but with JS expressions and
requires only JS support. Shares the filter-regex-* control options.
The target audience is Windows users - where filter-regex doesn't
work due to missing APIs, but mujs builds cleanly on Windows, and JS
is usually enabled in 3rd party Windows mpv builds.
Lua could have been used with similar effort, however, the JS regex
syntax is more extensive and also much more similar to POSIX.
Since 1d1d1fbff9 option-info/<name>/set-locally was being set to true
for every option. This broke setting start from ytdl-hook, which doesn't
overwrite start if it was set-locally. Fix this so that only adding an
option to reset-on-next-file or setting file-local-options/<name> make
set-locally true like before.
However, it's arguable that just adding an option to
reset-on-next-file without ever changing it should not make set-locally
true, so that e.g.
--reset-on-next-file=start 'https://youtube.com/watch?v=...&t=30'
will start at 30, though it currently doesn't.
Fixes#9081.
Let audio-display determine whether embedded images or external cover
art tracks should be selected when both are present.
Attached pictures are given priority by default as requested in #8539.
Also updates references to attached pictures in the log and manpage to
refer to cover art as well.
Closes#8539.
--watch-later-options-remove doesn't accept multiple options, so split
the example.
Also suggest the more correct -clr to empty the list, and remove the
workaround to not print an error with --watch-later-options=
This allows configuring which options are saved by quit-watch-later.
Fixes#4126, #4641 and #5567.
Toggling a video or audio filter twice would treat the option as changed
because the backup value is NULL, and the current value of vf/af is a
list with one empty item, so obj_settings_list_equal had to be changed.
Not sure what I was on when I wrote this. wayland-app-id is supposed to
default to "mpv". Just set that in the vo_sub_opts and don't do this
weird m_config_cache_write_opt thing. Also make the doc entry nicer.
This fixes a long-standing apparent issue where mpv would display the last
frame with no subtitles at EOF. This is caused by sub rendering switching from
video timestamps to audio timestamps when the video ends, and audio streams
often running past the timestamp of the last video frame. However, authoring
tools (most notably Aegisub) don't tend to provide easy ways to add meaningful
subtitles after the end of the video, so this is rarely actually useful.
This makes cover-art-auto behave more like sub-auto and audio-file-auto:
- load cover art with a language, e.g. if playing foo.mp3, foo.en.jpg
will be loaded with lang=en
- load cover art containing the media filename with fuzzy and all, e.g.
'foo (large).jpg'
- make all/2 load all images in the directory, and make fuzzy/1 the
default
These are all uncommon use cases, but synchronizing the behavior of the
external file options simplifies the code.
This is the Vulkan equivalent of the drm context for OpenGL, with
the big difference that it's implemented purely in terms of Vulkan
calls and doesn't actually require drm or kms.
The basic idea is to identify a display, mode, and plane on a device,
and then create a display backed surface for the swapchain. In theory,
past that point, everything is the same, and this is in fact the case
on Intel hardware. I can get a video playing on a vt.
On nvidia, naturally, things don't work that way. Instead, nvidia only
implemented the extension for scenarios where a VR application is
stealing a display from a running window system, and not for
standalone scenarios. With additional code, I've got this scenario to
work but that's a separate incremental change.
Other people have tested on AMD, and report roughly the same behaviour
as on Intel.
Note, that in this change, the VT will not be correctly restored after
qutting. The only way to restore the VT is to introduce some drm
specific code which I will illustrate in a separate change.
The accurate description of this option was:
- fit-border is enabled by default. When disabled, it adds a bug where
if the window has borders and mpv shrinks it to fit the desktop, then
the calculation ignores the borders and adds incorrect video crop.
The option was added at commits 70f64f3c and 949247d6, in order to
solve an issue (#2935) where if mpv wanted to display a video with
size WxH, then w32_common.c incorrectly set the window to WxH, while
down-scaling the video slightly to fit (even with small sizes).
It was addressed with a new option which is enabled by default, but
does the right thing (sets the client area to WxH) only when disabled,
so that everyone who prefers their video slightly downscaled could
keep their default behavior.
(#2935 also addressed an off-by-one issue, fixed before fit-border)
While disabling the option did avoid unnecessary downscaling, it also
added a bug when disabled: the borders are no longer taken into
account when the size is too big for the desktop. Most users don't
notice and are unaffected as it's enabled by default.
Shortly later (981048e0) the core issue is fixed, and now the client
area is correctly set to WxH instead of the window (and together with
the three following commits which center the video, adds a new bug
where the window title can be outside the display - addressed next).
However, fit-border remained, now without any effect, except that it
still has the same bug when disabled and the window is too big.
Later code changes and refactoring preserved this issue with great
attention to details, and it remained in identical form until now.
Simply rip out fit-border.
Today, validation is only possible for string type options. But there's
no particular reason why it needs to be restricted in this way, and
there are potential uses, to allow other options to be validated
without forcing the option to have to reimplement parsing from
scratch.
The first part, simply making the validation function an explicit
field instead of overloading priv is simple enough. But if we only do
that, then the validation function still needs to deal with the raw
pre-parsed string. Instead, we want to allow the value to be parsed
before it is validated. That in turn leads to us having validator
functions that should be type aware. Unfortunately, that means we need
to keep the explicit macro like OPT_STRING_VALIDATE() as a way to
enforce the correct typing of the function. Otherwise, we'd have to
have the validator take a void * and hope the implementation can cast
it correctly.
For help, we don't have this problem, as help doesn't look at the
value.
Then, we turn validators that are really help generators into explicit
help functions and where a validator is help + validation, we split
them into two parts.
I have, however, left functions that need to query information for both
help and validation as single functions to avoid code duplication.
In this change, I have not added an other OPT_FOO_VALIDATE() macros as
they are not needed, but I will add some in a separate change to
illustrate the pattern.
Simple groundwork for adding a couple of user options that allow
selecting the screen with a string name. The next two commits implements
these options for xorg and wayland.
This reverts commit 3d17e19c2c.
The effect of turning off this setting is that mpv doesn't tell libass what
the video stream's resolution is. This happens to result in some files having
their transforms scaled in ways that give higher performance (as described
in #7435) because libass happened to guess a video resolution that resulted
in transforms yielding smaller bitmaps, but it's just as easy for the opposite
to happen depending on the resolutions and effects involved.
The option's name is also somewhat misleading: setting the storage size affects
blur, but it also affects stroke (which is far more important for the vast
majority of scripts) and 3D transforms (which look very screwy when done wrong).
Apparently mpv supports loading config files from the same directory as
the mpv.exe. This is a fallback of some sort. It used the old_home
mechanism.
I want to add a warning if old_home exists, but that would always show
the warning on win32. Obviously we don't want that.
Add a separate exe_dir entry to deal with that.
Untested, but probably works.
Mistakenly reverted as part of the default configuration directory
location switch-back in aa18a8e1cd.
Separation of the mpv executable directory from old_path is a
good change now that we warn about the old_config directory also
existing.
Fixes#8232Fixes#8244Fixes#8262
Picks up files like "cover.jpg". It's made part of normal external file
loading, so I'm adding 3 new options that are direct equivalents for the
options that control loading of external subtitle and audio files. Even
though I bet nobody wants them and they just increase confusion... I
guess the world is actually hell, so this outcome should be fine.
It prefers non-specific external files like "cover.jpg" over embedded
cover art. Not sure if that's wanted or unwanted.
There's some pain over explicitly marking such files as external
pictures. This is basically an optimization: in most cases, a heuristic
would treat an image file loaded with --external-file the same (it's a
heuristic because ffmpeg can't tell us whether something is an image or
a video). However, even with this heuristic, it would decode the cover
art picture again on each seek, which would essentially slow down
seeking in audio files. This bothered me greatly, which is why I'm
adding these additional options at all, and bothered with the previous
commit.
Fixes: #3056
on macOS 10.15 setting the activation policy behaves quite weirdly. the
call changes the current active App to a nameless process, which
probably also the reason that prevents the not focusing to work.
a workaround for that, is to refocus the previous active app.
Fixes#7725
Accepting ":" in addition to "," seems confusing and dumb. It only
causing problems when you want to pass a value that contains ":". Remove
support for ":", it is now treated like any other normal character. This
affects all options that are listed as "Key/value list" in the option
list.
It's possible that this breaks for someone who happened to use ":" as
separator. But this was undocumented, and never recommended. Originally,
the option treated many other characters in a special way, but this was
changed in commit a3d561f950. I'm, not sure why ":" was explicitly
included. Maybe because -the absurd -vf/--af syntax uses ":" as list
separator. But "," was always recommended and used in examples for
key/value options.
Fixes: #8021 (if you consider it a bug)
This allows users to control whether full dialogue subtitles are displayed
with an audio track already in their preferred subtitle language.
Additionally, this improves handling for the forced flag, automatically
selecting between forced and unforced subtitle streams based on the user's
settings and the selected audio.
Seems like this is requested all the time.
It seems libass allows out of range values, but does allows the subtitle
to go out of the screen at the bottom (only when moving it to the top
it's "clamped"). Too bad, don't do that then. The bitmap sub rendering
code on the other hand is under our control, and will not move a
subtitle out of the screen.
Fixes: #7986
Options like --sub-ass-force-style and others could not be changed at
runtime (the changes didn't take any effect). Fix this by using the
brutal approach, and completely reinit the subtitle state when this
happens. Maybe a bit clunky, but for now I'd rather not put more effort
into this.
Fixes: #7689
Make it possible to restore from profiles by backing up the option
values before profile application. This is sort of like unapplying a
profile. Since there might be multiple ways to do this, a profile needs
to explicitly provide the "profile-restore" option, which specifies how
exactly this should be done.
This is a big mess. There is not natural way to do this. Profile
application is "destructive" and simply changes the values of the
options. Maybe one could argue that the option system should have
hierarchical "overlays" of profiles instead, where unset options will
use the value of the lower profiles. Options set interactively by the
user would be the top profile. Default values would be in the lowest
profile. You could unapply a profile by simply removing it from this
overlay stack.
But uh, let's not, so here's something stupid. It reuses some code used
for file local options to reduce code size. At least the overlay idea
would still be possible in theory, and could be added as another
profile-restore mode.
This is used by the following commit.
This is taken from a somewhat older proof-of-concept script. The basic
idea, and most of the implementation, is still the same. The way the
profiles are actually defined changed.
I still feel bad about this being a Lua script, and running user
expressions as Lua code in a vaguely defined environment, but I guess as
far as balance of effort/maintenance/results goes, this is fine.
It's a bit bloated (the Lua scripting state is at least 150KB or so in
total), so in order to enable this by default, I decided it should
unload itself by default if no auto-profiles are used. (And currently,
it does not actually rescan the profile list if a new config file is
loaded some time later, so the script would do nothing anyway if no auto
profiles were defined.)
This still requires defining inverse profiles for "unapplying" a
profile. Also this is still somewhat racy. Both will probably be
alleviated to some degree in the future.
Mess this into the --geometry option, because I like to be
irresponsible. I considered adding a separate option, but at least this
allows me to defer the question how the hell this should work as
property (geometry simply and inherently does not).
Tested on IceWM only. Option equality test and string output not tested.
Apparently mpv supports loading config files from the same directory as
the mpv.exe. This is a fallback of some sort. It used the old_home
mechanism.
I want to add a warning if old_home exists, but that would always show
the warning on win32. Obviously we don't want that.
Add a separate exe_dir entry to deal with that.
Untested, but probably works.
This simply printf()s a concatenation of the provided string and the
relevant escape sequences. No idea what exactly defines this escape
sequence (is it just a xterm thing that is now supported relatively
widely?), and this simply uses information provided on the linked github
issue.
Not much of an advantage over --term-status-msg, though at least this
can have a lower update frequency. Also I may consider setting a default
value, and then it shouldn't conflict with the status message.
Fixes: #1725
Can be useful to force it to adapt to extreme speed changes, while a
higher limit would just use a fraction closer to the original video
speed.
Probably useful for testing only.
Apparently, this was a bit of a mess, which caused the bug fixed by
commit ec7f2388af. Try to improve this, and only use track selection
entries that exist.
Replace use of .min==1 with a proper flag. This is a good idea, because
it has nothing to do with numeric limits (also see commit 9d32d62b61
for how this can go wrong).
With this, m_option.min/max are strictly used for numeric limits.
This was optional, with the intention that normally such options require
a valid format. But there is no reason for this (at least not anymore),
and it's actually more logical to accept "no" in all situations this
option type is used. This also gets rid of the weird min field special
use.
These used ".min = MP_NOPTS_VALUE" to indicate certain exceptions. This
broke with the recent change to how min/max are handled, which made
setting min or max mean that a value range is used, thus setting max=0.
Fix this by not using magic a value in .min; replace it with a proper
flag.
Fixes: #7596
While --input-file was removed for justified reasons, wanting to pass
down socket FDs this way is legitimate, useful, and easy to implement.
One odd thing is that
Fixes: #7592
As an unfortunate disaster, min/max values use the type double, which
causes tons of issues with int64_t types. Anyway, OPT_BYTE_SIZE is often
used as maximum for size_t quantities, which can have a size different
from (u)int64_t.
OPT_BYTE_SIZE still uses in64_t, because in theory, you could use it for
file sizes. (demux.c would for example be capable of caching more than
2GB on 32 bit platforms if a file cache is used. Though for some reason
the accounting code still uses size_t, so that use case is broken. But
still insist that it _could_ be used this way.)
There were various inconsistent attempts to set m_option.max to a value
such that the size_t/int64_t upper limit is not exceeded. Due to the
double max field, this didn't really work correctly. Try to fix this
with the M_MAX_MEM_BYTES constant. It's a good approximation, because on
32 bit it should allow 2GB (untested, also would probably exhaust
address space in practice but whatever), and something "high enough" in
64 bit.
For some reason, clang 11 still warns. But I think this might be a clang
bug, or I'm crazy. The result is correct anyway.
Since double has a mantissa too small to hold INT64_MAX in full
precision, converting INT64_MAX to double rounds up. Insert some casts
to silence corresponding warnings (as shown by clang 11).
Also, the comparison in multiply_int64() was incorrect (I think...),
because if v==(double)INT64_MAX, then v==(1<<64), which cannot be
represented as int64_t.
There are probably better ways to solve this.
Change all OPT_* macros such that they don't define the entire m_option
initializer, and instead expand only to a part of it, which sets certain
fields. This requires changing almost every option declaration, because
they all use these macros. A declaration now always starts with
{"name", ...
followed by designated initializers only (possibly wrapped in macros).
The OPT_* macros now initialize the .offset and .type fields only,
sometimes also .priv and others.
I think this change makes the option macros less tricky. The old code
had to stuff everything into macro arguments (and attempted to allow
setting arbitrary fields by letting the user pass designated
initializers in the vararg parts). Some of this was made messy due to
C99 and C11 not allowing 0-sized varargs with ',' removal. It's also
possible that this change is pointless, other than cosmetic preferences.
Not too happy about some things. For example, the OPT_CHOICE()
indentation I applied looks a bit ugly.
Much of this change was done with regex search&replace, but some places
required manual editing. In particular, code in "obscure" areas (which I
didn't include in compilation) might be broken now.
In wayland_common.c the author of some option declarations confused the
flags parameter with the default value (though the default value was
also properly set below). I fixed this with this change.
Forgot to remove this. Here you see my confusion and realization how
casting INT64_MAX to double becomes INT64_MAX+1 (due to mantissa
precision and rounding), so some things seemed not to make sense at
first.
The option code is very old and was added to MPlayer in the early 2000s,
when C99 was still new. MPlayer did not use the "bool" type anywhere,l
and the logical option equivalent to bool, the "flag" option type, used
int, with the convention that only the values 0 and 1 are allowed.
mpv may have hammered many, many additional tentacles to the option
code, but some of the basics never changed, and m_option_type_flag still
uses int. This seems a bit weird, since mpv uses bool for booleans. So
finally introduce an m_option_type_bool. To avoid duplicating too much
code, change the flag code to bool, and "reimplement" m_option_type_flag
on top of m_option_type_bool.
As a "demonstration", change the --fullscreen option to this new type.
Ideally, all options would be changed too bool, and m_option_type_flag
would be removed. But that is a lot of monotonous thankless work, so I'm
not doing it, and making it a painful years long transition.
At the same time, I'm introducing a new concept for option declarations.
Instead of OPT_BOOL(), which define the full m_option struct contents,
there's OPTF_BOOL(), which only takes the option field name itself. The
name is provided via a normal struct field initializer. Other fields
(such as flags) can be provided via designated initializers.
The advantage of this is that we don't need tons of nested vararg
macros. We also don't need to deal with 0-sized varargs being a pain
(and in fact they are not a thing in standard C99 and probably C11).
There is no need to provide a mandatory flags argument either, which is
the reason why so many OPT_ macros are used with a "0" argument. (The
flag argument seems to confuse other developers; they either don't
immediately recognize what it is, and sometimes it's supposed to be the
option's default value.)
Not having to mess with the flag argument in such option macros is also
a reason for the removal of M_OPT_RANGE etc., for the better or worse.
The only place that special-cased the _flag option type was in
command.c; change it to use something effectively very similar that
automatically includes the new _bool option type. Everything else should
be transparent to the change. The fullscreen option change should be
transparent too, as C99 bool is basically an integer type that is
clamped to 0/1 (except in Swift, Swift sucks).
Commit 8d965a1bfb changed option/property min/max handling. As a
consequence, ranges that contain only 1 or 0 elements are not possible
anymore. Normally that's fine, because it makes no sense to have an
option that has only one or none allowed value (statically).
But edition switching used some sort of mechanism where the property can
return a different, dynamically decided range at runtime. That meant
that if there were <2 editions, edition switching with the "cycle"
command would always pick the same value. But with the recent commit,
this changed to having "no range set" and would cycle through all
integer values.
Work this around with a simple change. Now, edition switching on a file
without editions shows "edition: auto" instead of "edition: 0", which
may appear odd. But the former is the --edition default value, and
previous mpv versions rendered the edition property like this when not
using switching.
(Who the fuck uses editions?)
Before this commit, option declarations used M_OPT_MIN/M_OPT_MAX (and
some other identifiers based on these) to signal whether an option had
min/max values. Remove these flags, and make it use a range implicitly
on the condition if min<max is true.
This requires care in all cases when only M_OPT_MIN or M_OPT_MAX were
set (instead of both). Generally, the commit replaces all these
instances with using DBL_MAX/DBL_MIN for the "unset" part of the range.
This also happens to fix some cases where you could pass over-large
values to integer options, which were silently truncated, but now cause
an error.
This commit has some higher potential for regressions.
Try to remove m_config implementation details from m_config_frontend.
Not sure if I like it. Seems to be ~100 lines of awkward code more, and
not much is gained from it. Also it took way too long to do it, and
there might be bugs.
Move the "old" mostly command line parsing and option management related
code to m_config_frontend.c/h. Move the the code that enables other part
of the player to access options to m_config_core.c/h. "frontend" is out
of lack of creativity for a better name.
Unfortunately, the separation isn't quite clean yet. m_config_frontend.c
still references some m_config_core.c implementation details, and
m_config_new() is even left in m_config_core.c for now. There some odd
functions that should be removed as well (marked as "Bad functions").
Fixing these things requires more changes and will be done separately.
struct m_config is left with the current name to reduce diff noise.
Also, since there are a _lot_ source files that include m_config.h, add
a replacement m_config.h that "redirects" to m_config_core.h.
This was mostly unused, and has certain problems. Just get rid of it.
It was still used in CDDA (--cdda-span) and a debug option for OpenGL
(--opengl-check-pattern). Replace both of these with 2 options, where
each sets the start/end values of the former span. Both were
undocumented somehow (normally we require all options to be documented),
so I'm not caring about compatibility, and not bothering to add it to
the API changelog.
Instead of having f_decoder_wrapper create its own copy of the entire
mpv option tree, create a struct local to that file and move all used
options to there.
movie_aspect is used by the "video-aspect" deprecated property code. I
think it's probably better not to remove the property yet, but
fortunately it's easy to work around without needing special handling
for this option or so.
correct_pts is used to prevent use of hr-seek in playloop.c. Ignore
that, if you use --no-correct-pts you're asking for trouble anyway. This
is the only behavior change.
See manpage additions. This has been a topic in MPlayer/mplayer2/mpv
since forever. But since libavcodec multi-threaded decoding was added,
I've always considered this pointless. libavcodec requires you to
"preload" it with packets, and then you can pretty much avoid blocking
on it, if decoding is fast enough.
But in some cases, a decoupled decoder thread _might_ help. Users have
for example come up with cases where decoding video in a separate
process and piping it as raw video to mpv helped. (Or my memory is
false, and it was about vapoursynth filtering, who knows.) So let's just
see whether this helps with anything.
Note that this would have been _much_ easier if libavcodec had an
asynchronous (or rather, non-blocking) API. It could probably have
easily gained that with a small change to its multi-threading code and a
small extension to its API, but I guess not.
Unfortunately, this uglifies f_decoder_wrapper quite a lot. Part of this
is due to annoying corner cases like legacy frame dropping and hardware
decoder state. These could probably be prettified later on.
There is also a change in playloop.c: this is because there is a need to
coordinate playback resets between demuxer thread, decoder thread, and
playback logic. I think this SEEK_BLOCK idea worked out reasonably well.
There are still a number of problems. For example, if the demuxer cache
is full, the decoder thread will simply block hard until the output
queue is full, which interferes with seeking. Could also be improved
later. Hardware decoding will probably die in a fire, because it will
run out of surfaces quickly. We could reduce the queue to size 1...
maybe later. We could update the queue options at runtime easily, but
currently I'm not going to bother.
I could only have put the lavc wrapper itself on a separate thread. But
there is some annoying interaction with EDL and backward playback shit,
and also you would have had to loop demuxer packets through the
playloop, so this sounded less annoying.
The food my mother made for us today was delicious.
Because audio uses the same code, also for audio (even if completely
pointless).
Fixes: #6926
Try to deal with various corner cases. But when I fix one thing, another
thing breaks. (And it's 50/50 whether I find the breakage immediately or
a few months later.) So results may vary.
The default for--hr-seek is changed to "default" (not creative enough to
find a better name). In this mode, audio seeking is exact if there is no
video, or if the video has only a single frame. This change is actually
pretty dumb, since audio frames are usually small enough that exact
seeking does not really add much. But it gets rid of some weird special
cases.
Internally, the most important change is that is_coverart and is_sparse
handling is merged. is_sparse was originally just a special case for
weird .ts streams that have the corresponding low-level flag set. The
idea is that they're pretty similar anyway, so this would reduce the
number of corner cases. But I'm not sure if this doesn't break the
original intended use case for it (I don't have a sample anyway).
This changes last-frame handling, and respects the duration of the last
frame only if audio is disabled. This is mostly "coincidental" due to
the need to make seeking past EOF trigger player exit, and is caused by
setting STATUS_EOF early. On the other hand, this might have been this
way before (see removed chunk close to it).
Works as ad-filter. I had some more plans, for example replacing
matching text with different text, but for now it's dropping matches
only. There's a big warning in the manpage that I might change
semantics. For example, I might turn it into a primitive sed.
In a sane world, you'd probably write a simple script that processes
downloaded subtitles before giving them to mpv, and avoid all this
complexity. But we don't live in a sane world, and the sooner you learn
this, the happier you will be. (But I also want to run this on muxed
subtitles.)
This is pretty straightforward. We use POSIX regexes, which are readily
available without additional pain or dependencies. This also means it's
(apparently) not available on win32 (MinGW). The regex list is because I
hate big monolithic regexes, and this makes it slightly better.
Very superficially tested.
Until now, filter_sdh was simply a function that was called by sd_ass
directly (if enabled).
I want to add another filter, so it's time to turn this into a somewhat
more general subtitle filtering infrastructure.
I pondered whether to reuse the audio/video filtering stuff - but better
not. Also, since subtitles are horrible and tend to refuse proper
abstraction, it's still messed into sd_ass, instead of working on the
dec_sub.c level. Actually mpv used to have subtitle "filters" and even
made subtitle converters part of it, but it was fairly horrible, so
don't do that again.
In addition, make runtime changes possible. Since this was supposed to
be a quick hack, I just decided to put all subtitle filter options into
a separate option group (=> simpler change notification), to manually
push the change through the playloop (like it was sort of before for OSD
options), and to recreate the sub filter chain completely in every
change. Should be good enough.
One strangeness is that due to prefetching and such, most subtitle
packets (or those some time ahead) are actually done filtering when we
change, so the user still needs to manually seek to actually refresh
everything. And since subtitle data is usually cached in ASS_Track (for
other terrible but user-friendly reasons), we also must clear the
subtitle data, but of course only on seek, since otherwise all subtitles
would just disappear. What a fucking mess, but such is life. We could
trigger a "refresh seek" to make this more automatic, but I don't feel
like it currently.
This is slightly inefficient (lots of allocations and copying), but I
decided that it doesn't matter. Could matter slightly for crazy ASS
subtitles that render with thousands of events.
Not very well tested. Still seems to work, but I didn't have many test
cases.
the macOS config was only used in cocoa-cb before and only included when
it was available. since this config is meant for general macOS options
and backend independent options we include it when cocoa is available.
one of the options is already used in the old cocoa backend, which broke
using it when build without swift or cocoa-cb support.
Fixes#7449
As requested I guess. It behaves quite similar to the --loop* options.
Not quite happy with the idea that 1) the option is mutated on each
operation (but at least it's consistent with --loop* and doesn't require
more properties), and 2) the ab-loop command will do nothing once all
loop iterations are done. As a concession, the OSD shows something about
"disabled".
Fixes: #7360
See #7435 and related for context.
Basically, it seems that while the original vsfilter processed subtitles
like with this option set to "yes", many current players (mpc-hc
default, vlc, probably most libass users) treat them like with "no". In
the linked issue, this makes rendering severely slower, and can consume
a lot of memory (or just overflow libass memory calculations). It seems
that changing this to "no" will lead to more good than bad, especially
because newer subtitles may be authored for the "no" behavior.
Most libass users seem to use "no" exactly because they do not call
ass_set_storage_size() at all. This API was needed because the scaling
of the subtitles depends on the video size (vsfilter bugs, or
something). In addition, it's my personal opinion that rendering should
not depend on the video at all, so I like setting the default of this to
"no".
win32 is a cursed abomination which has "drive letters" at the root of
the filesystem namespace for no reason. This requires special handling
beyond tolerating the idiotic "\" path separator.
Even more cursed is the fact that a path starting with a drive letter
can be a relative path. For example, "c:billsucks" is actually a
relative path to the current working directory of the C drive. So for
example if the current working directory is "c:/windowsphone", then
"c:billsucks" would reference "c:/windowsphone/billsucks".
You should realize that win32 is a ridiculous satanic trash fire by the
point you realize that win32 has at least 26 current working
directories, one for each drive letter.
Anyway, the actual problem is that mpv's mp_path_join() function would
return a relative path if an absolute relative path is joined with a
drive-relative path. This should never happen; I bet it breaks a lot of
assumptions (maybe even some security or safety relevant ones, but
probably not).
Since relative drive paths are such a fucked up shit idea, don't try to
support them "properly", and just solve the problem at hand. The
solution produces a path that should be invalid on win32.
Joining two relative paths still behaves the same; this is probably OK
(maybe).
The change isn't very minimal due to me rewriting parts of it without
strict need, but I don't care.
Note that the Python os.path.join() function (after which the mpv
function was apparently modeled) has the same problem.
There wasn't really much of a reason to keep split_opt and
splot_opt_silent apart. It made sense before the latter also had a log
call (which was silenced by using mp_null_log if necessary).
Just merge them back into one, and always rely on mp_null_log to silence
unwanted output.
Shouldn't have any functional changes.
Addresses dumb things like accidentally overwriting a media file with
e.g. "mpv --log-file test.mkv" (when the user thought that --log-file
was a flag option, when it actually takes a filename). This example will
now print an error. It still works with "-log-file overwritten.mkv", but
prints a warning.
Not sure if I'm being too careful or not "radical" enough. In any case,
both the syntax that stops working and the syntax that produces a
warning now have been discouraged and were called legacy for almost a
decade.
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.)
There are a lot of ad-hoc component lists in mpv: for example the stream
and demuxer lists. It doesn't seem to make sense to add any abstractions
around it since they are completely trivial and have very specific
probing mechanisms and so on, so they will remain ad-hoc.
This commits add a way to let these add arbitrary per-component options,
without giving up the ad-hoc way, and without having to dump them into
options.c with lots of ifdeffery (like it was done until now).
Also see next commit.
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.
This option type, used by --audio-channels, had a completely broken
m_option_type.equal implementation, and thus reacted incorrectly to
runtime option changes.
Broken since commit b16cea750f.
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
keyvalue_list_find_key() was called on a "partially" constructed list,
because the terminating NULL was added only later. Didn't I say this
code is cursed?
Fixes: #7273
This was completely broken: it compared the first item of the filter
list only. Apparently I forgot that this is a list. This probably broke
aspects of runtime filter changing probably since commit b16cea750f.
Fix this, and remove some redundant code from obj_settings_equals().
Which is not the same as m_obj_settings_equal(), so rename it to make
confusing them harder. (obj_setting_match() has these very weird label
semantics that should probably just be killed. Or not.)
I don't even know anymore whether this was intended or not. Certain use
cases for the "-o" options might require this. These options are for
passing general FFmpeg options. These are translated to av_opt_set()
calls, which may or may not accumulate the option values on multiple
calls with the same option name (how should I know?).
Anyway, it seems crazy to allow non-unique keys, so make them unique.
The ad-hoc nature of the option code makes this wonderfully complicated
(when I wrote that this code is cursed, I meant it). In combination with
lazy testing, it probably means there are lots of bugs here.
Whenever I deal with this, I have to look at the code to make sense of
this. And beyond that, there are some strange inconsistencies. (I think
this code is cursed. It always was, and maybe always will be.)
Although the manpage claimed that using multiple items for -add etc. is
deprecated, string list options didn't warn against it. So add the
warning, and add something in the changelog (even though nobody will
ever read this).
The manpage mentioned --vf-append, but this didn't even exist. So add
it, I guess. We encourage using -append for the other option types, so
for consistency, it should work on filter options. (And I already
tricked me into believing it existed when I mentioned it in the
manpage.)
Make the "operations" table separate for all option types, and mention
the option type on every single of the top-level list options.
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 for the previous commit, and should affect behavior with the
special M_PROPERTY_GET_CONSTRICTED_TYPE mechanism only. The effect is
that cycling the "edition" property, if the option is set to "auto",
will change to the second edition instead of the first.
Normally, option values must always be within their range, so this
should not affect anything else. M_PROPERTY_GET_CONSTRICTED_TYPE is
sort-of fine with this kind of behavior.
If this affects any other M_PROPERTY_GET_CONSTRICTED_TYPE users
neqatively, I will revert the change.
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>
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.
We don't want m_config uninitialization to call random change callbacks.
This happens at the end of mp_destroy(), when almost everything else is
already destroyed, and the change callbacks would probably trigger UB
all over the place.
The change callbacks could be trigger by m_config_restore_backups(),
which is just used as a cheap way to free the remaining state. The worst
is that this depends on which options may still have been part of this
"backup" state, which depends on user input.
Probably never a practical problem, since the backup state is most
likely guaranteed to be empty before uninit is performed, but still.
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.
Goes in line with the recent changes to always checking for option value
changes. The player core will use this to determine whether it should
send additional change events.
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.
The original MPlayer m_config was essentially only responsible for
handling some command line parsing details, handling profiles, and
file-local options. And then there's the new mpv stuff (that stuff was
regretfully written by me), which is mostly associated with making
things thread-safe (includes things like making it all library-safe,
instead of stuffing all option data into global variables).
This commit tries to separate them some more. For example,
m_config_shadow (the thread-safe thing) now does not need access to
m_config anymore. m_config can hopefully be reduced to handling only the
"old" mplayer-derived mechanisms.
This will allow any other threads to write to the global option data in
a safe way.
The typical example for this is the fullscreen option, which needs to be
written by VO (or even some other thing running completely separate from
the main thread). We have a complicated and annoying contraption which
gets the value updated on the main thread, and this function will help
get rid of it.
As of this commit, this doesn't really work yet, because he main thread
uses its own weird copy of the option data.
This adds m_config_cache_get_next_changed() and the change_flags field
in m_config_cache. Both can be used to determine whether specific
options changed (rather than the entire sub-group).
Not sure if I'm very happy with that. The former rather compact
update_options() is now a bit of a mess, because it needs to be
incremental. m_config_cache_get_next_changed() will not be too nice to
use, and change_flags still relies on global "allocation" of change
flags (see UPDATE_* defines in m_option.h). If C weren't such a
primitive language that smells like grandpa, it would be nice to define
per-option change callbacks or so.
This compares options by value to determine whether they have changed.
This makes it slower in theory, but in practice it probably doesn't
matter (options are rarely changed after initialization). The
alternative would have been per-option change counters (wastes too much
memory; not a practical problem but too ugly), or keep all
m_config_caches in a global list and have bitmaps with per-option change
bits (sounds complicated). I guess the current way is OK.
Technically, this changes semantics slightly by ignoring setting an
option to the same value. Technically this wasn't a no-op, although the
effect was almost almost no-op. Some code would actually become cleaner
by ignoring such redundant change events, and them being no-op is
probably also what the user would normally assume.
Create a separate struct for internal fields of m_config_cache, so API
users can't just mess with stuff they shouldn't access.
Move the ts field out of m_config_data, so we don't need unnecessary
atomics in one case.
This is just preparation, and shouldn't change any behavior.
The exact type name (m_obj_list_t) was removed in 2013. I don't think
this stub comment helps much with understanding this complicated thing
anyway (this code is for the --vf/--af options, and makes up almost half
of m_option.c).
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.
Until now, using a filter not in mpv's builtin filter list would assume
it's a libavfilter filter. If it wasn't, the option value was still
accepted, but creating the filter simply failed. But since this happens
after option parsing, so the result is confusing.
Improve this slightly by checking filter names. This will reject truly
unknown filters at option parsing time. Unfortunately, this still does
not check filter arguments. This would be much more complex, because
you'd have to create a dummy filter graph and allocate the filter. Maybe
another time.
This function is dangerous, because it disables the already basic/week
type checking the option system has at all. I'm tend towards thinking
that all of its uses should be replaced.
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.
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.
I have no idea why this still exists, since we have --input-ipc-server.
I think there was something about Windows, but the latter option is
implemented even on Windows.
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.
Options marked with this flag were changed to strictly read-only after
initialization (mpv_initialize() in the client API, after option parsing
and config file loading with the CLI player).
This used to be necessary, because there was a single option struct that
could be accessed by multiple threads. For example, --config-dir sets
MPOpts.force_configdir, which was read whenever anything accessed the
mpv config dir (which could be on different threads, e.g. font
initialization tries to lookup fonts.conf from an arbitrary thread).
This isn't needed anymore, because threads now access these in a thread
safe way. In the case of --config-dir, the path is actually just copied
on init.
This M_OPT_FIXED mechanism is thus not strictly needed anymore. It still
prevents writing to some options that cannot take effect at runtime, but
even that can be dropped. In general, all mpv options can be changed any
time at runtime, even if they never take effect, and there's no need to
make an exception for a very low number of options. So just get rid of
it.
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.
In some corner cases (see #6802), it can be beneficial to use a larger
stream buffer size. Use this as argument to rewrite everything for no
reason.
Turn stream.c itself into a ring buffer, with configurable size. The
latter would have been easily achievable with minimal changes, and the
ring buffer is the hard part. There is no reason to have a ring buffer
at all, except possibly if ffmpeg don't fix their awful mp4 demuxer, and
some subtle issues with demux_mkv.c wanting to seek back by small
offsets (the latter was handled with small stream_peek() calls, which
are unneeded now).
In addition, this turns small forward seeks into reads (where data is
simply skipped). Before this commit, only stream_skip() did this (which
also mean that stream_skip() simply calls stream_seek() now).
Replace all stream_peek() calls with something else (usually
stream_read_peek()). The function was a problem, because it returned a
pointer to the internal buffer, which is now a ring buffer with
wrapping. The new function just copies the data into a buffer, and in
some cases requires callers to dynamically allocate memory. (The most
common case, demux_lavf.c, required a separate buffer allocation anyway
due to FFmpeg "idiosyncrasies".) This is the bulk of the demuxer_*
changes.
I'm not happy with this. There still isn't a good reason why there
should be a ring buffer, that is complex, and most of the time just
wastes half of the available memory. Maybe another rewrite soon.
It also contains bugs; you're an alpha tester now.
In 2017, we lowered this to debug level. But I think setting options is
important enough that it should be logged even in verbose, at least
compared to all the other dumb noise.
This might be reduced again if verbose logging becomes much cleaner.
Purpose uncertain. I guess it's slightly better, maybe.
The move of the sws/zimg options from VO opts (vo_opt_list) to the
top-level option list is tricky. VO opts have some helper code in vo.c,
that sends VOCTRL_SET_PANSCAN to the VO on every VO opts change. That's
because updating certain VO options used to be this way (and not just
the panscan option). This isn't needed anymore for sws/zimg options, so
explicitly move them away.
Internally, vo_gpu uses NaN for some options to indicate a default value
that is different depending on the context (e.g. different scalers).
There are 2 problems with this:
1. you couldn't reset the options to their defaults
2. NaN is a damn mess and shouldn't be part of the API
The option parser already rejected NaN explicitly, which is why 1.
didn't work. Regarding 2., JSON might be a good example, and actually
caused a bug report.
Fix this by mapping NaN to the special value "default". I think I'd
prefer other mechanisms (maybe just having every scaler expose separate
options?), but for now this will do. See you in a future commit, which
painfully deprecates this and replaces it with something else.
I refrained from using "no" (my favorite magic value for "unset" etc.)
because then I'd have e.g. make --no-scale-param1 work, which in
addition to a lot of effort looks dumb and nobody will use it.
Here's also an apology for the shitty added test script.
Fixes: #6691
This provides a very similar API to sws_utils.h, which can be used to
convert and scale from one mp_image to another.
This commit adds only the code, but does not use it anywhere.
The code is quite preliminary and barely tested. It supports only a few
pixel formats, and will return failure for many others. (Unlike
libswscale, which tries to support anything that FFmpeg knows.)
zimg itself accepts only planar formats. Supporting other formats
requires manual packing/unpacking. (Compared to libswscale, the zimg API
is generally lower level, but allows for more flexibility.) Only BGR0
output was actually tested. It appears to work.
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.
It seems using multiple prefixes for an option isn't supported out of
laziness (and shouldn't, because what the fuck). So assert() on this.
(Unfortunately this prefix nonsense is still needed. Especially AO and
VO options use this through the options_prefix field.)
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.
m_config has a m_config_option array, that is used for all option
access. The code maintaining shadow copies also tried to make use of it,
and did so by "cleverly" assigning each m_sub_options run a slice of
that array. But actually it's much simpler to, you know, directly access
the damn options.
This helps separation m_config and the general option code slightly.
Still seems to work after a superficial test, good enough.
This is good because a private thing is not so public anymore, and it's
also preparation for further changes.
Some tricky memory management issues: m_config_data (i.e. config->data)
now depends on m_config_shadow, instead of m_config. In particular,
free_option_data() accesses the m_config_shadow.groups array. Obviously
it must be freed before m_config_shadow.
Move the comments documenting exported functions to the header. It looks
like the header is the preferred place for that (although I don't really
appreciate headers where you lose the overview because of all the
documentation comments). Add comments to some undocumented prototypes.
This was one of those "shouldn't exist" type of functions that could
access internals that were supposed to be isolated away, but some code
needed to access it anyway.
It looks like the last use of it went away in 2016, shortly after it was
introduced.
Or at least I hope it's theoretical. This function is supposed to unset
any old listeners for the given cache, and the code works only if
there's at most 1. Add a defense break to avoid UB if there's more than
one, and add an assert() to check the assumption that there's at most
one.
The added comment is unrelated.
Semantics a bit questionable. This is done for the OSC (next commit),
and a comment added the manpage explicitly states this. Meaning this is
probably garbage and needs to revisit when the OSC changes and/or
someone wants to use this margin feature for something else.
Not sure about the subtitle thing. It's imaginable that someone uses
these options to create empty borders for subtitles on the bottom, so
subtitles should be located there. On the other hand, this gives a
rather unpolished user experience when using the (later added) OSC
feature to not overlap with the video. There's not much of a point if
the OSC still overlaps the video. However, I'm too lazy to think about
this, so it stays like it is.
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 conversion to string as the pretty printer returns it is
sometimes used on OSD. I think it's pretty odd that quantities below 1
KB are shown as number without suffix. So use "B" for them.
For orthogonality, allow the same for parsing. (Although strictly
speaking, this is not a requirement of the option API. Option parsers
don't need to accept pretty-printed strings.)
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).
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.
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.