mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-03 01:02:19 +00:00
spectrum: use function pointers for data readers
Don't check the format for each sample frame to read. We can make that decission in _setup already. This is still not ideal as we call the function per frame. Ideally we determine how many samples we can copy and have a loop in the input reader. As an alternative we might also consider to use the fft variants for the various formats and not convert to float for all cases - we would still need to mix or deinterleave though.
This commit is contained in:
parent
2738917852
commit
b792b100e2
2 changed files with 244 additions and 93 deletions
|
@ -479,10 +479,245 @@ gst_spectrum_stop (GstBaseTransform * trans)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* mixing data readers */
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_float (const guint8 * data, guint channels, gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
gfloat *in = (gfloat *) data;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i];
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_double (const guint8 * data, guint channels, gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
gdouble *in = (gdouble *) data;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i];
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_int32 (const guint8 * data, guint channels, gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
gint32 *in = (gint32 *) data;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i] * 2 + 1;
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_int32_max (const guint8 * data, guint channels,
|
||||
gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
gint32 *in = (gint32 *) data;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i] / max_value;
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_int24 (const guint8 * data, guint channels, gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
gint32 value = GST_READ_UINT24_BE (data);
|
||||
#else
|
||||
gint32 value = GST_READ_UINT24_LE (data);
|
||||
#endif
|
||||
if (value & 0x00800000)
|
||||
value |= 0xff000000;
|
||||
v += value * 2 + 1;
|
||||
}
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_int24_max (const guint8 * data, guint channels,
|
||||
gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
gint32 value = GST_READ_UINT24_BE (data);
|
||||
#else
|
||||
gint32 value = GST_READ_UINT24_LE (data);
|
||||
#endif
|
||||
if (value & 0x00800000)
|
||||
value |= 0xff000000;
|
||||
v += value / max_value;
|
||||
}
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_int16 (const guint8 * data, guint channels, gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
gint16 *in = (gint16 *) data;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i] * 2 + 1;
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_mixed_int16_max (const guint8 * data, guint channels,
|
||||
gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
gint16 *in = (gint16 *) data;
|
||||
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i] / max_value;
|
||||
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
/* non mixing data readers */
|
||||
|
||||
static gfloat
|
||||
input_data_float (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
return ((gfloat *) data)[0];
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_double (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
return (gfloat) ((gdouble *) data)[0];
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_int32 (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
return ((gint32 *) data)[0] * 2 + 1;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_int32_max (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
return ((gint32 *) data)[0] / max_value;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_int24 (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
gint32 in = GST_READ_UINT24_BE (data);
|
||||
#else
|
||||
gint32 in = GST_READ_UINT24_LE (data);
|
||||
#endif
|
||||
if (in & 0x00800000)
|
||||
in |= 0xff000000;
|
||||
return in * 2 + 1;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_int24_max (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
gint32 in = GST_READ_UINT24_BE (data);
|
||||
#else
|
||||
gint32 in = GST_READ_UINT24_LE (data);
|
||||
#endif
|
||||
if (in & 0x00800000)
|
||||
in |= 0xff000000;
|
||||
return in / max_value;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_int16 (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
return ((gint16 *) data)[0] * 2 + 1;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
input_data_int16_max (const guint8 * data, gfloat max_value)
|
||||
{
|
||||
return ((gint16 *) data)[0] / max_value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_spectrum_setup (GstAudioFilter * base, GstRingBufferSpec * format)
|
||||
{
|
||||
GstSpectrum *spectrum = GST_SPECTRUM (base);
|
||||
guint width = format->width / 8;
|
||||
gboolean is_float = (format->type == GST_BUFTYPE_FLOAT);
|
||||
/* max_value will be 0 when depth is 1,
|
||||
* interpret -1 and 0 as -1 and +1 if that's the case. */
|
||||
gfloat max_value = (1UL << (format->depth - 1)) - 1;
|
||||
|
||||
spectrum->input_data_mixed = NULL;
|
||||
spectrum->input_data = NULL;
|
||||
|
||||
if (is_float) {
|
||||
if (width == 4) {
|
||||
spectrum->input_data_mixed = input_data_mixed_float;
|
||||
spectrum->input_data = input_data_float;
|
||||
} else if (width == 8) {
|
||||
spectrum->input_data_mixed = input_data_mixed_double;
|
||||
spectrum->input_data = input_data_double;
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else {
|
||||
if (width == 4) {
|
||||
if (max_value) {
|
||||
spectrum->input_data_mixed = input_data_mixed_int32_max;
|
||||
spectrum->input_data = input_data_int32_max;
|
||||
} else {
|
||||
spectrum->input_data_mixed = input_data_mixed_int32;
|
||||
spectrum->input_data = input_data_int32;
|
||||
}
|
||||
} else if (width == 3) {
|
||||
if (max_value) {
|
||||
spectrum->input_data_mixed = input_data_mixed_int24_max;
|
||||
spectrum->input_data = input_data_int24_max;
|
||||
} else {
|
||||
spectrum->input_data_mixed = input_data_mixed_int24;
|
||||
spectrum->input_data = input_data_int24;
|
||||
}
|
||||
} else if (width == 2) {
|
||||
if (max_value) {
|
||||
spectrum->input_data_mixed = input_data_mixed_int16_max;
|
||||
spectrum->input_data = input_data_int16_max;
|
||||
} else {
|
||||
spectrum->input_data_mixed = input_data_mixed_int16;
|
||||
spectrum->input_data = input_data_int16;
|
||||
}
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
gst_spectrum_reset_state (spectrum);
|
||||
return TRUE;
|
||||
|
@ -601,94 +836,6 @@ gst_spectrum_message_new (GstSpectrum * spectrum, GstClockTime timestamp,
|
|||
return gst_message_new_element (GST_OBJECT (spectrum), s);
|
||||
}
|
||||
|
||||
/* FIXME: have dedicated read function pointers for each format */
|
||||
static gfloat
|
||||
gst_spectrum_input_data_mixed (const guint8 * data, gfloat is_float,
|
||||
guint width, guint channels, gfloat max_value)
|
||||
{
|
||||
guint i;
|
||||
gfloat v = 0.0;
|
||||
|
||||
if (is_float) {
|
||||
if (width == 4) {
|
||||
gfloat *in = (gfloat *) data;
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i];
|
||||
} else if (width == 8) {
|
||||
gdouble *in = (gdouble *) data;
|
||||
for (i = 0; i < channels; i++)
|
||||
v += in[i];
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else {
|
||||
if (width == 4) {
|
||||
gint32 *in = (gint32 *) data;
|
||||
/* max_value will be 0 when depth is 1,
|
||||
* interpret -1 and 0 as -1 and +1 if that's the case. */
|
||||
for (i = 0; i < channels; i++)
|
||||
v += max_value ? in[i] / max_value : in[i] * 2 + 1;
|
||||
} else if (width == 3) {
|
||||
for (i = 0; i < channels; i++) {
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
gint32 value = GST_READ_UINT24_BE (data);
|
||||
#else
|
||||
gint32 value = GST_READ_UINT24_LE (data);
|
||||
#endif
|
||||
if (value & 0x00800000)
|
||||
value |= 0xff000000;
|
||||
v += max_value ? value / max_value : value * 2 + 1;
|
||||
}
|
||||
} else if (width == 2) {
|
||||
gint16 *in = (gint16 *) data;
|
||||
for (i = 0; i < channels; i++)
|
||||
v += max_value ? in[i] / max_value : in[i] * 2 + 1;
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
return v / channels;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
gst_spectrum_input_data (const guint8 * data, gfloat is_float, guint width,
|
||||
gfloat max_value)
|
||||
{
|
||||
gfloat v = 0.0;
|
||||
|
||||
if (is_float) {
|
||||
if (width == 4) {
|
||||
v = ((gfloat *) data)[0];
|
||||
} else if (width == 8) {
|
||||
v = ((gdouble *) data)[0];
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
} else {
|
||||
if (width == 4) {
|
||||
gint32 *in = (gint32 *) data;
|
||||
/* max_value will be 0 when depth is 1,
|
||||
* interpret -1 and 0 as -1 and +1 if that's the case. */
|
||||
v = max_value ? in[0] / max_value : in[0] * 2 + 1;
|
||||
} else if (width == 3) {
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
gint32 in = GST_READ_UINT24_BE (data);
|
||||
#else
|
||||
gint32 in = GST_READ_UINT24_LE (data);
|
||||
#endif
|
||||
if (in & 0x00800000)
|
||||
in |= 0xff000000;
|
||||
v = max_value ? in / max_value : in * 2 + 1;
|
||||
} else if (width == 2) {
|
||||
gint16 *in = (gint16 *) data;
|
||||
v = max_value ? in[0] / max_value : in[0] * 2 + 1;
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_spectrum_run_fft (GstSpectrum * spectrum, GstSpectrumChannel * cd,
|
||||
guint input_pos)
|
||||
|
@ -770,7 +917,6 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
guint rate = format->rate;
|
||||
guint channels = format->channels;
|
||||
guint width = format->width / 8;
|
||||
gboolean is_float = (format->type == GST_BUFTYPE_FLOAT);
|
||||
gfloat max_value = (1UL << (format->depth - 1)) - 1;
|
||||
guint bands = spectrum->bands;
|
||||
guint nfft = 2 * bands - 2;
|
||||
|
@ -818,8 +964,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
|
||||
while (size >= width * channels) {
|
||||
/* Move the mixdown of current frame into our ringbuffer */
|
||||
input[input_pos] = gst_spectrum_input_data_mixed (data, is_float, width,
|
||||
channels, max_value);
|
||||
input[input_pos] = spectrum->input_data_mixed (data, channels, max_value);
|
||||
|
||||
data += width * channels;
|
||||
size -= width * channels;
|
||||
|
@ -883,8 +1028,7 @@ gst_spectrum_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
|
|||
cd = &spectrum->channel_data[c];
|
||||
input = cd->input;
|
||||
/* Move the current frames into our ringbuffers */
|
||||
input[input_pos] = gst_spectrum_input_data (data, is_float, width,
|
||||
max_value);
|
||||
input[input_pos] = spectrum->input_data (data, max_value);
|
||||
data += width;
|
||||
}
|
||||
size -= width * channels;
|
||||
|
|
|
@ -37,6 +37,10 @@ typedef struct _GstSpectrum GstSpectrum;
|
|||
typedef struct _GstSpectrumClass GstSpectrumClass;
|
||||
typedef struct _GstSpectrumChannel GstSpectrumChannel;
|
||||
|
||||
typedef gfloat (*GstSpectrumInputDataMixed)(const guint8 * data, guint channels,
|
||||
gfloat max_value);
|
||||
typedef gfloat (*GstSpectrumInputData)(const guint8 * data, gfloat max_value);
|
||||
|
||||
struct _GstSpectrumChannel
|
||||
{
|
||||
gfloat *input;
|
||||
|
@ -72,6 +76,9 @@ struct _GstSpectrum
|
|||
guint input_pos;
|
||||
guint64 error_per_interval;
|
||||
guint64 accumulated_error;
|
||||
|
||||
GstSpectrumInputDataMixed input_data_mixed;
|
||||
GstSpectrumInputData input_data;
|
||||
};
|
||||
|
||||
struct _GstSpectrumClass
|
||||
|
|
Loading…
Reference in a new issue