audio-resampler: add VARIABLE_RATE flag

Add a VARIABLE rate flag that selects an interpolating filter.
Move some function setup code in the _new function.
This commit is contained in:
Wim Taymans 2016-02-25 14:09:44 +01:00
parent 7bb149dcc1
commit f692d5e459
3 changed files with 62 additions and 51 deletions

View file

@ -673,14 +673,18 @@ chain_resample (GstAudioConverter * convert, AudioChain * prev)
GstAudioResamplerFlags flags; GstAudioResamplerFlags flags;
GstAudioFormat format = convert->current_format; GstAudioFormat format = convert->current_format;
gint channels = convert->current_channels; gint channels = convert->current_channels;
gboolean variable_rate;
if (in->rate != out->rate variable_rate = convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE;
|| convert->flags & GST_AUDIO_CONVERTER_FLAG_VARIABLE_RATE) {
if (in->rate != out->rate || variable_rate) {
method = GET_OPT_RESAMPLER_METHOD (convert); method = GET_OPT_RESAMPLER_METHOD (convert);
flags = 0; flags = 0;
if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED) if (convert->current_layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED)
flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED; flags |= GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED;
if (variable_rate)
flags |= GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE;
convert->resampler = convert->resampler =
gst_audio_resampler_new (method, flags, format, channels, in->rate, gst_audio_resampler_new (method, flags, format, channels, in->rate,

View file

@ -69,6 +69,7 @@ struct _GstAudioResampler
GstAudioResamplerFlags flags; GstAudioResamplerFlags flags;
GstAudioFormat format; GstAudioFormat format;
GstStructure *options; GstStructure *options;
gint format_index;
gint channels; gint channels;
gint in_rate; gint in_rate;
gint out_rate; gint out_rate;
@ -354,9 +355,6 @@ make_taps (GstAudioResampler * resampler,
get_kaiser_tap (x + i, resampler->n_taps, get_kaiser_tap (x + i, resampler->n_taps,
resampler->cutoff, resampler->kaiser_beta); resampler->cutoff, resampler->kaiser_beta);
break; break;
default:
break;
} }
return weight; return weight;
} }
@ -1146,40 +1144,9 @@ alloc_cache_mem (GstAudioResampler * resampler, gint bps, gint n_taps,
static void static void
setup_functions (GstAudioResampler * resampler) setup_functions (GstAudioResampler * resampler)
{ {
gboolean non_interleaved;
gint index, fidx; gint index, fidx;
non_interleaved = index = resampler->format_index;
(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED);
/* we resample each channel separately */
resampler->blocks = resampler->channels;
resampler->inc = 1;
resampler->ostride = non_interleaved ? 1 : resampler->channels;
switch (resampler->format) {
case GST_AUDIO_FORMAT_S16:
GST_DEBUG ("using S16 functions");
index = 0;
break;
case GST_AUDIO_FORMAT_S32:
GST_DEBUG ("using S32 functions");
index = 1;
break;
case GST_AUDIO_FORMAT_F32:
GST_DEBUG ("using F32 functions");
index = 2;
break;
case GST_AUDIO_FORMAT_F64:
GST_DEBUG ("using F64 functions");
index = 3;
break;
default:
g_assert_not_reached ();
break;
}
resampler->deinterleave = deinterleave_funcs[index];
resampler->convert_taps = convert_taps_funcs[index];
switch (resampler->filter_interpolation) { switch (resampler->filter_interpolation) {
default: default:
@ -1266,10 +1233,6 @@ resampler_calculate_taps (GstAudioResampler * resampler)
GET_OPT_FILTER_MODE_THRESHOLD (resampler->options); GET_OPT_FILTER_MODE_THRESHOLD (resampler->options);
filter_interpolation = GET_OPT_FILTER_INTERPOLATION (resampler->options); filter_interpolation = GET_OPT_FILTER_INTERPOLATION (resampler->options);
/* interpolated table but no interpolation given, assume default */
if (resampler->filter_mode != GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
filter_interpolation == GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE)
filter_interpolation = DEFAULT_OPT_FILTER_INTERPOLATION;
} else { } else {
resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL; resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
filter_interpolation = GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE; filter_interpolation = GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE;
@ -1299,7 +1262,6 @@ resampler_calculate_taps (GstAudioResampler * resampler)
oversample = 1; oversample = 1;
} }
resampler->oversample = oversample; resampler->oversample = oversample;
resampler->filter_interpolation = filter_interpolation;
n_taps = resampler->n_taps; n_taps = resampler->n_taps;
bps = resampler->bps; bps = resampler->bps;
@ -1308,7 +1270,8 @@ resampler_calculate_taps (GstAudioResampler * resampler)
oversample); oversample);
if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO) { if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO) {
if (out_rate <= oversample) { if (out_rate <= oversample
&& !(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE)) {
/* don't interpolate if we need to calculate at least the same amount /* don't interpolate if we need to calculate at least the same amount
* of filter coefficients than the full table case */ * of filter coefficients than the full table case */
resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL; resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_FULL;
@ -1319,6 +1282,12 @@ resampler_calculate_taps (GstAudioResampler * resampler)
resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED; resampler->filter_mode = GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED;
} }
} }
/* interpolated table but no interpolation given, assume default */
if (resampler->filter_mode != GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
filter_interpolation == GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE)
filter_interpolation = DEFAULT_OPT_FILTER_INTERPOLATION;
resampler->filter_interpolation = filter_interpolation;
if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_FULL && if (resampler->filter_mode == GST_AUDIO_RESAMPLER_FILTER_MODE_FULL &&
resampler->method != GST_AUDIO_RESAMPLER_METHOD_NEAREST) { resampler->method != GST_AUDIO_RESAMPLER_METHOD_NEAREST) {
@ -1327,8 +1296,6 @@ resampler_calculate_taps (GstAudioResampler * resampler)
alloc_cache_mem (resampler, bps, n_taps, out_rate); alloc_cache_mem (resampler, bps, n_taps, out_rate);
} }
setup_functions (resampler);
if (resampler->filter_interpolation != if (resampler->filter_interpolation !=
GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE) { GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_NONE) {
gint i, isize; gint i, isize;
@ -1358,6 +1325,7 @@ resampler_calculate_taps (GstAudioResampler * resampler)
resampler->convert_taps (tmp_taps, taps, weight, n_taps); resampler->convert_taps (tmp_taps, taps, weight, n_taps);
} }
} }
setup_functions (resampler);
} }
#define PRINT_TAPS(type,print) \ #define PRINT_TAPS(type,print) \
@ -1499,13 +1467,19 @@ gst_audio_resampler_new (GstAudioResamplerMethod method,
GstAudioFormat format, gint channels, GstAudioFormat format, gint channels,
gint in_rate, gint out_rate, GstStructure * options) gint in_rate, gint out_rate, GstStructure * options)
{ {
gboolean non_interleaved;
GstAudioResampler *resampler; GstAudioResampler *resampler;
const GstAudioFormatInfo *info; const GstAudioFormatInfo *info;
GstStructure *def_options = NULL; GstStructure *def_options = NULL;
g_return_val_if_fail (channels > 0, FALSE); g_return_val_if_fail (method >= GST_AUDIO_RESAMPLER_METHOD_NEAREST
g_return_val_if_fail (in_rate > 0, FALSE); && method <= GST_AUDIO_RESAMPLER_METHOD_KAISER, NULL);
g_return_val_if_fail (out_rate > 0, FALSE); g_return_val_if_fail (format == GST_AUDIO_FORMAT_S16 ||
format == GST_AUDIO_FORMAT_S32 || format == GST_AUDIO_FORMAT_F32 ||
format == GST_AUDIO_FORMAT_F64, NULL);
g_return_val_if_fail (channels > 0, NULL);
g_return_val_if_fail (in_rate > 0, NULL);
g_return_val_if_fail (out_rate > 0, NULL);
audio_resampler_init (); audio_resampler_init ();
@ -1515,10 +1489,38 @@ gst_audio_resampler_new (GstAudioResamplerMethod method,
resampler->format = format; resampler->format = format;
resampler->channels = channels; resampler->channels = channels;
switch (format) {
case GST_AUDIO_FORMAT_S16:
resampler->format_index = 0;
break;
case GST_AUDIO_FORMAT_S32:
resampler->format_index = 1;
break;
case GST_AUDIO_FORMAT_F32:
resampler->format_index = 2;
break;
case GST_AUDIO_FORMAT_F64:
resampler->format_index = 3;
break;
default:
g_assert_not_reached ();
break;
}
info = gst_audio_format_get_info (format); info = gst_audio_format_get_info (format);
resampler->bps = GST_AUDIO_FORMAT_INFO_WIDTH (info) / 8; resampler->bps = GST_AUDIO_FORMAT_INFO_WIDTH (info) / 8;
resampler->sbuf = g_malloc0 (sizeof (gpointer) * channels); resampler->sbuf = g_malloc0 (sizeof (gpointer) * channels);
non_interleaved =
(resampler->flags & GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED);
/* we resample each channel separately */
resampler->blocks = resampler->channels;
resampler->inc = 1;
resampler->ostride = non_interleaved ? 1 : resampler->channels;
resampler->deinterleave = deinterleave_funcs[resampler->format_index];
resampler->convert_taps = convert_taps_funcs[resampler->format_index];
GST_DEBUG ("method %d, bps %d, channels %d", method, resampler->bps, GST_DEBUG ("method %d, bps %d, channels %d", method, resampler->bps,
resampler->channels); resampler->channels);

View file

@ -82,7 +82,8 @@ typedef struct _GstAudioResampler GstAudioResampler;
/** /**
* GstAudioResamplerFilterMode: * GstAudioResamplerFilterMode:
* @GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED: Use interpolated filter tables. This * @GST_AUDIO_RESAMPLER_FILTER_MODE_INTERPOLATED: Use interpolated filter tables. This
* uses less memory but more CPU and is slightly less accurate. * uses less memory but more CPU and is slightly less accurate but it allows for more
* efficient variable rate resampling with gst_audio_resampler_update().
* @GST_AUDIO_RESAMPLER_FILTER_MODE_FULL: Use full filter table. This uses more memory * @GST_AUDIO_RESAMPLER_FILTER_MODE_FULL: Use full filter table. This uses more memory
* but less CPU. * but less CPU.
* @GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO: Automatically choose between interpolated * @GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO: Automatically choose between interpolated
@ -132,7 +133,7 @@ typedef enum {
* *
* GST_TYPE_AUDIO_RESAMPLER_INTERPOLATION: how the filter coeficients should be * GST_TYPE_AUDIO_RESAMPLER_INTERPOLATION: how the filter coeficients should be
* interpolated. * interpolated.
* GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_LINEAR is default. * GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC is default.
*/ */
#define GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION "GstAudioResampler.filter-interpolation" #define GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION "GstAudioResampler.filter-interpolation"
/** /**
@ -148,7 +149,7 @@ typedef enum {
* *
* G_TYPE_DOUBLE: The maximum allowed phase error when switching sample * G_TYPE_DOUBLE: The maximum allowed phase error when switching sample
* rates. * rates.
* 0.05 is the default. * 0.1 is the default.
*/ */
#define GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR "GstAudioResampler.max-phase-error" #define GST_AUDIO_RESAMPLER_OPT_MAX_PHASE_ERROR "GstAudioResampler.max-phase-error"
@ -180,12 +181,16 @@ typedef enum {
* @GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED: samples are non-interleaved. an array * @GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED: samples are non-interleaved. an array
* of blocks of samples, one for each channel, should be passed to the resample * of blocks of samples, one for each channel, should be passed to the resample
* function. * function.
* @GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE: optimize for dynamic updates of the sample
* rates with gst_audio_resampler_update(). This will select an interpolating filter
* when #GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO is configured.
* *
* Different resampler flags. * Different resampler flags.
*/ */
typedef enum { typedef enum {
GST_AUDIO_RESAMPLER_FLAG_NONE = (0), GST_AUDIO_RESAMPLER_FLAG_NONE = (0),
GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED = (1 << 0), GST_AUDIO_RESAMPLER_FLAG_NON_INTERLEAVED = (1 << 0),
GST_AUDIO_RESAMPLER_FLAG_VARIABLE_RATE = (1 << 1),
} GstAudioResamplerFlags; } GstAudioResamplerFlags;
#define GST_AUDIO_RESAMPLER_QUALITY_MIN 0 #define GST_AUDIO_RESAMPLER_QUALITY_MIN 0