mirror of
https://github.com/mpv-player/mpv
synced 2025-01-09 00:19:32 +00:00
audio: change how filters are inserted on playback speed changes
Use a pseudo-filter when changing speed with resampling, instead of somehow changing a samplerate somewhere. This uses the same underlying mechanism, but is a bit more structured and cleaner. It also makes some of the following changes easier. Since we now always use filters to change audio speed, move most of the work set_playback_speed() does to recreate_audio_filters().
This commit is contained in:
parent
995a6af787
commit
e094e9cb75
@ -227,7 +227,6 @@ static int filter_n_bytes(struct dec_audio *da, struct mp_audio_buffer *outbuf,
|
||||
// Filter
|
||||
struct mp_audio filter_data;
|
||||
mp_audio_buffer_peek(da->decode_buffer, &filter_data);
|
||||
filter_data.rate = da->afilter->input.rate; // due to playback speed change
|
||||
len = MPMIN(filter_data.samples, len);
|
||||
filter_data.samples = len;
|
||||
bool eof = error == AD_EOF && filter_data.samples == 0;
|
||||
|
@ -53,6 +53,7 @@ extern const struct af_info af_info_center;
|
||||
extern const struct af_info af_info_sinesuppress;
|
||||
extern const struct af_info af_info_karaoke;
|
||||
extern const struct af_info af_info_scaletempo;
|
||||
extern const struct af_info af_info_forcespeed;
|
||||
extern const struct af_info af_info_bs2b;
|
||||
extern const struct af_info af_info_lavfi;
|
||||
extern const struct af_info af_info_convert24;
|
||||
@ -83,6 +84,7 @@ static const struct af_info *const filter_list[] = {
|
||||
&af_info_center,
|
||||
&af_info_sinesuppress,
|
||||
&af_info_karaoke,
|
||||
&af_info_forcespeed,
|
||||
&af_info_scaletempo,
|
||||
#if HAVE_LIBBS2B
|
||||
&af_info_bs2b,
|
||||
|
@ -120,6 +120,7 @@ enum af_control {
|
||||
AF_CONTROL_SET_PAN_BALANCE,
|
||||
AF_CONTROL_GET_PAN_BALANCE,
|
||||
AF_CONTROL_SET_PLAYBACK_SPEED,
|
||||
AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE,
|
||||
};
|
||||
|
||||
// Argument for AF_CONTROL_SET_PAN_LEVEL
|
||||
|
69
audio/filter/af_forcespeed.c
Normal file
69
audio/filter/af_forcespeed.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "af.h"
|
||||
|
||||
struct priv {
|
||||
double speed;
|
||||
};
|
||||
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
{
|
||||
struct priv *priv = af->priv;
|
||||
|
||||
switch (cmd) {
|
||||
case AF_CONTROL_REINIT: {
|
||||
struct mp_audio *in = arg;
|
||||
struct mp_audio orig_in = *in;
|
||||
struct mp_audio *out = af->data;
|
||||
|
||||
mp_audio_copy_config(out, in);
|
||||
out->rate = in->rate * priv->speed;
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: {
|
||||
priv->speed = *(double *)arg;
|
||||
return AF_OK;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
mp_audio_copy_config(data, af->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
struct priv *priv = af->priv;
|
||||
af->control = control;
|
||||
af->filter = filter;
|
||||
priv->speed = 1.0;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
|
||||
const struct af_info af_info_forcespeed = {
|
||||
.info = "Force audio speed",
|
||||
.name = "forcespeed",
|
||||
.open = af_open,
|
||||
.priv_size = sizeof(struct priv),
|
||||
};
|
@ -127,6 +127,7 @@ SOURCES = audio/audio.c \
|
||||
audio/filter/af_equalizer.c \
|
||||
audio/filter/af_export.c \
|
||||
audio/filter/af_extrastereo.c \
|
||||
audio/filter/af_forcespeed.c \
|
||||
audio/filter/af_format.c \
|
||||
audio/filter/af_hrtf.c \
|
||||
audio/filter/af_karaoke.c \
|
||||
|
@ -43,25 +43,61 @@
|
||||
#include "core.h"
|
||||
#include "command.h"
|
||||
|
||||
static int try_filter(struct MPContext *mpctx,
|
||||
char *name, char *label, char **args)
|
||||
{
|
||||
struct dec_audio *d_audio = mpctx->d_audio;
|
||||
|
||||
if (af_find_by_label(d_audio->afilter, label))
|
||||
return 0;
|
||||
|
||||
struct af_instance *af = af_add(d_audio->afilter, name, args);
|
||||
if (!af)
|
||||
return -1;
|
||||
|
||||
af->label = talloc_strdup(af, label);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int recreate_audio_filters(struct MPContext *mpctx)
|
||||
{
|
||||
assert(mpctx->d_audio);
|
||||
|
||||
struct af_stream *afs = mpctx->d_audio->afilter;
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
struct af_stream *afs = mpctx->d_audio->afilter;
|
||||
|
||||
struct mp_audio in_format;
|
||||
mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &in_format);
|
||||
int new_srate = in_format.rate;
|
||||
double speed = opts->playback_speed;
|
||||
|
||||
if (!af_control_any_rev(afs, AF_CONTROL_SET_PLAYBACK_SPEED,
|
||||
&opts->playback_speed))
|
||||
{
|
||||
new_srate = in_format.rate * opts->playback_speed;
|
||||
if (new_srate != afs->output.rate)
|
||||
opts->playback_speed = new_srate / (double)in_format.rate;
|
||||
if (speed != 1.0) {
|
||||
int method = AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE;
|
||||
if (speed > 1.0 && opts->pitch_correction)
|
||||
method = AF_CONTROL_SET_PLAYBACK_SPEED;
|
||||
if (!af_control_any_rev(afs, method, &speed)) {
|
||||
if (af_remove_by_label(afs, "playback-speed") < 0)
|
||||
return -1;
|
||||
|
||||
// Compatibility: if the user uses --af=scaletempo, always use
|
||||
// this filter to change speed. Don't insert a second "scaletempo"
|
||||
// filter either.
|
||||
if (!af_control_any_rev(afs, AF_CONTROL_SET_PLAYBACK_SPEED, &speed))
|
||||
{
|
||||
char *filter = method == AF_CONTROL_SET_PLAYBACK_SPEED
|
||||
? "scaletempo" : "forcespeed";
|
||||
if (try_filter(mpctx, filter, "playback-speed", NULL) < 0)
|
||||
return -1;
|
||||
// Try again.
|
||||
if (!af_control_any_rev(afs, method, &speed))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (af_remove_by_label(afs, "playback-speed") < 0)
|
||||
return -1;
|
||||
// The filters could be inserted by the user (we don't remove them).
|
||||
af_control_any_rev(afs, AF_CONTROL_SET_PLAYBACK_SPEED, &speed);
|
||||
af_control_any_rev(afs, AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE, &speed);
|
||||
}
|
||||
afs->input.rate = new_srate;
|
||||
|
||||
if (af_init(afs) < 0) {
|
||||
MP_ERR(mpctx, "Couldn't find matching filter/ao format!\n");
|
||||
@ -88,23 +124,6 @@ int reinit_audio_filters(struct MPContext *mpctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int try_filter(struct MPContext *mpctx,
|
||||
char *name, char *label, char **args)
|
||||
{
|
||||
struct dec_audio *d_audio = mpctx->d_audio;
|
||||
|
||||
if (af_find_by_label(d_audio->afilter, label))
|
||||
return 0;
|
||||
|
||||
struct af_instance *af = af_add(d_audio->afilter, name, args);
|
||||
if (!af)
|
||||
return -1;
|
||||
|
||||
af->label = talloc_strdup(af, label);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_playback_speed(struct MPContext *mpctx, double new_speed)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
@ -117,19 +136,6 @@ void set_playback_speed(struct MPContext *mpctx, double new_speed)
|
||||
if (!mpctx->d_audio)
|
||||
return;
|
||||
|
||||
if (new_speed > 1.0 && opts->pitch_correction) {
|
||||
if (!af_control_any_rev(mpctx->d_audio->afilter,
|
||||
AF_CONTROL_SET_PLAYBACK_SPEED,
|
||||
&new_speed))
|
||||
{
|
||||
if (try_filter(mpctx, "scaletempo", "playback-speed", NULL) < 0)
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (af_remove_by_label(mpctx->d_audio->afilter, "playback-speed") < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
recreate_audio_filters(mpctx);
|
||||
}
|
||||
|
||||
|
@ -114,6 +114,7 @@ def build(ctx):
|
||||
( "audio/filter/af_equalizer.c" ),
|
||||
( "audio/filter/af_export.c", "sys-mman-h" ),
|
||||
( "audio/filter/af_extrastereo.c" ),
|
||||
( "audio/filter/af_forcespeed.c" ),
|
||||
( "audio/filter/af_format.c" ),
|
||||
( "audio/filter/af_hrtf.c" ),
|
||||
( "audio/filter/af_karaoke.c" ),
|
||||
|
Loading…
Reference in New Issue
Block a user