2013-03-09 08:30:26 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
|
|
|
|
* Copyright (c) 2013 Stefano Pigozzi <stefano.pigozzi@gmail.com>
|
|
|
|
*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
|
|
|
* MPlayer 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.
|
|
|
|
*
|
|
|
|
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <libavutil/opt.h>
|
|
|
|
#include <libavutil/audioconvert.h>
|
|
|
|
#include <libavutil/common.h>
|
|
|
|
#include <libavutil/samplefmt.h>
|
|
|
|
#include <libavutil/mathematics.h>
|
|
|
|
|
|
|
|
#include "talloc.h"
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#if defined(CONFIG_LIBAVRESAMPLE)
|
|
|
|
#include <libavresample/avresample.h>
|
|
|
|
#elif defined(CONFIG_LIBSWRESAMPLE)
|
|
|
|
#include <libswresample/swresample.h>
|
|
|
|
#define AVAudioResampleContext SwrContext
|
|
|
|
#define avresample_alloc_context swr_alloc
|
|
|
|
#define avresample_open swr_init
|
|
|
|
#define avresample_close(x) do { } while(0)
|
|
|
|
#define avresample_available(x) 0
|
|
|
|
#define avresample_convert(ctx, out, out_planesize, out_samples, in, in_planesize, in_samples) \
|
|
|
|
swr_convert(ctx, out, out_samples, (const uint8_t**)(in), in_samples)
|
2013-04-05 22:56:01 +00:00
|
|
|
#define avresample_set_channel_mapping swr_set_channel_mapping
|
2013-03-09 08:30:26 +00:00
|
|
|
#else
|
|
|
|
#error "config.h broken"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "core/mp_msg.h"
|
|
|
|
#include "core/subopt-helper.h"
|
|
|
|
#include "audio/filter/af.h"
|
2013-03-23 12:01:44 +00:00
|
|
|
#include "audio/fmt-conversion.h"
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
struct af_resample_opts {
|
|
|
|
int filter_size;
|
|
|
|
int phase_shift;
|
|
|
|
int linear;
|
|
|
|
double cutoff;
|
|
|
|
|
|
|
|
int in_rate;
|
2013-03-23 12:01:44 +00:00
|
|
|
int in_format;
|
2013-04-05 18:39:52 +00:00
|
|
|
struct mp_chmap in_channels;
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
int out_rate;
|
|
|
|
int out_format;
|
2013-04-05 18:39:52 +00:00
|
|
|
struct mp_chmap out_channels;
|
2013-03-09 08:30:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct af_resample {
|
2013-03-29 21:29:13 +00:00
|
|
|
int allow_detach;
|
2013-03-09 08:30:26 +00:00
|
|
|
struct AVAudioResampleContext *avrctx;
|
2013-04-05 22:56:01 +00:00
|
|
|
struct AVAudioResampleContext *avrctx_out; // for output channel reordering
|
2013-03-09 08:30:26 +00:00
|
|
|
struct af_resample_opts ctx; // opts in the context
|
|
|
|
struct af_resample_opts opts; // opts requested by the user
|
2013-04-05 22:56:01 +00:00
|
|
|
// At least libswresample keeps a pointer around for this:
|
|
|
|
int reorder_in[MP_NUM_CHANNELS];
|
|
|
|
int reorder_out[MP_NUM_CHANNELS];
|
|
|
|
bool need_reorder_out;
|
|
|
|
uint8_t *reorder_buffer;
|
2013-03-09 08:30:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CONFIG_LIBAVRESAMPLE
|
|
|
|
static int get_delay(struct af_resample *s)
|
|
|
|
{
|
|
|
|
return avresample_get_delay(s->avrctx);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int get_delay(struct af_resample *s)
|
|
|
|
{
|
|
|
|
return swr_get_delay(s->avrctx, s->ctx.in_rate);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static double af_resample_default_cutoff(int filter_size)
|
|
|
|
{
|
|
|
|
return FFMAX(1.0 - 6.5 / (filter_size + 8), 0.80);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool needs_lavrctx_reconfigure(struct af_resample *s,
|
|
|
|
struct mp_audio *in,
|
|
|
|
struct mp_audio *out)
|
|
|
|
{
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
return s->ctx.in_rate != in->rate ||
|
2013-03-23 12:01:44 +00:00
|
|
|
s->ctx.in_format != in->format ||
|
2013-04-05 18:39:52 +00:00
|
|
|
!mp_chmap_equals(&s->ctx.in_channels, &in->channels) ||
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
s->ctx.out_rate != out->rate ||
|
2013-03-23 12:01:44 +00:00
|
|
|
s->ctx.out_format != out->format ||
|
2013-04-05 18:39:52 +00:00
|
|
|
!mp_chmap_equals(&s->ctx.out_channels, &out->channels) ||
|
2013-03-09 08:30:26 +00:00
|
|
|
s->ctx.filter_size != s->opts.filter_size ||
|
|
|
|
s->ctx.phase_shift != s->opts.phase_shift ||
|
|
|
|
s->ctx.linear != s->opts.linear ||
|
|
|
|
s->ctx.cutoff != s->opts.cutoff;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-03-23 12:05:32 +00:00
|
|
|
static bool test_conversion(int src_format, int dst_format)
|
|
|
|
{
|
|
|
|
return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE &&
|
|
|
|
af_to_avformat(dst_format) != AV_SAMPLE_FMT_NONE;
|
|
|
|
}
|
|
|
|
|
2013-03-09 08:30:26 +00:00
|
|
|
#define ctx_opt_set_int(a,b) av_opt_set_int(s->avrctx, (a), (b), 0)
|
|
|
|
#define ctx_opt_set_dbl(a,b) av_opt_set_double(s->avrctx, (a), (b), 0)
|
|
|
|
|
|
|
|
static int control(struct af_instance *af, int cmd, void *arg)
|
|
|
|
{
|
|
|
|
struct af_resample *s = (struct af_resample *) af->setup;
|
|
|
|
struct mp_audio *in = (struct mp_audio *) arg;
|
|
|
|
struct mp_audio *out = (struct mp_audio *) af->data;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case AF_CONTROL_REINIT: {
|
2013-03-23 12:01:44 +00:00
|
|
|
struct mp_audio orig_in = *in;
|
|
|
|
|
|
|
|
if (((out->rate == in->rate) || (out->rate == 0)) &&
|
|
|
|
(out->format == in->format) &&
|
2013-04-05 18:39:52 +00:00
|
|
|
(mp_chmap_equals(&out->channels, &in->channels) || out->nch == 0) &&
|
2013-03-29 21:29:13 +00:00
|
|
|
s->allow_detach)
|
2013-03-09 08:30:26 +00:00
|
|
|
return AF_DETACH;
|
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
if (out->rate == 0)
|
|
|
|
out->rate = in->rate;
|
|
|
|
|
2013-04-05 18:39:52 +00:00
|
|
|
if (mp_chmap_is_empty(&out->channels))
|
|
|
|
mp_audio_set_channels(out, &in->channels);
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
|
|
|
|
if (in_samplefmt == AV_SAMPLE_FMT_NONE) {
|
2013-04-05 17:47:51 +00:00
|
|
|
mp_audio_set_format(in, AF_FORMAT_FLOAT_NE);
|
2013-03-23 12:01:44 +00:00
|
|
|
in_samplefmt = af_to_avformat(in->format);
|
|
|
|
}
|
|
|
|
enum AVSampleFormat out_samplefmt = af_to_avformat(out->format);
|
|
|
|
if (out_samplefmt == AV_SAMPLE_FMT_NONE) {
|
2013-04-05 17:47:51 +00:00
|
|
|
mp_audio_set_format(out, in->format);
|
2013-03-23 12:01:44 +00:00
|
|
|
out_samplefmt = in_samplefmt;
|
|
|
|
}
|
|
|
|
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
af->mul = (double) (out->rate * out->nch) / (in->rate * in->nch);
|
2013-03-09 08:30:26 +00:00
|
|
|
af->delay = out->nch * s->opts.filter_size / FFMIN(af->mul, 1);
|
|
|
|
|
|
|
|
if (needs_lavrctx_reconfigure(s, in, out)) {
|
2013-04-05 21:58:08 +00:00
|
|
|
avresample_close(s->avrctx);
|
2013-04-05 22:56:01 +00:00
|
|
|
avresample_close(s->avrctx_out);
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
s->ctx.out_rate = out->rate;
|
|
|
|
s->ctx.in_rate = in->rate;
|
2013-03-23 12:01:44 +00:00
|
|
|
s->ctx.out_format = out->format;
|
|
|
|
s->ctx.in_format = in->format;
|
2013-04-05 18:39:52 +00:00
|
|
|
s->ctx.out_channels= out->channels;
|
|
|
|
s->ctx.in_channels = in->channels;
|
2013-03-09 08:30:26 +00:00
|
|
|
s->ctx.filter_size = s->opts.filter_size;
|
|
|
|
s->ctx.phase_shift = s->opts.phase_shift;
|
|
|
|
s->ctx.linear = s->opts.linear;
|
|
|
|
s->ctx.cutoff = s->opts.cutoff;
|
|
|
|
|
2013-04-05 18:39:52 +00:00
|
|
|
// unchecked: don't take channel reordering into account
|
|
|
|
uint64_t in_ch_layout = mp_chmap_to_lavc_unchecked(&in->channels);
|
|
|
|
uint64_t out_ch_layout = mp_chmap_to_lavc_unchecked(&out->channels);
|
2013-03-09 08:30:26 +00:00
|
|
|
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
ctx_opt_set_int("in_channel_layout", in_ch_layout);
|
|
|
|
ctx_opt_set_int("out_channel_layout", out_ch_layout);
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
ctx_opt_set_int("in_sample_rate", s->ctx.in_rate);
|
|
|
|
ctx_opt_set_int("out_sample_rate", s->ctx.out_rate);
|
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
ctx_opt_set_int("in_sample_fmt", in_samplefmt);
|
|
|
|
ctx_opt_set_int("out_sample_fmt", out_samplefmt);
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
ctx_opt_set_int("filter_size", s->ctx.filter_size);
|
|
|
|
ctx_opt_set_int("phase_shift", s->ctx.phase_shift);
|
|
|
|
ctx_opt_set_int("linear_interp", s->ctx.linear);
|
|
|
|
|
|
|
|
ctx_opt_set_dbl("cutoff", s->ctx.cutoff);
|
|
|
|
|
2013-04-05 22:56:01 +00:00
|
|
|
struct mp_chmap in_lavc;
|
|
|
|
mp_chmap_from_lavc(&in_lavc, in_ch_layout);
|
|
|
|
mp_chmap_get_reorder(s->reorder_in, &in->channels, &in_lavc);
|
|
|
|
|
|
|
|
struct mp_chmap out_lavc;
|
|
|
|
mp_chmap_from_lavc(&out_lavc, out_ch_layout);
|
|
|
|
mp_chmap_get_reorder(s->reorder_out, &out_lavc, &out->channels);
|
|
|
|
s->need_reorder_out = !mp_chmap_equals(&out_lavc, &out->channels);
|
|
|
|
|
|
|
|
// Same configuration; we just reorder.
|
|
|
|
av_opt_set_int(s->avrctx_out, "in_channel_layout", out_ch_layout, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "out_channel_layout", out_ch_layout, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "in_sample_fmt", out_samplefmt, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "out_sample_fmt", out_samplefmt, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "in_sample_rate", s->ctx.out_rate, 0);
|
|
|
|
av_opt_set_int(s->avrctx_out, "out_sample_rate", s->ctx.out_rate, 0);
|
|
|
|
|
|
|
|
// API has weird requirements, quoting avresample.h:
|
|
|
|
// * This function can only be called when the allocated context is not open.
|
|
|
|
// * Also, the input channel layout must have already been set.
|
|
|
|
avresample_set_channel_mapping(s->avrctx, s->reorder_in);
|
|
|
|
avresample_set_channel_mapping(s->avrctx_out, s->reorder_out);
|
|
|
|
|
|
|
|
if (avresample_open(s->avrctx) < 0 ||
|
|
|
|
avresample_open(s->avrctx_out) < 0)
|
|
|
|
{
|
2013-03-09 08:30:26 +00:00
|
|
|
mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Cannot open "
|
|
|
|
"Libavresample Context. \n");
|
|
|
|
return AF_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
return ((in->format == orig_in.format) &&
|
2013-04-05 18:39:52 +00:00
|
|
|
mp_chmap_equals(&in->channels, &orig_in.channels))
|
2013-03-23 12:01:44 +00:00
|
|
|
? AF_OK : AF_FALSE;
|
|
|
|
}
|
|
|
|
case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET: {
|
|
|
|
if (af_to_avformat(*(int*)arg) == AV_SAMPLE_FMT_NONE)
|
|
|
|
return AF_FALSE;
|
|
|
|
|
2013-04-05 17:47:51 +00:00
|
|
|
mp_audio_set_format(af->data, *(int*)arg);
|
2013-03-23 12:01:44 +00:00
|
|
|
return AF_OK;
|
2013-03-09 08:30:26 +00:00
|
|
|
}
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
case AF_CONTROL_CHANNELS | AF_CONTROL_SET: {
|
2013-04-05 18:39:52 +00:00
|
|
|
mp_audio_set_channels(af->data, (struct mp_chmap *)arg);
|
audio: switch to libavcodec channel order, use libavresample for mixing
Switch the internal channel order to libavcodec's. If the channel number
mismatches at some point, use libavresample for up- or downmixing.
Remove the old af_pan automatic downmixing.
The libavcodec channel order should be equivalent to WAVEFORMATEX order,
at least nowadays. reorder_ch.h assumes that WAVEFORMATEX and libavcodec
might be different, but all defined channels have the same mappings.
Remove the downmixing with af_pan as well as the channel conversion with
af_channels from af.c, and prefer af_lavrresample for this. The
automatic downmixing behavior should be the same as before (if the
--channels option is set to 2, which is the default, the audio output
is forced to 2 channels, and libavresample does all downmixing).
Note that mpv still can't do channel layouts. It will pick the default
channel layout according to the channel count. This will be fixed later
by passing down the channel layout as well.
af_hrtf depends on the order of the input channels, so reorder to ALSA
(for which this code was written). This is better than changing the
filter code, which is more risky.
ao_pulse can accept waveext order directly, so set that as channel
mapping.
2013-03-23 16:49:52 +00:00
|
|
|
return AF_OK;
|
|
|
|
}
|
2013-03-09 08:30:26 +00:00
|
|
|
case AF_CONTROL_COMMAND_LINE: {
|
|
|
|
s->opts.cutoff = 0.0;
|
|
|
|
|
|
|
|
const opt_t subopts[] = {
|
|
|
|
{"srate", OPT_ARG_INT, &out->rate, NULL},
|
|
|
|
{"filter_size", OPT_ARG_INT, &s->opts.filter_size, NULL},
|
|
|
|
{"phase_shift", OPT_ARG_INT, &s->opts.phase_shift, NULL},
|
|
|
|
{"linear", OPT_ARG_BOOL, &s->opts.linear, NULL},
|
|
|
|
{"cutoff", OPT_ARG_FLOAT, &s->opts.cutoff, NULL},
|
2013-03-29 21:29:13 +00:00
|
|
|
{"detach", OPT_ARG_BOOL, &s->allow_detach, NULL},
|
2013-03-09 08:30:26 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
if (subopt_parse(arg, subopts) != 0) {
|
|
|
|
mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Invalid option "
|
|
|
|
"specified.\n");
|
|
|
|
return AF_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->opts.cutoff <= 0.0)
|
|
|
|
s->opts.cutoff = af_resample_default_cutoff(s->opts.filter_size);
|
|
|
|
return AF_OK;
|
|
|
|
}
|
|
|
|
case AF_CONTROL_RESAMPLE_RATE | AF_CONTROL_SET:
|
|
|
|
out->rate = *(int *)arg;
|
|
|
|
return AF_OK;
|
|
|
|
}
|
|
|
|
return AF_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef ctx_opt_set_int
|
|
|
|
#undef ctx_opt_set_dbl
|
|
|
|
|
|
|
|
static void uninit(struct af_instance *af)
|
|
|
|
{
|
|
|
|
if (af->setup) {
|
|
|
|
struct af_resample *s = af->setup;
|
|
|
|
if (s->avrctx)
|
|
|
|
avresample_close(s->avrctx);
|
2013-04-05 22:56:01 +00:00
|
|
|
if (s->avrctx_out)
|
|
|
|
avresample_close(s->avrctx_out);
|
2013-03-09 08:30:26 +00:00
|
|
|
talloc_free(af->setup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct mp_audio *play(struct af_instance *af, struct mp_audio *data)
|
|
|
|
{
|
|
|
|
struct af_resample *s = af->setup;
|
|
|
|
struct mp_audio *in = data;
|
|
|
|
struct mp_audio *out = af->data;
|
|
|
|
|
|
|
|
|
|
|
|
int in_size = data->len;
|
|
|
|
int in_samples = in_size / (data->bps * data->nch);
|
|
|
|
int out_samples = avresample_available(s->avrctx) +
|
|
|
|
av_rescale_rnd(get_delay(s) + in_samples,
|
|
|
|
s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP);
|
|
|
|
int out_size = out->bps * out_samples * out->nch;
|
|
|
|
|
|
|
|
if (talloc_get_size(out->audio) < out_size)
|
|
|
|
out->audio = talloc_realloc_size(out, out->audio, out_size);
|
|
|
|
|
|
|
|
af->delay = out->bps * av_rescale_rnd(get_delay(s),
|
|
|
|
s->ctx.out_rate, s->ctx.in_rate,
|
|
|
|
AV_ROUND_UP);
|
|
|
|
|
|
|
|
out_samples = avresample_convert(s->avrctx,
|
|
|
|
(uint8_t **) &out->audio, out_size, out_samples,
|
|
|
|
(uint8_t **) &in->audio, in_size, in_samples);
|
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
*data = *out;
|
2013-04-05 22:56:01 +00:00
|
|
|
|
|
|
|
if (s->need_reorder_out) {
|
|
|
|
if (talloc_get_size(s->reorder_buffer) < out_size)
|
|
|
|
s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
|
|
|
|
data->audio = s->reorder_buffer;
|
|
|
|
out_samples = avresample_convert(s->avrctx_out,
|
|
|
|
(uint8_t **) &data->audio, out_size, out_samples,
|
|
|
|
(uint8_t **) &out->audio, out_size, out_samples);
|
|
|
|
}
|
|
|
|
|
|
|
|
data->len = out->bps * out_samples * out->nch;
|
2013-03-09 08:30:26 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int af_open(struct af_instance *af)
|
|
|
|
{
|
|
|
|
struct af_resample *s = talloc_zero(NULL, struct af_resample);
|
|
|
|
|
|
|
|
af->control = control;
|
|
|
|
af->uninit = uninit;
|
|
|
|
af->play = play;
|
|
|
|
af->mul = 1;
|
|
|
|
af->data = talloc_zero(s, struct mp_audio);
|
|
|
|
|
2013-03-23 12:01:44 +00:00
|
|
|
af->data->rate = 0;
|
2013-03-09 08:30:26 +00:00
|
|
|
|
|
|
|
int default_filter_size = 16;
|
|
|
|
s->opts = (struct af_resample_opts) {
|
|
|
|
.linear = 0,
|
|
|
|
.filter_size = default_filter_size,
|
|
|
|
.cutoff = af_resample_default_cutoff(default_filter_size),
|
|
|
|
.phase_shift = 10,
|
|
|
|
};
|
|
|
|
|
2013-03-29 21:29:13 +00:00
|
|
|
s->allow_detach = 1;
|
|
|
|
|
2013-03-09 08:30:26 +00:00
|
|
|
s->avrctx = avresample_alloc_context();
|
2013-04-05 22:56:01 +00:00
|
|
|
s->avrctx_out = avresample_alloc_context();
|
2013-03-09 08:30:26 +00:00
|
|
|
af->setup = s;
|
|
|
|
|
2013-04-05 22:56:01 +00:00
|
|
|
if (s->avrctx && s->avrctx_out) {
|
2013-03-09 08:30:26 +00:00
|
|
|
return AF_OK;
|
|
|
|
} else {
|
|
|
|
mp_msg(MSGT_AFILTER, MSGL_ERR, "[lavrresample] Cannot initialize "
|
|
|
|
"Libavresample Context. \n");
|
|
|
|
uninit(af);
|
|
|
|
return AF_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct af_info af_info_lavrresample = {
|
|
|
|
"Sample frequency conversion using libavresample",
|
|
|
|
"lavrresample",
|
|
|
|
"Stefano Pigozzi (based on Michael Niedermayer's lavcresample)",
|
|
|
|
"",
|
|
|
|
AF_FLAGS_REENTRANT,
|
2013-03-23 12:05:32 +00:00
|
|
|
af_open,
|
|
|
|
.test_conversion = test_conversion,
|
2013-03-09 08:30:26 +00:00
|
|
|
};
|