From 6d7debb0bb854c792e1dce6a6cd3a6a0c806055c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 5 Sep 2007 21:20:12 +0000 Subject: [PATCH] gst/volume/gstvolume.c: Correctly clamp float/double samples in the [-1.0,1.0] range to prevent weird effects. Original commit message from CVS: * gst/volume/gstvolume.c: (volume_choose_func), (volume_process_double), (volume_process_double_clamp), (volume_process_float_clamp): Correctly clamp float/double samples in the [-1.0,1.0] range to prevent weird effects. * tests/check/elements/volume.c: (GST_START_TEST), (volume_suite): Add unit tests for all samples types that had none before. --- ChangeLog | 10 + gst/volume/gstvolume.c | 53 +- tests/check/elements/volume.c | 1048 ++++++++++++++++++++++++++++++++- 3 files changed, 1089 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 744e5421e2..ef6e941b13 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2007-09-05 Sebastian Dröge + + * gst/volume/gstvolume.c: (volume_choose_func), + (volume_process_double), (volume_process_double_clamp), + (volume_process_float_clamp): + Correctly clamp float/double samples in the [-1.0,1.0] range to + prevent weird effects. + * tests/check/elements/volume.c: (GST_START_TEST), (volume_suite): + Add unit tests for all samples types that had none before. + 2007-09-05 Tim-Philipp Müller * gst-libs/gst/rtp/gstrtpbuffer.c: diff --git a/gst/volume/gstvolume.c b/gst/volume/gstvolume.c index ca08c57573..4747581fa4 100644 --- a/gst/volume/gstvolume.c +++ b/gst/volume/gstvolume.c @@ -214,8 +214,12 @@ static gboolean volume_set_caps (GstBaseTransform * base, GstCaps * incaps, static void volume_process_double (GstVolume * this, gpointer bytes, guint n_bytes); +static void volume_process_double_clamp (GstVolume * this, gpointer bytes, + guint n_bytes); static void volume_process_float (GstVolume * this, gpointer bytes, guint n_bytes); +static void volume_process_float_clamp (GstVolume * this, gpointer bytes, + guint n_bytes); static void volume_process_int32 (GstVolume * this, gpointer bytes, guint n_bytes); static void volume_process_int32_clamp (GstVolume * this, gpointer bytes, @@ -284,10 +288,22 @@ volume_choose_func (GstVolume * this) case GST_VOLUME_FORMAT_FLOAT: switch (this->width) { case 32: - this->process = volume_process_float; + /* only clamp if the gain is greater than 1.0 + * FIXME: real_vol_f can change while processing the buffer! + */ + if (this->real_vol_f > 1.0) + this->process = volume_process_float_clamp; + else + this->process = volume_process_float; break; case 64: - this->process = volume_process_double; + /* only clamp if the gain is greater than 1.0 + * FIXME: real_vol_f can change while processing the buffer! + */ + if (this->real_vol_f > 1.0) + this->process = volume_process_double_clamp; + else + this->process = volume_process_double; break; } break; @@ -481,22 +497,34 @@ gst_volume_init (GstVolume * this, GstVolumeClass * g_class) /* NOTE: although it might be tempting to have volume_process_mute() which uses * memset(bytes, 0, nbytes) for the vol=0 case, this has the downside that - * unmuting would unly take place after processing a buffer. + * unmuting would only take place after processing a buffer. */ static void volume_process_double (GstVolume * this, gpointer bytes, guint n_bytes) { gdouble *data = (gdouble *) bytes; - guint i, num_samples; - - num_samples = n_bytes / sizeof (gdouble); + guint i, num_samples = n_bytes / sizeof (gdouble); for (i = 0; i < num_samples; i++) { *data++ *= this->real_vol_f; } } +static void +volume_process_double_clamp (GstVolume * this, gpointer bytes, guint n_bytes) +{ + gdouble *data = (gdouble *) bytes; + guint i, num_samples = n_bytes / sizeof (gdouble); + gdouble tmp; + + for (i = 0; i < num_samples; i++) { + tmp = *data * this->real_vol_f; + *data++ = CLAMP (tmp, -1.0, 1.0); + } + +} + static void volume_process_float (GstVolume * this, gpointer bytes, guint n_bytes) { @@ -515,6 +543,19 @@ volume_process_float (GstVolume * this, gpointer bytes, guint n_bytes) oil_scalarmultiply_f32_ns (data, data, &this->real_vol_f, num_samples); } +static void +volume_process_float_clamp (GstVolume * this, gpointer bytes, guint n_bytes) +{ + gfloat *data = (gfloat *) bytes; + guint i, num_samples = n_bytes / sizeof (gfloat); + gfloat tmp; + + for (i = 0; i < num_samples; i++) { + tmp = *data * this->real_vol_f; + *data++ = CLAMP (tmp, -1.0, 1.0); + } +} + static void volume_process_int32 (GstVolume * this, gpointer bytes, guint n_bytes) { diff --git a/tests/check/elements/volume.c b/tests/check/elements/volume.c index 3cc14cdc76..c0ca64cb6a 100644 --- a/tests/check/elements/volume.c +++ b/tests/check/elements/volume.c @@ -39,11 +39,25 @@ GstPad *mysrcpad, *mysinkpad; "channels = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \ "endianness = (int) BYTE_ORDER, " \ - "width = (int) 16, " \ - "depth = (int) 16, " \ + "width = (int) { 8, 16, 24, 32 }, " \ + "depth = (int) { 8, 16, 24, 32 }, " \ + "signed = (bool) TRUE; " \ + "audio/x-raw-float, " \ + "channels = (int) [ 1, MAX ], " \ + "rate = (int) [ 1, MAX ], " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) { 32, 64 }" \ + +#define VOLUME_CAPS_STRING_S8 \ + "audio/x-raw-int, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 8, " \ + "depth = (int) 8, " \ "signed = (bool) TRUE" -#define VOLUME_CAPS_STRING \ +#define VOLUME_CAPS_STRING_S16 \ "audio/x-raw-int, " \ "channels = (int) 1, " \ "rate = (int) 44100, " \ @@ -52,6 +66,38 @@ GstPad *mysrcpad, *mysinkpad; "depth = (int) 16, " \ "signed = (bool) TRUE" +#define VOLUME_CAPS_STRING_S24 \ + "audio/x-raw-int, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 24, " \ + "depth = (int) 24, " \ + "signed = (bool) TRUE" + +#define VOLUME_CAPS_STRING_S32 \ + "audio/x-raw-int, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 32, " \ + "depth = (int) 32, " \ + "signed = (bool) TRUE" + +#define VOLUME_CAPS_STRING_F32 \ + "audio/x-raw-float, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 32" + +#define VOLUME_CAPS_STRING_F64 \ + "audio/x-raw-float, " \ + "channels = (int) 1, " \ + "rate = (int) 44100, " \ + "endianness = (int) BYTE_ORDER, " \ + "width = (int) 64" + #define VOLUME_WRONG_CAPS_STRING \ "audio/x-raw-int, " \ "channels = (int) 1, " \ @@ -104,7 +150,185 @@ cleanup_volume (GstElement * volume) gst_check_teardown_element (volume); } -GST_START_TEST (test_unity) +GST_START_TEST (test_unity_s8) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gint8 in[2] = { 64, -16 }; + gint8 *res; + + volume = setup_volume (); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (2); + memcpy (GST_BUFFER_DATA (inbuffer), in, 2); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint8 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_half_s8) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint8 in[2] = { 64, -16 }; + gint8 out[2] = { 32, -8 }; + gint8 *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 0.5, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (2); + memcpy (GST_BUFFER_DATA (inbuffer), in, 2); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint8 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0], + res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 2) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_double_s8) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint8 in[2] = { 64, -16 }; + gint8 out[2] = { 127, -32 }; /* notice the clamped sample */ + gint8 *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 2.0, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (2); + memcpy (GST_BUFFER_DATA (inbuffer), in, 2); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint8 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0], + res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 2) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_mute_s8) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint8 in[2] = { 64, -16 }; + gint8 out[2] = { 0, 0 }; + gint8 *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "mute", TRUE, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (2); + memcpy (GST_BUFFER_DATA (inbuffer), in, 2); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint8 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0], + res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 2) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_unity_s16) { GstElement *volume; GstBuffer *inbuffer, *outbuffer; @@ -119,7 +343,7 @@ GST_START_TEST (test_unity) inbuffer = gst_buffer_new_and_alloc (4); memcpy (GST_BUFFER_DATA (inbuffer), in, 4); - caps = gst_caps_from_string (VOLUME_CAPS_STRING); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16); gst_buffer_set_caps (inbuffer, caps); gst_caps_unref (caps); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -141,7 +365,7 @@ GST_START_TEST (test_unity) GST_END_TEST; -GST_START_TEST (test_half) +GST_START_TEST (test_half_s16) { GstElement *volume; GstBuffer *inbuffer; @@ -160,7 +384,7 @@ GST_START_TEST (test_half) inbuffer = gst_buffer_new_and_alloc (4); memcpy (GST_BUFFER_DATA (inbuffer), in, 4); fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0); - caps = gst_caps_from_string (VOLUME_CAPS_STRING); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16); gst_buffer_set_caps (inbuffer, caps); gst_caps_unref (caps); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -188,7 +412,7 @@ GST_START_TEST (test_half) GST_END_TEST; -GST_START_TEST (test_double) +GST_START_TEST (test_double_s16) { GstElement *volume; GstBuffer *inbuffer; @@ -207,7 +431,7 @@ GST_START_TEST (test_double) inbuffer = gst_buffer_new_and_alloc (4); memcpy (GST_BUFFER_DATA (inbuffer), in, 4); fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0); - caps = gst_caps_from_string (VOLUME_CAPS_STRING); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16); gst_buffer_set_caps (inbuffer, caps); gst_caps_unref (caps); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -236,7 +460,7 @@ GST_START_TEST (test_double) GST_END_TEST; -GST_START_TEST (test_mute) +GST_START_TEST (test_mute_s16) { GstElement *volume; GstBuffer *inbuffer; @@ -255,7 +479,7 @@ GST_START_TEST (test_mute) inbuffer = gst_buffer_new_and_alloc (4); memcpy (GST_BUFFER_DATA (inbuffer), in, 4); fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0); - caps = gst_caps_from_string (VOLUME_CAPS_STRING); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16); gst_buffer_set_caps (inbuffer, caps); gst_caps_unref (caps); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -283,6 +507,778 @@ GST_START_TEST (test_mute) GST_END_TEST; +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) +#define get_unaligned_i24(_x) ( (((guint8*)_x)[0]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[2]) << 16) ) +#define write_unaligned_u24(_x,samp) do { (((guint8*)_x)[0]) = samp & 0xFF; (((guint8*)_x)[1]) = (samp >> 8) & 0xFF; (((guint8*)_x)[2]) = (samp >> 16) & 0xFF; } while (0) +#else /* BIG ENDIAN */ +#define get_unaligned_i24(_x) ( (((guint8*)_x)[2]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[0]) << 16) ) +#define write_unaligned_u24(_x,samp) do { (((guint8*)_x)[0]) = (samp >> 16) & 0xFF; (((guint8*)_x)[1]) = (samp >> 8) & 0xFF; (((guint8*)_x)[2]) = samp & 0xFF; } while (0) +#endif + +GST_START_TEST (test_unity_s24) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gint32 in_32[2] = { 4194304, -4096 }; + guint8 in[6]; + guint8 *res; + gint32 res_32[2]; + + + write_unaligned_u24 (in, in_32[0]); + write_unaligned_u24 (in + 3, in_32[1]); + + volume = setup_volume (); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (6); + memcpy (GST_BUFFER_DATA (inbuffer), in, 6); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = GST_BUFFER_DATA (outbuffer); + + res_32[0] = get_unaligned_i24 (res); + res_32[1] = get_unaligned_i24 ((res + 3)); + + GST_INFO ("expected %+5d %+5d real %+5d %+5d", in_32[0], in_32[1], res_32[0], + res_32[1]); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_half_s24) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint32 in_32[2] = { 4194304, -4096 }; + guint8 in[6]; + guint8 *res; + gint32 res_32[2]; + gint32 out_32[2] = { 2097152, -2048 }; + + write_unaligned_u24 (in, in_32[0]); + write_unaligned_u24 (in + 3, in_32[1]); + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 0.5, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (6); + memcpy (GST_BUFFER_DATA (inbuffer), in, 6); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = GST_BUFFER_DATA (outbuffer); + + res_32[0] = get_unaligned_i24 (res); + res_32[1] = get_unaligned_i24 ((res + 3)); + + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out_32[0], out_32[1], + res_32[0], res_32[1]); + fail_unless (memcmp (res_32, out_32, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_double_s24) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint32 in_32[2] = { 4194304, -4096 }; + guint8 in[6]; + guint8 *res; + gint32 res_32[2]; + gint32 out_32[2] = { 8388607, -8192 }; /* notice the clamped sample */ + + write_unaligned_u24 (in, in_32[0]); + write_unaligned_u24 (in + 3, in_32[1]); + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 2.0, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (6); + memcpy (GST_BUFFER_DATA (inbuffer), in, 6); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = GST_BUFFER_DATA (outbuffer); + + res_32[0] = get_unaligned_i24 (res); + res_32[1] = get_unaligned_i24 ((res + 3)); + + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out_32[0], out_32[1], + res_32[0], res_32[1]); + fail_unless (memcmp (res_32, out_32, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + + +GST_START_TEST (test_mute_s24) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint32 in_32[2] = { 4194304, -4096 }; + guint8 in[6]; + guint8 *res; + gint32 res_32[2]; + gint32 out_32[2] = { 0, 0 }; /* notice the clamped sample */ + + write_unaligned_u24 (in, in_32[0]); + write_unaligned_u24 (in + 3, in_32[1]); + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "mute", TRUE, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (6); + memcpy (GST_BUFFER_DATA (inbuffer), in, 6); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + + res = GST_BUFFER_DATA (outbuffer); + + res_32[0] = get_unaligned_i24 (res); + res_32[1] = get_unaligned_i24 ((res + 3)); + + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out_32[0], out_32[1], + res_32[0], res_32[1]); + fail_unless (memcmp (res_32, out_32, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_unity_s32) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gint32 in[2] = { 1073741824, -65536 }; + gint32 *res; + + volume = setup_volume (); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint32 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_half_s32) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint32 in[2] = { 1073741824, -65536 }; + gint32 out[2] = { 536870912, -32768 }; + gint32 *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 0.5, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint32 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0], + res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_double_s32) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint32 in[2] = { 1073741824, -65536 }; + gint32 out[2] = { 2147483647, -131072 }; /* notice the clamped sample */ + gint32 *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 2.0, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint32 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0], + res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + + +GST_START_TEST (test_mute_s32) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gint32 in[2] = { 1073741824, -65536 }; + gint32 out[2] = { 0, 0 }; + gint32 *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "mute", TRUE, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gint32 *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0], + res[1]); + fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 8) == 0); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_unity_f32) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gfloat in[2] = { 0.75, -0.25 }; + gfloat *res; + + volume = setup_volume (); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gfloat *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", in[0], in[1], res[0], + res[1]); + fail_unless_equals_float (res[0], in[0]); + fail_unless_equals_float (res[1], in[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_half_f32) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gfloat in[2] = { 0.75, -0.25 }; + gfloat out[2] = { 0.375, -0.125 }; + gfloat *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 0.5, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gfloat *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1], + res[0], res[1]); + fail_unless_equals_float (res[0], out[0]); + fail_unless_equals_float (res[1], out[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_double_f32) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gfloat in[2] = { 0.75, -0.25 }; + gfloat out[2] = { 1.0, -0.5 }; /* notice the clamped sample */ + gfloat *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 2.0, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gfloat *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1], + res[0], res[1]); + fail_unless_equals_float (res[0], out[0]); + fail_unless_equals_float (res[1], out[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + + +GST_START_TEST (test_mute_f32) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gfloat in[2] = { 0.75, -0.25 }; + gfloat out[2] = { 0, 0 }; + gfloat *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "mute", TRUE, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (8); + memcpy (GST_BUFFER_DATA (inbuffer), in, 8); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gfloat *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1], + res[0], res[1]); + fail_unless_equals_float (res[0], out[0]); + fail_unless_equals_float (res[1], out[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_unity_f64) +{ + GstElement *volume; + GstBuffer *inbuffer, *outbuffer; + GstCaps *caps; + gdouble in[2] = { 0.75, -0.25 }; + gdouble *res; + + volume = setup_volume (); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (16); + memcpy (GST_BUFFER_DATA (inbuffer), in, 16); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gdouble *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", in[0], in[1], res[0], + res[1]); + fail_unless_equals_float (res[0], in[0]); + fail_unless_equals_float (res[1], in[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_half_f64) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gdouble in[2] = { 0.75, -0.25 }; + gdouble out[2] = { 0.375, -0.125 }; + gdouble *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 0.5, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (16); + memcpy (GST_BUFFER_DATA (inbuffer), in, 16); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 16) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gdouble *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1], + res[0], res[1]); + fail_unless_equals_float (res[0], out[0]); + fail_unless_equals_float (res[1], out[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + +GST_START_TEST (test_double_f64) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gdouble in[2] = { 0.75, -0.25 }; + gdouble out[2] = { 1.0, -0.5 }; /* notice the clamped sample */ + gdouble *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "volume", 2.0, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (16); + memcpy (GST_BUFFER_DATA (inbuffer), in, 16); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 16) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gdouble *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1], + res[0], res[1]); + fail_unless_equals_float (res[0], out[0]); + fail_unless_equals_float (res[1], out[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; + + +GST_START_TEST (test_mute_f64) +{ + GstElement *volume; + GstBuffer *inbuffer; + GstBuffer *outbuffer; + GstCaps *caps; + gdouble in[2] = { 0.75, -0.25 }; + gdouble out[2] = { 0, 0 }; + gdouble *res; + + volume = setup_volume (); + g_object_set (G_OBJECT (volume), "mute", TRUE, NULL); + fail_unless (gst_element_set_state (volume, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); + + inbuffer = gst_buffer_new_and_alloc (16); + memcpy (GST_BUFFER_DATA (inbuffer), in, 16); + fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 16) == 0); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64); + gst_buffer_set_caps (inbuffer, caps); + gst_caps_unref (caps); + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + /* FIXME: reffing the inbuffer should make the transformation not be + * inplace + gst_buffer_ref (inbuffer); + */ + + /* pushing gives away my reference ... */ + fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + /* ... but it ends up being modified inplace and + * collected on the global buffer list */ + ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); + fail_unless_equals_int (g_list_length (buffers), 1); + fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); + fail_unless (inbuffer == outbuffer); + res = (gdouble *) GST_BUFFER_DATA (outbuffer); + GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1], + res[0], res[1]); + fail_unless_equals_float (res[0], out[0]); + fail_unless_equals_float (res[1], out[1]); + + /* cleanup */ + cleanup_volume (volume); +} + +GST_END_TEST; GST_START_TEST (test_wrong_caps) { @@ -348,7 +1344,7 @@ GST_START_TEST (test_passthrough) inbuffer = gst_buffer_new_and_alloc (4); memcpy (GST_BUFFER_DATA (inbuffer), in, 4); - caps = gst_caps_from_string (VOLUME_CAPS_STRING); + caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16); gst_buffer_set_caps (inbuffer, caps); gst_caps_unref (caps); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); @@ -414,10 +1410,30 @@ volume_suite (void) TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); - tcase_add_test (tc_chain, test_unity); - tcase_add_test (tc_chain, test_half); - tcase_add_test (tc_chain, test_double); - tcase_add_test (tc_chain, test_mute); + tcase_add_test (tc_chain, test_unity_s8); + tcase_add_test (tc_chain, test_half_s8); + tcase_add_test (tc_chain, test_double_s8); + tcase_add_test (tc_chain, test_mute_s8); + tcase_add_test (tc_chain, test_unity_s16); + tcase_add_test (tc_chain, test_half_s16); + tcase_add_test (tc_chain, test_double_s16); + tcase_add_test (tc_chain, test_mute_s16); + tcase_add_test (tc_chain, test_unity_s24); + tcase_add_test (tc_chain, test_half_s24); + tcase_add_test (tc_chain, test_double_s24); + tcase_add_test (tc_chain, test_mute_s24); + tcase_add_test (tc_chain, test_unity_s32); + tcase_add_test (tc_chain, test_half_s32); + tcase_add_test (tc_chain, test_double_s32); + tcase_add_test (tc_chain, test_mute_s32); + tcase_add_test (tc_chain, test_unity_f32); + tcase_add_test (tc_chain, test_half_f32); + tcase_add_test (tc_chain, test_double_f32); + tcase_add_test (tc_chain, test_mute_f32); + tcase_add_test (tc_chain, test_unity_f64); + tcase_add_test (tc_chain, test_half_f64); + tcase_add_test (tc_chain, test_double_f64); + tcase_add_test (tc_chain, test_mute_f64); tcase_add_test (tc_chain, test_wrong_caps); tcase_add_test (tc_chain, test_passthrough); tcase_add_test (tc_chain, test_controller_usability);