audio/filters: add af_force

Its main purpose is for testing in case channel layout stuff breaks, in
particular in connection with old audio filters.
This commit is contained in:
wm4 2013-05-09 12:09:23 +02:00
parent ce2515ddb8
commit d9582ad0a4
6 changed files with 189 additions and 0 deletions

View File

@ -210,6 +210,34 @@ channels=nch[:nr:from1:to1:from2:to2:from3:to3:...]
Would change the number of channels to 6 and set up 4 routes that copy
channel 0 to channels 0 to 3. Channel 4 and 5 will contain silence.
force=in-format:in-srate:in-channels:out-format:out-srate:out-channels
Force a specific audio format/configuration without actually changing the
audio data. Keep in mind that the filter system might auto-insert actual
conversion filters before or after this filter if needed.
All parameters are optional. The ``in-`` variants restrict what the filter
accepts as input. The ``out-`` variants change the audio format, without
actually doing a conversion. The data will be 'reinterpreted' by the
filters or audio outputs following this filter.
<in-format>
Force conversion to this format. See ``format`` filter for valid audio
format values.
<in-srate>
Force conversion to a specific sample rate. The rate is an integer,
48000 for example.
<in-channels>
Force mixing to a specific channel layout. See ``--channels`` option
for possible values.
<out-format>
<out-srate>
<out-channels>
format[=format]
Convert between different sample formats. Automatically enabled when
needed by the sound card or another filter. See also ``--format``.
@ -293,6 +321,11 @@ pan=n[:L00:L01:L02:...L10:L11:L12:...Ln0:Ln1:Ln2:...]
channels 0 and 1 into output channel 2 (which could be sent to a
subwoofer for example).
*NOTE*: if you just want to force remixing to a certain output channel
layout, it's easier to use the ``force`` filter. For example,
``mpv '--af=force=channels=5.1' '--channels=5.1'`` would always force
remixing audio to 5.1 and output it like this.
sub[=fc:ch]
Adds a subwoofer channel to the audio stream. The audio data used for
creating the subwoofer channel is an average of the sound in channel 0 and

View File

@ -139,6 +139,7 @@ SOURCES = talloc.c \
audio/filter/af_dummy.c \
audio/filter/af_equalizer.c \
audio/filter/af_extrastereo.c \
audio/filter/af_force.c \
audio/filter/af_format.c \
audio/filter/af_hrtf.c \
audio/filter/af_karaoke.c \

View File

@ -56,6 +56,12 @@ void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src)
dst->rate = src->rate;
}
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b)
{
return a->format == b->format && a->rate == b->rate &&
mp_chmap_equals(&a->channels, &b->channels);
}
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format)
{
char *chstr = mp_chmap_to_str(chmap);

View File

@ -38,6 +38,7 @@ void mp_audio_set_num_channels(struct mp_audio *mpa, int num_channels);
void mp_audio_set_channels_old(struct mp_audio *mpa, int num_channels);
void mp_audio_set_channels(struct mp_audio *mpa, const struct mp_chmap *chmap);
void mp_audio_copy_config(struct mp_audio *dst, const struct mp_audio *src);
bool mp_audio_config_equals(const struct mp_audio *a, const struct mp_audio *b);
char *mp_audio_fmt_to_str(int srate, const struct mp_chmap *chmap, int format);
char *mp_audio_config_to_str(struct mp_audio *mpa);

View File

@ -29,6 +29,7 @@ extern struct af_info af_info_dummy;
extern struct af_info af_info_delay;
extern struct af_info af_info_channels;
extern struct af_info af_info_format;
extern struct af_info af_info_force;
extern struct af_info af_info_volume;
extern struct af_info af_info_equalizer;
extern struct af_info af_info_pan;
@ -52,6 +53,7 @@ static struct af_info* filter_list[] = {
&af_info_dummy,
&af_info_delay,
&af_info_channels,
&af_info_force,
&af_info_volume,
&af_info_equalizer,
&af_info_pan,

146
audio/filter/af_force.c Normal file
View File

@ -0,0 +1,146 @@
/*
* 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 <stdlib.h>
#include <libavutil/common.h>
#include "core/m_config.h"
#include "core/m_option.h"
#include "audio/format.h"
#include "af.h"
struct priv {
struct m_config *config;
int in_format;
int in_srate;
struct mp_chmap in_channels;
int out_format;
int out_srate;
struct mp_chmap out_channels;
struct mp_audio data;
struct mp_audio temp;
};
static const struct priv defaults = {
.in_format = AF_FORMAT_UNKNOWN,
.out_format = AF_FORMAT_UNKNOWN,
};
#define OPT_BASE_STRUCT struct priv
static const struct m_option options[] = {
OPT_AUDIOFORMAT("format", in_format, 0),
OPT_INTRANGE("srate", in_srate, 0, 1000, 8*48000),
OPT_CHMAP("channels", in_channels, CONF_MIN, .min = 0),
OPT_AUDIOFORMAT("out-format", out_format, 0),
OPT_INTRANGE("out-srate", out_srate, 0, 1000, 8*48000),
OPT_CHMAP("out-channels", out_channels, CONF_MIN, .min = 0),
{0}
};
static int control(struct af_instance *af, int cmd, void *arg)
{
struct priv *priv = af->setup;
switch (cmd) {
case AF_CONTROL_REINIT: {
struct mp_audio *in = arg;
struct mp_audio orig_in = *in;
struct mp_audio *out = af->data;
if (priv->in_format != AF_FORMAT_UNKNOWN)
mp_audio_set_format(in, priv->in_format);
if (priv->in_channels.num)
mp_audio_set_channels(in, &priv->in_channels);
if (priv->in_srate)
in->rate = priv->in_srate;
mp_audio_copy_config(out, in);
if (priv->out_format != AF_FORMAT_UNKNOWN)
mp_audio_set_format(out, priv->out_format);
if (priv->out_channels.num)
mp_audio_set_channels(out, &priv->out_channels);
if (priv->out_srate)
out->rate = priv->out_srate;
if (in->nch != out->nch || in->bps != out->bps) {
mp_msg(MSGT_AFILTER, MSGL_ERR,
"[af_force] Forced input/output format are incompatible.\n");
return AF_ERROR;
}
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
}
case AF_CONTROL_COMMAND_LINE: {
if (m_config_parse_suboptions(priv->config, "af_force", (char *)arg) < 0)
return AF_ERROR;
return AF_OK;
}
}
return AF_UNKNOWN;
}
static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
{
struct priv *priv = af->setup;
struct mp_audio *r = &priv->temp;
*r = *af->data;
r->audio = data->audio;
r->len = data->len;
return r;
}
static void uninit(struct af_instance *af)
{
talloc_free(af->setup);
}
static int af_open(struct af_instance *af)
{
af->control = control;
af->uninit = uninit;
af->play = play;
af->mul = 1;
struct priv *priv = talloc(NULL, struct priv);
af->setup = priv;
*priv = defaults;
priv->config = m_config_simple(priv);
talloc_steal(priv, priv->config);
m_config_register_options(priv->config, options);
af->data = &priv->data;
return AF_OK;
}
struct af_info af_info_force = {
"Force audio format",
"force",
"",
"",
0,
af_open
};