From 4681a87ccecd4a8ce645534e8a207064b8beffff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 30 Oct 2008 13:44:41 +0000 Subject: [PATCH] gst/speexresample/: Add support for int8, int24 and int32 input by converting internally to/from int16 or double. Original commit message from CVS: * gst/speexresample/gstspeexresample.c: (gst_speex_resample_stop), (gst_speex_resample_get_funcs), (gst_speex_resample_transform_size), (gst_speex_resample_convert_buffer), (gst_speex_resample_push_drain), (gst_speex_resample_process): * gst/speexresample/gstspeexresample.h: * gst/speexresample/speex_resampler_wrapper.h: Add support for int8, int24 and int32 input by converting internally to/from int16 or double. --- gst/speexresample/gstspeexresample.c | 200 +++++++++++++++++++- gst/speexresample/gstspeexresample.h | 6 + gst/speexresample/speex_resampler_wrapper.h | 10 +- 3 files changed, 204 insertions(+), 12 deletions(-) diff --git a/gst/speexresample/gstspeexresample.c b/gst/speexresample/gstspeexresample.c index e0dee7dbdc..186400caed 100644 --- a/gst/speexresample/gstspeexresample.c +++ b/gst/speexresample/gstspeexresample.c @@ -61,12 +61,33 @@ GST_STATIC_CAPS ( \ "channels = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ "width = (int) { 32, 64 }; " \ + "audio/x-raw-int, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 32, " \ + "depth = (int) 32, " \ + "signed = (boolean) true; " \ + "audio/x-raw-int, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 24, " \ + "depth = (int) 24, " \ + "signed = (boolean) true; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ "channels = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ "width = (int) 16, " \ "depth = (int) 16, " \ + "signed = (boolean) true; " \ + "audio/x-raw-int, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 8, " \ + "depth = (int) 8, " \ "signed = (boolean) true" \ ) @@ -202,6 +223,14 @@ gst_speex_resample_stop (GstBaseTransform * base) resample->funcs = NULL; + g_free (resample->tmp_in); + resample->tmp_in = NULL; + resample->tmp_in_size = 0; + + g_free (resample->tmp_out); + resample->tmp_out = NULL; + resample->tmp_out_size = 0; + gst_caps_replace (&resample->sinkcaps, NULL); gst_caps_replace (&resample->srccaps, NULL); @@ -268,11 +297,11 @@ gst_speex_resample_get_funcs (gint width, gboolean fp) { const SpeexResampleFuncs *funcs = NULL; - if (width == 16 && !fp) + if ((width == 8 || width == 16) && !fp) funcs = &int_funcs; else if (width == 32 && fp) funcs = &float_funcs; - else if (width == 64 && fp) + else if ((width == 64 && fp) || ((width == 32 || width == 24) && !fp)) funcs = &double_funcs; else g_assert_not_reached (); @@ -474,7 +503,6 @@ gst_speex_resample_transform_size (GstBaseTransform * base, /* asked to convert size of an incoming buffer */ size /= fac; - //*othersize = (size * ratio_den + (ratio_num >> 1)) / ratio_num; *othersize = (size * ratio_den + ratio_num - 1) / ratio_num; *othersize *= fac; size *= fac; @@ -483,7 +511,6 @@ gst_speex_resample_transform_size (GstBaseTransform * base, /* asked to convert size of an outgoing buffer */ size /= fac; - //*othersize = (size * ratio_num + (ratio_den >> 1)) / ratio_den; *othersize = (size * ratio_num + ratio_den - 1) / ratio_den; *othersize *= fac; size *= fac; @@ -527,6 +554,105 @@ gst_speex_resample_set_caps (GstBaseTransform * base, GstCaps * incaps, return TRUE; } +#define GST_MAXINT24 (8388607) +#define GST_MININT24 (-8388608) + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) +#define GST_READ_UINT24 GST_READ_UINT24_LE +#define GST_WRITE_UINT24 GST_WRITE_UINT24_LE +#else +#define GST_READ_UINT24 GST_READ_UINT24_BE +#define GST_WRITE_UINT24 GST_WRITE_UINT24_BE +#endif + +static void +gst_speex_resample_convert_buffer (GstSpeexResample * resample, + const guint8 * in, guint8 * out, guint len, gboolean inverse) +{ + if (inverse) { + if (resample->width == 8 && !resample->fp) { + gint8 *o = (gint8 *) out; + gint16 *i = (gint16 *) in; + gint32 tmp; + + while (len) { + tmp = *i + (G_MAXINT8 >> 1); + *o = CLAMP (tmp >> 8, G_MININT8, G_MAXINT8); + o++; + i++; + len--; + } + } else if (resample->width == 24 && !resample->fp) { + guint8 *o = (guint8 *) out; + gdouble *i = (gdouble *) in; + gdouble tmp; + + while (len) { + tmp = *i; + GST_WRITE_UINT24 (o, CLAMP (tmp * GST_MAXINT24 + 0.5, GST_MININT24, + GST_MAXINT24)); + o += 3; + i++; + len--; + } + } else if (resample->width == 32 && !resample->fp) { + gint32 *o = (gint32 *) out; + gdouble *i = (gdouble *) in; + gdouble tmp; + + while (len) { + tmp = *i; + *o = CLAMP (tmp * G_MAXINT32 + 0.5, G_MININT32, G_MAXINT32); + o++; + i++; + len--; + } + } + } else { + if (resample->width == 8 && !resample->fp) { + gint8 *i = (gint8 *) in; + gint16 *o = (gint16 *) out; + gint32 tmp; + + while (len) { + tmp = *i; + *o = tmp << 8; + o++; + i++; + len--; + } + } else if (resample->width == 24 && !resample->fp) { + guint8 *i = (guint8 *) in; + gdouble *o = (gdouble *) out; + gdouble tmp; + guint32 tmp2; + + while (len) { + tmp2 = GST_READ_UINT24 (i); + if (tmp2 & 0x00800000) + tmp2 |= 0xff000000; + tmp = (gint32) tmp2; + *o = tmp / GST_MAXINT24; + o++; + i += 3; + len--; + } + } else if (resample->width == 32 && !resample->fp) { + gint32 *i = (gint32 *) in; + gdouble *o = (gdouble *) out; + gdouble tmp; + + while (len) { + tmp = *i; + *o = tmp / G_MAXINT32; + o++; + i++; + len--; + } + } + } +} + static void gst_speex_resample_push_drain (GstSpeexResample * resample) { @@ -537,16 +663,31 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) guint out_len, out_processed; gint err; guint num, den, len; + guint8 *outtmp = NULL; + gboolean need_convert = FALSE; if (!resample->state) return; + need_convert = (resample->funcs->width != resample->width); + resample->funcs->get_ratio (resample->state, &num, &den); out_len = resample->funcs->get_input_latency (resample->state); - out_len = out_processed = (out_len * den + (num >> 1)) / num; + out_len = out_processed = (out_len * den + num - 1) / num; outsize = (resample->width / 8) * out_len * resample->channels; + if (need_convert) { + guint outsize_tmp = + (resample->funcs->width / 8) * out_len * resample->channels; + if (outsize_tmp <= resample->tmp_out_size) { + outtmp = resample->tmp_out; + } else { + resample->tmp_out_size = outsize_tmp; + resample->tmp_out = outtmp = g_realloc (resample->tmp_out, outsize_tmp); + } + } + res = gst_pad_alloc_buffer_and_set_caps (trans->srcpad, GST_BUFFER_OFFSET_NONE, outsize, GST_PAD_CAPS (trans->srcpad), &buf); @@ -561,7 +702,8 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) err = resample->funcs->process (resample->state, - NULL, &len, (guint8 *) GST_BUFFER_DATA (buf), &out_processed); + NULL, &len, (need_convert) ? outtmp : GST_BUFFER_DATA (buf), + &out_processed); if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) { GST_WARNING_OBJECT (resample, "Failed to process drain: %s", @@ -576,6 +718,10 @@ gst_speex_resample_push_drain (GstSpeexResample * resample) return; } + if (need_convert) + gst_speex_resample_convert_buffer (resample, outtmp, GST_BUFFER_DATA (buf), + out_processed, TRUE); + GST_BUFFER_DURATION (buf) = GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); GST_BUFFER_SIZE (buf) = @@ -670,6 +816,8 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, guint32 in_len, in_processed; guint32 out_len, out_processed; gint err = RESAMPLER_ERR_SUCCESS; + guint8 *in_tmp, *out_tmp; + gboolean need_convert = (resample->funcs->width != resample->width); in_len = GST_BUFFER_SIZE (inbuf) / resample->channels; out_len = GST_BUFFER_SIZE (outbuf) / resample->channels; @@ -680,9 +828,38 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, in_processed = in_len; out_processed = out_len; - err = resample->funcs->process (resample->state, - (const guint8 *) GST_BUFFER_DATA (inbuf), &in_processed, - (guint8 *) GST_BUFFER_DATA (outbuf), &out_processed); + if (need_convert) { + guint in_size_tmp = + in_len * resample->channels * (resample->funcs->width / 8); + guint out_size_tmp = + out_len * resample->channels * (resample->funcs->width / 8); + + if (in_size_tmp <= resample->tmp_in_size) { + in_tmp = resample->tmp_in; + } else { + resample->tmp_in = in_tmp = g_realloc (resample->tmp_in, in_size_tmp); + resample->tmp_in_size = in_size_tmp; + } + + gst_speex_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf), + in_tmp, in_len, FALSE); + + if (out_size_tmp <= resample->tmp_out_size) { + out_tmp = resample->tmp_out; + } else { + resample->tmp_out = out_tmp = g_realloc (resample->tmp_out, out_size_tmp); + resample->tmp_out_size = out_size_tmp; + } + } + + if (need_convert) { + err = resample->funcs->process (resample->state, + in_tmp, &in_processed, out_tmp, &out_processed); + } else { + err = resample->funcs->process (resample->state, + (const guint8 *) GST_BUFFER_DATA (inbuf), &in_processed, + (guint8 *) GST_BUFFER_DATA (outbuf), &out_processed); + } if (G_UNLIKELY (in_len != in_processed)) GST_WARNING_OBJECT (resample, "Converted %d of %d input samples", @@ -712,6 +889,11 @@ gst_speex_resample_process (GstSpeexResample * resample, GstBuffer * inbuf, resample->funcs->strerror (err)); return GST_FLOW_ERROR; } else { + + if (need_convert) + gst_speex_resample_convert_buffer (resample, out_tmp, + GST_BUFFER_DATA (outbuf), out_processed, TRUE); + GST_BUFFER_DURATION (outbuf) = GST_FRAMES_TO_CLOCK_TIME (out_processed, resample->outrate); GST_BUFFER_SIZE (outbuf) = diff --git a/gst/speexresample/gstspeexresample.h b/gst/speexresample/gstspeexresample.h index 25be5ca991..1cf2196c8d 100644 --- a/gst/speexresample/gstspeexresample.h +++ b/gst/speexresample/gstspeexresample.h @@ -69,6 +69,12 @@ struct _GstSpeexResample { gint width; gboolean fp; + guint8 *tmp_in; + guint tmp_in_size; + + guint8 *tmp_out; + guint tmp_out_size; + SpeexResamplerState *state; const SpeexResampleFuncs *funcs; }; diff --git a/gst/speexresample/speex_resampler_wrapper.h b/gst/speexresample/speex_resampler_wrapper.h index 6f3fba9b80..c5a214de77 100644 --- a/gst/speexresample/speex_resampler_wrapper.h +++ b/gst/speexresample/speex_resampler_wrapper.h @@ -56,6 +56,7 @@ typedef struct { int (*reset_mem) (SpeexResamplerState * st); int (*skip_zeros) (SpeexResamplerState * st); const char * (*strerror) (gint err); + unsigned int width; } SpeexResampleFuncs; SpeexResamplerState *resample_float_resampler_init (guint32 nb_channels, @@ -87,7 +88,8 @@ static const SpeexResampleFuncs float_funcs = resample_float_resampler_set_quality, resample_float_resampler_reset_mem, resample_float_resampler_skip_zeros, - resample_float_resampler_strerror + resample_float_resampler_strerror, + 16 }; SpeexResamplerState *resample_double_resampler_init (guint32 nb_channels, @@ -119,7 +121,8 @@ static const SpeexResampleFuncs double_funcs = resample_double_resampler_set_quality, resample_double_resampler_reset_mem, resample_double_resampler_skip_zeros, - resample_double_resampler_strerror + resample_double_resampler_strerror, + 64 }; SpeexResamplerState *resample_int_resampler_init (guint32 nb_channels, @@ -151,7 +154,8 @@ static const SpeexResampleFuncs int_funcs = resample_int_resampler_set_quality, resample_int_resampler_reset_mem, resample_int_resampler_skip_zeros, - resample_int_resampler_strerror + resample_int_resampler_strerror, + 32 }; #endif /* __SPEEX_RESAMPLER_WRAPPER_H__ */