Until now, we didn't do this, because it required some effort, and
didn't seem to be necessary. It probably still isn't, but it sounds
like a good idea not to output arbitrary data on these channels.
The situation is complicated by the fact that just adding new channels
to a planar frame would require messing with buffers. So we would have
to allocate new buffers and add them to the frame. We could have to
maintain an extra buffer pool for this. Avoid this by being "clever",
and just allocate a frame with enough channels in the first place.
libav/swresample won't know about these channels and won't write to
them, but we can grab them in reorder_planes() and use them for the
NA channels.
This is better, because now we call swr_get_delay() with the output
samplerate, instead of with the input samplerate and then multiplying it
with the ratio and rounding it up.
This manually retrieved the remaining audio from the resampler. It
subtly missed a conversion which could leave to an unsubtle crash.
This could happen if reorder_planes() was supposed to insert NA
channels, and the resampler/actual output format were different.
Simplify it by reusing the normal drain path. One oddness is that
the filter will add an output frame outside of normal filtering,
but that should be fine.
This brings the volume control closer to what is percepted as linear
volume change.
Adjust the --softvol-max default to roughly the old maximum (roughly
doubles the gain).
Some time ago, a mechanism was added for automatically removing PCM-only
filters if the input format is spdif.
This could cause an infinite loop if the AO did not support spdif, but
was falling back to some PCM format. Then this code tried to remove the
last filter, which is a dummy filter for receiving and queuing filter
output. af_remove() simply fails gracefully in this case, so this
happens over and over again.
Fix by explicitly checking whether the filter to remove is a dummy
filter. (af_remove() also fails only if the dummy filters are attempted
to be removed - checking this directly is simpler.)
Some audio APIs explicitly require you to add dummy channels. These are
not rendered, and only exist for the sake of the audio API or hardware
strangeness. At least ALSA, Sndio, and CoreAudio seem to have them.
This commit is preparation for using them with ao_coreaudio.
The result is a bit messy. libavresample/libswresample don't have good
API for this; avresample_set_channel_mapping() is pretty useless.
Although in theory you can use it to add and remove channels, you
can't set the channel counts. So we do the ordering ourselves by making
sure the audio data is planar, and by swapping the plane pointers. This
requires lots of messiness to get the conversions in place. Also, the
input reordering is still done with the "old" method, and doesn't
support padded channels - hopefully this will never be needed. (I tried
to come up with cleaner solutions, but compared to my other attempts,
the final commit is not that bad.)
It could happen that a lavrresample filter would keep its old output
format when the decoder changed its output format. This simply happened
because the output format was never reset.
Normally, this was not an issue, because lavrresample filters only
inserted for format conversion were removed on format changes. But if
--no-audio-pitch-correction is set and playback speed is changed, then
there is a "permanent" lavrresample filter in the filter chain, which
shows this behavior.
Fix by explicitly resetting output formats for all filters which support
it.
Note: this can crash with libswresample in some cases. I'm not sure if
this is mpv's fault or libswresample's, but since it works with
libavresample, I'm going to assume it's not our's.
The af_add() function has a problem: if the inserted filter returns
AF_DETACH during init, the function will have a dangling pointer. Until
now this was avoided by making sure none of the used filters actually
return AF_DETACH, but it's getting infeasible.
Solve this by requiring passing an unique label to af_add(), which is
then used instead of the pointer.
libswresample doesn't normalize when remixing to a float format. This
will cause clipping due to float samples being out of the allowed range.
Fortunately this extremely bad default can be changed.
This does not happen with libavresample: it normalizes by default.
Fixes#1752.
--af=bs2b:help abort()ed because the default value of the "profile"
option is not represented by any choice. Fix it by adding an "unset"
choice. (It's a bit odd because there's already a "default" choice,
which is not default, but I don't care enough about this filter.)
Fixes#1712.
To handle seeking correctly, we need to flush the filter. libavfilter
does not support flushing, so we destroy and recreate it. We also need
to handle resume-after-EOF, because the mpv audio code sends an EOF
before and after seeking (the latter happens because the player drains
the filter chain in a generic way, which "causes" EOF).
Handle the failure gracefully, instead of exploding and disabling audio.
Just set the speed back to 1.0.
Also remove the AF_DETACH from af_scaletempo. This actually created a
dangling pointer in af_add(), a tricky consequence of af_add()
reconfiguring the filter chain and the newly added filter using
AF_DETACH. Fortunately the AF_DETACH is not needed (and probably never
worked - it comes from MPlayer times, and MPlayer also disables audio
when trying to change speed with spdif).
Although the libraries we use for resampling (libavresample and
libswresample) do not support changing sampelrate on the fly, this makes
it easier to make sure no audio buffers are implicitly dropped. In fact,
this commit adds additional code to drain the resampler explicitly.
Changing speed twice without feeding audio in-between made it crash
with libavresample inc ertain cases (libswresample is fine). This is
probably a libavresample bug. Hopefully this will be fixed, and also I
attempted to workaround the situation that crashes it. (It seems to
point in direction of random memory corruption, though.)
rubberband_available() can return a negative value, which we assigned to
a size_t variable, leading to the frame allocation to fail. This could
spam "Error filtering frame.". (That it spams this instead of exiting
should probably also be considered a bug.)
At least in the realtime mode and in our case, a negative return value
should not have any different meaning from a 0 return value, in
particular because we call rubberband_get_samples_required() or set the
"final" parameter for rubberband_process() to continue/stop processing.
After some testing, I am fairly convinced that these defaults sound
better than the previous settings. This also eliminates some issue
with random crackling and noise.
Also remove the `stretch` option since it has no effect in
realtime mode.
The previous commit on this filter accidentally removed the
RubberBandOptionProcessRealTime option. Without it, the lib prints a
warning and passes the audio through.
Also add the RubberBandOptionSmoothingOn option back. Though for some
reason the output sounds still very wrong.
librubberband exports a big load of options. Normally, the default
settings (whether they're librubberband defaults or our defaults) should
be sufficient, but since I'm not so sure about this, making it
configurable allows others to figure it out for me.
The problem here is that librubberband can buffer an arbitrary amount
of data, but at the same time doesn't provide a way to query how much
data is buffered. So we keep track of this manually, assuming that
librubberband tries to reach the requested time ratio for input and
output (which is probably true).
The disadvantage is that rounding errors could accumulate over time.
(Maybe it should try to round towards keeping the time ratio.)
In theory it could happen that draining on EOF happens incrementally,
and then the unconditional reset could have dropped the remaining
buffered audio.
If "--af=rubberband" is used, librubberband will be used to speed up or
slow down audio with pitch correction.
This still has some problems: the audio delay is not calculated
correctly, so the audio position jitters around by a few milliseconds.
This will probably ruin video timing.
Staring at the code a bit, it turns out that changing speed without
losing state is quite easy. The initialization code is big and
complicated, but most of it is specific only to the configured audio
format, not the speed.
Refactor the code so that changing speed at runtime could work. (It's
not actually used yet - the player code still does a complete reinit.
This will be fixed in the next commit.)
The "if (s->speed_tempo == s->speed_pitch)" looks a bit strange, but
does the same thing as the code did before: speed can be changed only if
exactly one flag is set. If both are set or none, speed can't be
changed.
This code skipped initialization if no speed/pitch change was to be
applied.
It also didn't force conversion of the audio to a supported format,
which is probably the most important case in context of compatibility.
With this change applied, af_scaletempo will always force format
conversion.
To make the change less disruptive, make the filter detach if
unconvertable formats are used. Some users use spdif and also have
"af=scaletempo" in their config, so better not completely break this.
In the case the filter was added with the "speed=both" suboption, the
filter also detached itself in this case; but it's an obscure case, so I
don't care about that.
Adds about 7 lines of boilerplate per filter. This could be avoided by
providing a different entrypoint (something like af->filter_inplace),
which would basically mirror the old interface exactly for this kind of
filter. But I feel like it would just be a hack to support all those
old, useless filters better. (The ideal solution would be using a
language that can do closures to provide a compat. wrapper, but
whatever.)
af_bs2b has terribly repetitious code for setting up filter functions
for each format (most of them useless, in addition to bs2b being
useless), so I did something terrible with macros.
af_sinesuppress had commented code for float filtering (maybe it was
broken; it has been commented every since it was added in 2006). Remove
this code.
Just to make sure all filters get the correct format. Together wih the
check in af_add_output_frame(), this asserts that
af->prev->fmt_out == af->fmt_in
This also requires setting the "in" pseudo-filter (s->first) formats
correctly. Before this commit, the fmt_in/fmt_out fields weren't used
for this filter.