audio-resampler: improve filter construction

Remove some unused variables from the inner product functions.
Make filter coefficients by interpolating if required.
Rename some fields.
Try hard to not recalculate filters when just chaging the rate.
Add more proprties to audioresample.
This commit is contained in:
Wim Taymans 2016-02-15 18:06:19 +01:00
parent 0f3ff9177f
commit 524ea147cc
5 changed files with 533 additions and 294 deletions

View file

@ -337,15 +337,14 @@ gst_audio_converter_update_config (GstAudioConverter * convert,
convert->in.rate = in_rate;
convert->out.rate = out_rate;
if (convert->resampler)
gst_audio_resampler_update (convert->resampler, in_rate, out_rate, config);
if (config) {
gst_structure_foreach (config, copy_config, convert);
gst_structure_free (config);
}
if (convert->resampler)
gst_audio_resampler_update (convert->resampler, in_rate, out_rate,
convert->config);
return TRUE;
}

View file

@ -22,7 +22,7 @@
static inline void
inner_product_gfloat_none_1_sse (gfloat * o, const gfloat * a,
const gfloat * b, gint len, const gfloat * icoeff, gint oversample)
const gfloat * b, gint len, const gfloat * icoeff)
{
gint i = 0;
__m128 sum = _mm_setzero_ps ();
@ -42,12 +42,13 @@ inner_product_gfloat_none_1_sse (gfloat * o, const gfloat * a,
static inline void
inner_product_gfloat_linear_1_sse (gfloat * o, const gfloat * a,
const gfloat * b, gint len, const gfloat * icoeff, gint oversample)
const gfloat * b, gint len, const gfloat * icoeff)
{
gint i = 0;
__m128 sum = _mm_setzero_ps (), t;
__m128 sum, t;
__m128 f = _mm_loadu_ps(icoeff);
sum = _mm_setzero_ps ();
for (; i < len; i += 4) {
t = _mm_loadu_ps (a + i);
sum = _mm_add_ps (sum, _mm_mul_ps (_mm_unpacklo_ps (t, t),
@ -63,7 +64,7 @@ inner_product_gfloat_linear_1_sse (gfloat * o, const gfloat * a,
static inline void
inner_product_gfloat_cubic_1_sse (gfloat * o, const gfloat * a,
const gfloat * b, gint len, const gfloat * icoeff, gint oversample)
const gfloat * b, gint len, const gfloat * icoeff)
{
gint i = 0;
__m128 sum = _mm_setzero_ps ();
@ -83,7 +84,7 @@ inner_product_gfloat_cubic_1_sse (gfloat * o, const gfloat * a,
static inline void
inner_product_gfloat_none_2_sse (gfloat * o, const gfloat * a,
const gfloat * b, gint len, const gfloat * icoeff, gint oversample)
const gfloat * b, gint len, const gfloat * icoeff)
{
gint i = 0;
__m128 sum = _mm_setzero_ps (), t;
@ -121,7 +122,7 @@ MAKE_RESAMPLE_FUNC (gfloat, none, 2, sse);
static inline void
inner_product_gint16_none_1_sse2 (gint16 * o, const gint16 * a,
const gint16 * b, gint len, const gint16 * icoeff, gint oversample)
const gint16 * b, gint len, const gint16 * icoeff)
{
gint i = 0;
__m128i sum, ta, tb;
@ -149,7 +150,7 @@ inner_product_gint16_none_1_sse2 (gint16 * o, const gint16 * a,
static inline void
inner_product_gint16_linear_1_sse2 (gint16 * o, const gint16 * a,
const gint16 * b, gint len, const gint16 * icoeff, gint oversample)
const gint16 * b, gint len, const gint16 * icoeff)
{
gint i = 0;
__m128i sum, t, ta, tb;
@ -193,7 +194,7 @@ inner_product_gint16_linear_1_sse2 (gint16 * o, const gint16 * a,
static inline void
inner_product_gint16_cubic_1_sse2 (gint16 * o, const gint16 * a,
const gint16 * b, gint len, const gint16 * icoeff, gint oversample)
const gint16 * b, gint len, const gint16 * icoeff)
{
gint i = 0;
__m128i sum, ta, tb;
@ -230,7 +231,7 @@ inner_product_gint16_cubic_1_sse2 (gint16 * o, const gint16 * a,
static inline void
inner_product_gdouble_none_1_sse2 (gdouble * o, const gdouble * a,
const gdouble * b, gint len, const gdouble * icoeff, gint oversample)
const gdouble * b, gint len, const gdouble * icoeff)
{
gint i = 0;
__m128d sum = _mm_setzero_pd ();
@ -255,7 +256,7 @@ inner_product_gdouble_none_1_sse2 (gdouble * o, const gdouble * a,
static inline void
inner_product_gdouble_linear_1_sse2 (gdouble * o, const gdouble * a,
const gdouble * b, gint len, const gdouble * icoeff, gint oversample)
const gdouble * b, gint len, const gdouble * icoeff)
{
gint i = 0;
__m128d sum = _mm_setzero_pd ();
@ -274,7 +275,7 @@ inner_product_gdouble_linear_1_sse2 (gdouble * o, const gdouble * a,
static inline void
inner_product_gdouble_cubic_1_sse2 (gdouble * o, const gdouble * a,
const gdouble * b, gint len, const gdouble * icoeff, gint oversample)
const gdouble * b, gint len, const gdouble * icoeff)
{
gint i = 0;
__m128d sum1 = _mm_setzero_pd (), t;
@ -300,7 +301,7 @@ inner_product_gdouble_cubic_1_sse2 (gdouble * o, const gdouble * a,
static inline void
inner_product_gint16_none_2_sse2 (gint16 * o, const gint16 * a,
const gint16 * b, gint len, const gint16 * icoeff, gint oversample)
const gint16 * b, gint len, const gint16 * icoeff)
{
gint i = 0;
__m128i sum, ta, tb, t1;
@ -332,7 +333,7 @@ inner_product_gint16_none_2_sse2 (gint16 * o, const gint16 * a,
static inline void
inner_product_gdouble_none_2_sse2 (gdouble * o, const gdouble * a,
const gdouble * b, gint len, const gdouble * icoeff, gint oversample)
const gdouble * b, gint len, const gdouble * icoeff)
{
gint i = 0;
__m128d sum = _mm_setzero_pd (), t;
@ -368,6 +369,45 @@ MAKE_RESAMPLE_FUNC (gdouble, cubic, 1, sse2);
MAKE_RESAMPLE_FUNC (gint16, none, 2, sse2);
MAKE_RESAMPLE_FUNC (gdouble, none, 2, sse2);
static void
interpolate_gdouble_linear_sse2 (gdouble * o, const gdouble * a,
gint len, const gdouble * icoeff)
{
gint i = 0;
__m128d f = _mm_loadu_pd (icoeff), t1, t2;
for (; i < len; i += 2) {
t1 = _mm_mul_pd (_mm_load_pd (a + 2*i + 0), f);
t1 = _mm_add_sd (t1, _mm_unpackhi_pd (t1, t1));
t2 = _mm_mul_pd (_mm_load_pd (a + 2*i + 2), f);
t2 = _mm_add_sd (t2, _mm_unpackhi_pd (t2, t2));
_mm_store_pd (o + i, _mm_unpacklo_pd (t1, t2));
}
}
static void
interpolate_gdouble_cubic_sse2 (gdouble * o, const gdouble * a,
gint len, const gdouble * icoeff)
{
gint i = 0;
__m128d t1, t2;
__m128d f1 = _mm_loadu_pd (icoeff);
__m128d f2 = _mm_loadu_pd (icoeff+2);
for (; i < len; i += 2) {
t1 = _mm_add_pd (_mm_mul_pd (_mm_load_pd (a + 4*i + 0), f1),
_mm_mul_pd (_mm_load_pd (a + 4*i + 2), f2));
t1 = _mm_add_sd (t1, _mm_unpackhi_pd (t1, t1));
t2 = _mm_add_pd (_mm_mul_pd (_mm_load_pd (a + 4*i + 4), f1),
_mm_mul_pd (_mm_load_pd (a + 4*i + 6), f2));
t2 = _mm_add_sd (t2, _mm_unpackhi_pd (t2, t2));
_mm_store_pd (o + i, _mm_unpacklo_pd (t1, t2));
}
}
#endif
#if defined (HAVE_SMMINTRIN_H) && defined(__SSE4_1__)
@ -375,7 +415,7 @@ MAKE_RESAMPLE_FUNC (gdouble, none, 2, sse2);
static inline void
inner_product_gint32_none_1_sse41 (gint32 * o, const gint32 * a,
const gint32 * b, gint len, const gint32 * icoeff, gint oversample)
const gint32 * b, gint len, const gint32 * icoeff)
{
gint i = 0;
__m128i sum, ta, tb;
@ -413,7 +453,7 @@ inner_product_gint32_none_1_sse41 (gint32 * o, const gint32 * a,
static inline void
inner_product_gint32_linear_1_sse41 (gint32 * o, const gint32 * a,
const gint32 * b, gint len, const gint32 * icoeff, gint oversample)
const gint32 * b, gint len, const gint32 * icoeff)
{
gint i = 0;
gint64 res;
@ -457,7 +497,7 @@ inner_product_gint32_linear_1_sse41 (gint32 * o, const gint32 * a,
static inline void
inner_product_gint32_cubic_1_sse41 (gint32 * o, const gint32 * a,
const gint32 * b, gint len, const gint32 * icoeff, gint oversample)
const gint32 * b, gint len, const gint32 * icoeff)
{
gint i = 0;
gint64 res;
@ -537,6 +577,9 @@ audio_resampler_check_x86 (const gchar *option)
resample_gint16_none_2 = resample_gint16_none_2_sse2;
resample_gfloat_none_2 = resample_gfloat_none_2_sse;
resample_gdouble_none_2 = resample_gdouble_none_2_sse2;
interpolate_gdouble_linear = interpolate_gdouble_linear_sse2;
interpolate_gdouble_cubic = interpolate_gdouble_cubic_sse2;
#else
GST_DEBUG ("SSE2 optimisations not enabled");
#endif

File diff suppressed because it is too large Load diff

View file

@ -74,15 +74,19 @@ GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
#undef USE_SPEEX
#define DEFAULT_QUALITY GST_AUDIO_RESAMPLER_QUALITY_DEFAULT
#define DEFAULT_RESAMPLE_METHOD GST_AUDIO_RESAMPLER_METHOD_KAISER
#define DEFAULT_SINC_FILTER_MODE GST_AUDIO_RESAMPLER_FILTER_MODE_AUTO
#define DEFAULT_SINC_FILTER_AUTO_THRESHOLD (1*1048576)
#define DEFAULT_SINC_FILTER_INTERPOLATION GST_AUDIO_RESAMPLER_FILTER_INTERPOLATION_CUBIC
enum
{
PROP_0,
PROP_QUALITY,
PROP_RESAMPLE_METHOD,
PROP_SINC_FILTER_MODE,
PROP_SINC_FILTER_AUTO_THRESHOLD
PROP_SINC_FILTER_AUTO_THRESHOLD,
PROP_SINC_FILTER_INTERPOLATION
};
#define SUPPORTED_CAPS \
@ -150,6 +154,11 @@ gst_audio_resample_class_init (GstAudioResampleClass * klass)
DEFAULT_QUALITY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_RESAMPLE_METHOD,
g_param_spec_enum ("resample-method", "Resample method to use",
"What resample method to use",
GST_TYPE_AUDIO_RESAMPLER_METHOD,
DEFAULT_RESAMPLE_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_SINC_FILTER_MODE,
g_param_spec_enum ("sinc-filter-mode", "Sinc filter table mode",
"What sinc filter table mode to use",
@ -164,6 +173,14 @@ gst_audio_resample_class_init (GstAudioResampleClass * klass)
"Memory usage threshold to use if sinc filter mode is AUTO, given in bytes",
0, G_MAXUINT, DEFAULT_SINC_FILTER_AUTO_THRESHOLD,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class,
PROP_SINC_FILTER_INTERPOLATION,
g_param_spec_enum ("sinc-filter-interpolation",
"Sinc filter interpolation",
"How to interpolate the sinc filter table",
GST_TYPE_AUDIO_RESAMPLER_FILTER_INTERPOLATION,
DEFAULT_SINC_FILTER_INTERPOLATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_static_pad_template (gstelement_class,
&gst_audio_resample_src_template);
@ -205,10 +222,11 @@ gst_audio_resample_init (GstAudioResample * resample)
{
GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
resample->method = GST_AUDIO_RESAMPLER_METHOD_KAISER;
resample->method = DEFAULT_RESAMPLE_METHOD;
resample->quality = DEFAULT_QUALITY;
resample->sinc_filter_mode = DEFAULT_SINC_FILTER_MODE;
resample->sinc_filter_auto_threshold = DEFAULT_SINC_FILTER_AUTO_THRESHOLD;
resample->sinc_filter_interpolation = DEFAULT_SINC_FILTER_INTERPOLATION;
gst_base_transform_set_gap_aware (trans, TRUE);
gst_pad_set_query_function (trans->srcpad, gst_audio_resample_query);
@ -357,7 +375,10 @@ make_options (GstAudioResample * resample, GstAudioInfo * in,
resample->method,
GST_AUDIO_RESAMPLER_OPT_FILTER_MODE, GST_TYPE_AUDIO_RESAMPLER_FILTER_MODE,
resample->sinc_filter_mode, GST_AUDIO_RESAMPLER_OPT_FILTER_MODE_THRESHOLD,
G_TYPE_UINT, resample->sinc_filter_auto_threshold, NULL);
G_TYPE_UINT, resample->sinc_filter_auto_threshold,
GST_AUDIO_RESAMPLER_OPT_FILTER_INTERPOLATION,
GST_TYPE_AUDIO_RESAMPLER_FILTER_INTERPOLATION,
resample->sinc_filter_interpolation, NULL);
return options;
}
@ -999,6 +1020,10 @@ gst_audio_resample_set_property (GObject * object, guint prop_id,
GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
gst_audio_resample_update_state (resample, NULL, NULL);
break;
case PROP_RESAMPLE_METHOD:
resample->method = g_value_get_enum (value);
gst_audio_resample_update_state (resample, NULL, NULL);
break;
case PROP_SINC_FILTER_MODE:
/* FIXME locking! */
resample->sinc_filter_mode = g_value_get_enum (value);
@ -1009,6 +1034,11 @@ gst_audio_resample_set_property (GObject * object, guint prop_id,
resample->sinc_filter_auto_threshold = g_value_get_uint (value);
gst_audio_resample_update_state (resample, NULL, NULL);
break;
case PROP_SINC_FILTER_INTERPOLATION:
/* FIXME locking! */
resample->sinc_filter_interpolation = g_value_get_enum (value);
gst_audio_resample_update_state (resample, NULL, NULL);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1027,12 +1057,18 @@ gst_audio_resample_get_property (GObject * object, guint prop_id,
case PROP_QUALITY:
g_value_set_int (value, resample->quality);
break;
case PROP_RESAMPLE_METHOD:
g_value_set_enum (value, resample->method);
break;
case PROP_SINC_FILTER_MODE:
g_value_set_enum (value, resample->sinc_filter_mode);
break;
case PROP_SINC_FILTER_AUTO_THRESHOLD:
g_value_set_uint (value, resample->sinc_filter_auto_threshold);
break;
case PROP_SINC_FILTER_INTERPOLATION:
g_value_set_enum (value, resample->sinc_filter_interpolation);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -67,6 +67,7 @@ struct _GstAudioResample {
gint quality;
GstAudioResamplerFilterMode sinc_filter_mode;
guint32 sinc_filter_auto_threshold;
GstAudioResamplerFilterInterpolation sinc_filter_interpolation;
/* state */
GstAudioInfo in;