diff --git a/ChangeLog b/ChangeLog index eb0413dac8..907e94e4e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2008-05-14 Sebastian Dröge + + * gst/interleave/Makefile.am: + * gst/interleave/deinterleave.h: + * gst/interleave/interleave.h: + * gst/interleave/plugin.h: + Split definitions into separate header files for better documentation + generation. + + * gst/interleave/deinterleave.c: (gst_deinterleave_base_init), + (gst_deinterleave_class_init), (gst_deinterleave_sink_setcaps), + (gst_deinterleave_process): + Don't use alloca, allow caps changes as long as the number of channels + does not change, don't use g_warning, return NOT_NEGOTIATED as early + as possible and some other cleanup. + + * gst/interleave/interleave.c: (gst_interleave_base_init), + (gst_interleave_class_init): + Do some random cleanup. + + * tests/check/Makefile.am: + * tests/check/elements/deinterleave.c: (GST_START_TEST), + (deinterleave_chain_func), (deinterleave_pad_added), + (deinterleave_suite): + Add unit tests for the deinterleave element. + 2008-05-13 Wim Taymans Patch by: Sjoerd Simons diff --git a/gst/interleave/Makefile.am b/gst/interleave/Makefile.am index 9a09cdbcf9..62e7f3e3ce 100644 --- a/gst/interleave/Makefile.am +++ b/gst/interleave/Makefile.am @@ -6,4 +6,4 @@ libgstinterleave_la_CFLAGS = $(GST_CFLAGS) libgstinterleave_la_LIBADD = $(GST_LIBS) libgstinterleave_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = plugin.h +noinst_HEADERS = plugin.h interleave.h deinterleave.h diff --git a/gst/interleave/deinterleave.c b/gst/interleave/deinterleave.c index f2e7977791..743eb9f5a6 100644 --- a/gst/interleave/deinterleave.c +++ b/gst/interleave/deinterleave.c @@ -3,6 +3,7 @@ * 2000 Wim Taymans * 2005 Wim Taymans * 2007 Andy Wingo + * 2008 Sebastian Dröge * * deinterleave.c: deinterleave samples, based on interleave.c * @@ -22,48 +23,16 @@ * Boston, MA 02111-1307, USA. */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif #include - - -#define GST_TYPE_DEINTERLEAVE (gst_deinterleave_get_type()) -#define GST_DEINTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleave)) -#define GST_DEINTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLEAVE,GstDeinterleaveClass)) -#define GST_DEINTERLEAVE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleaveClass)) -#define GST_IS_DEINTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLEAVE)) -#define GST_IS_DEINTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLEAVE)) - -typedef struct _GstDeinterleave GstDeinterleave; -typedef struct _GstDeinterleaveClass GstDeinterleaveClass; - - -struct _GstDeinterleave -{ - GstElement element; - - /*< private > */ - GList *srcpads; - GstCaps *sinkcaps; - gint channels; - - GstPad *sink; -}; - -struct _GstDeinterleaveClass -{ - GstElementClass parent_class; -}; - +#include "deinterleave.h" GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug); #define GST_CAT_DEFAULT gst_deinterleave_debug - static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC, GST_PAD_SOMETIMES, @@ -85,26 +54,18 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_BOILERPLATE (GstDeinterleave, gst_deinterleave, GstElement, GST_TYPE_ELEMENT); - static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer); static gboolean gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps); static gboolean gst_deinterleave_sink_activate_push (GstPad * pad, gboolean active); - -static const GstElementDetails details = -GST_ELEMENT_DETAILS ("Audio deinterleaver", - "Filter/Converter/Audio", - "Splits one interleaved multichannel audio stream into many mono audio streams", - "Andy Wingo , " "Iain "); - static void gst_deinterleave_base_init (gpointer g_class) { - GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "interleave", 0, - "interleave element"); - - gst_element_class_set_details (g_class, &details); + gst_element_class_set_details_simple (g_class, "Audio deinterleaver", + "Filter/Converter/Audio", + "Splits one interleaved multichannel audio stream into many mono audio streams", + "Andy Wingo , " "Iain "); gst_element_class_add_pad_template (g_class, gst_static_pad_template_get (&sink_template)); @@ -115,7 +76,8 @@ gst_deinterleave_base_init (gpointer g_class) static void gst_deinterleave_class_init (GstDeinterleaveClass * klass) { - /* pass */ + GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "deinterleave", 0, + "deinterleave element"); } static void @@ -179,20 +141,47 @@ static gboolean gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps) { GstDeinterleave *self; + GstCaps *srccaps; + GstStructure *s; self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) { - goto cannot_change_caps_dog; + GList *l; + gint new_channels; + + if (!caps) + goto cannot_change_caps; + + s = gst_caps_get_structure (caps, 0); + + /* We allow caps changes as long as the number of channels doesn't change */ + if (!gst_structure_get_int (s, "channels", &new_channels) || + new_channels != self->channels) + goto cannot_change_caps; + + GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps); + gst_caps_replace (&self->sinkcaps, caps); + + /* Set new caps on all srcpads */ + srccaps = gst_caps_copy (caps); + s = gst_caps_get_structure (srccaps, 0); + gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL); + gst_structure_remove_field (s, "channel-positions"); + + for (l = self->srcpads; l; l = l->next) { + GstPad *pad = GST_PAD (l->data); + + if (!gst_pad_set_caps (pad, srccaps)) + goto cannot_change_caps; + } + + gst_caps_unref (srccaps); } else { GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps); gst_caps_replace (&self->sinkcaps, caps); - } - - { - GstCaps *srccaps; - GstStructure *s; + /* Add all srcpads */ srccaps = gst_caps_copy (caps); s = gst_caps_get_structure (srccaps, 0); if (!gst_structure_get_int (s, "channels", &self->channels)) @@ -207,14 +196,15 @@ gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps) return TRUE; -cannot_change_caps_dog: +cannot_change_caps: { + GST_ERROR_OBJECT (self, "can't set new caps: %" GST_PTR_FORMAT, caps); gst_object_unref (self); return FALSE; } no_channels: { - g_warning ("yarr, shiver me timbers"); + GST_ERROR_OBJECT (self, "invalid caps"); gst_object_unref (self); return FALSE; } @@ -225,37 +215,45 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; /* initialized to silence a warning */ GList *srcs; - guint bufsize, i, j, channels, pads_pushed, nframes; + guint bufsize, i, j, channels, pads_pushed, buffers_allocated, nframes; GstBuffer **buffers_out; gfloat *in, *out; channels = self->channels; - buffers_out = g_alloca (sizeof (GstBuffer *) * channels); + buffers_out = g_new0 (GstBuffer *, channels); nframes = GST_BUFFER_SIZE (buf) / channels / sizeof (gfloat); bufsize = nframes * sizeof (gfloat); pads_pushed = 0; + buffers_allocated = 0; - for (i = 0; i < channels; i++) - buffers_out[i] = NULL; - + /* Allocate buffers */ for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) { GstPad *pad = (GstPad *) srcs->data; buffers_out[i] = NULL; - ret = gst_pad_alloc_buffer (pad, -1, bufsize, GST_PAD_CAPS (pad), - &buffers_out[i]); + ret = + gst_pad_alloc_buffer (pad, GST_BUFFER_OFFSET_NONE, bufsize, + GST_PAD_CAPS (pad), &buffers_out[i]); if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) goto alloc_buffer_failed; if (buffers_out[i] && GST_BUFFER_SIZE (buffers_out[i]) != bufsize) goto alloc_buffer_bad_size; - if (buffers_out[i]) + if (buffers_out[i]) { gst_buffer_copy_metadata (buffers_out[i], buf, - GST_BUFFER_COPY_TIMESTAMPS); + GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS); + buffers_allocated++; + } } - /* do the thing */ + /* Return NOT_LINKED if we couldn't allocate any buffers */ + if (!buffers_allocated) { + ret = GST_FLOW_NOT_LINKED; + goto done; + } + + /* deinterleave */ for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) { GstPad *pad = (GstPad *) srcs->data; @@ -263,8 +261,8 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) in += i; /* gfloat * arith */ if (buffers_out[i]) { out = (gfloat *) GST_BUFFER_DATA (buffers_out[i]); - for (j = 0; j < nframes; j++) - out[j] = in[j * channels]; + for (j = 0; j < nframes * channels; j += channels) + *out++ = in[j]; ret = gst_pad_push (pad, buffers_out[i]); buffers_out[i] = NULL; @@ -280,7 +278,9 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) if (!pads_pushed) ret = GST_FLOW_NOT_LINKED; +done: gst_buffer_unref (buf); + g_free (buffers_out); return ret; alloc_buffer_failed: @@ -307,6 +307,7 @@ clean_buffers: gst_buffer_unref (buffers_out[i]); } gst_buffer_unref (buf); + g_free (buffers_out); return ret; } } diff --git a/gst/interleave/deinterleave.h b/gst/interleave/deinterleave.h new file mode 100644 index 0000000000..ee3f8e17ec --- /dev/null +++ b/gst/interleave/deinterleave.h @@ -0,0 +1,65 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2005 Wim Taymans + * 2007 Andy Wingo + * 2008 Sebastian Dröge + * + * deinterleave.c: deinterleave samples, based on interleave.c + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __DEINTERLEAVE_H__ +#define __DEINTERLEAVE_H__ + +G_BEGIN_DECLS + +#include + +#define GST_TYPE_DEINTERLEAVE (gst_deinterleave_get_type()) +#define GST_DEINTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleave)) +#define GST_DEINTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DEINTERLEAVE,GstDeinterleaveClass)) +#define GST_DEINTERLEAVE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleaveClass)) +#define GST_IS_DEINTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DEINTERLEAVE)) +#define GST_IS_DEINTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DEINTERLEAVE)) + +typedef struct _GstDeinterleave GstDeinterleave; +typedef struct _GstDeinterleaveClass GstDeinterleaveClass; + +struct _GstDeinterleave +{ + GstElement element; + + /*< private > */ + GList *srcpads; + GstCaps *sinkcaps; + gint channels; + + GstPad *sink; +}; + +struct _GstDeinterleaveClass +{ + GstElementClass parent_class; +}; + +GType gst_deinterleave_get_type (void); + +G_END_DECLS + +#endif /* __DEINTERLEAVE_H__ */ diff --git a/gst/interleave/interleave.c b/gst/interleave/interleave.c index bce077d7ad..be5b410885 100644 --- a/gst/interleave/interleave.c +++ b/gst/interleave/interleave.c @@ -45,45 +45,11 @@ #endif #include - - -#define GST_TYPE_INTERLEAVE (gst_interleave_get_type()) -#define GST_INTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INTERLEAVE,GstInterleave)) -#define GST_INTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INTERLEAVE,GstInterleaveClass)) -#define GST_INTERLEAVE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_INTERLEAVE,GstInterleaveClass)) -#define GST_IS_INTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INTERLEAVE)) -#define GST_IS_INTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INTERLEAVE)) - - -typedef struct _GstInterleave GstInterleave; -typedef struct _GstInterleaveClass GstInterleaveClass; - - -struct _GstInterleave -{ - GstElement element; - - GstCaps *sinkcaps; - guint channels; - - GstPad *src; - - GstActivateMode mode; - - guint pending_in; -}; - -struct _GstInterleaveClass -{ - GstElementClass parent_class; -}; - +#include "interleave.h" GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug); #define GST_CAT_DEFAULT gst_interleave_debug - static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink%d", GST_PAD_SINK, GST_PAD_REQUEST, @@ -156,20 +122,13 @@ static gboolean gst_interleave_src_setcaps (GstPad * pad, GstCaps * caps); static gboolean gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps); static GstCaps *gst_interleave_src_getcaps (GstPad * pad); - -static const GstElementDetails details = -GST_ELEMENT_DETAILS ("Audio interleaver", - "Filter/Converter/Audio", - "Folds many mono channels into one interleaved audio stream", - "Andy Wingo "); - static void gst_interleave_base_init (gpointer g_class) { - GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0, - "interleave element"); - - gst_element_class_set_details (g_class, &details); + gst_element_class_set_details_simple (g_class, "Audio interleaver", + "Filter/Converter/Audio", + "Folds many mono channels into one interleaved audio stream", + "Andy Wingo "); gst_element_class_add_pad_template (g_class, gst_static_pad_template_get (&sink_template)); @@ -184,6 +143,9 @@ gst_interleave_class_init (GstInterleaveClass * klass) gstelement_class = GST_ELEMENT_CLASS (klass); + GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0, + "interleave element"); + gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR (gst_interleave_request_new_pad); } diff --git a/gst/interleave/interleave.h b/gst/interleave/interleave.h new file mode 100644 index 0000000000..915871eb57 --- /dev/null +++ b/gst/interleave/interleave.h @@ -0,0 +1,66 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * 2005 Wim Taymans + * 2007 Andy Wingo + * + * interleave.c: interleave samples, based on gstsignalprocessor.c + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __INTERLEAVE_H__ +#define __INTERLEAVE_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_INTERLEAVE (gst_interleave_get_type()) +#define GST_INTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INTERLEAVE,GstInterleave)) +#define GST_INTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INTERLEAVE,GstInterleaveClass)) +#define GST_INTERLEAVE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_INTERLEAVE,GstInterleaveClass)) +#define GST_IS_INTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INTERLEAVE)) +#define GST_IS_INTERLEAVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INTERLEAVE)) + +typedef struct _GstInterleave GstInterleave; +typedef struct _GstInterleaveClass GstInterleaveClass; + +struct _GstInterleave +{ + GstElement element; + + /*< private >*/ + GstCaps *sinkcaps; + guint channels; + + GstPad *src; + GstActivateMode mode; + + guint pending_in; +}; + +struct _GstInterleaveClass +{ + GstElementClass parent_class; +}; + +GType gst_interleave_get_type (void); + +G_END_DECLS + +#endif /* __INTERLEAVE_H__ */ diff --git a/gst/interleave/plugin.h b/gst/interleave/plugin.h index bc722bdb6d..3e96a7e115 100644 --- a/gst/interleave/plugin.h +++ b/gst/interleave/plugin.h @@ -25,12 +25,7 @@ #include - -G_BEGIN_DECLS - -GType gst_interleave_get_type (void); -GType gst_deinterleave_get_type (void); - -G_END_DECLS +#include "interleave.h" +#include "deinterleave.h" #endif /* __GST_PLUGIN_INTERLEAVE_H__ */ diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 797a4f4211..2c986a20da 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -73,6 +73,7 @@ check_PROGRAMS = \ $(check_neon) \ $(check_ofa) \ $(check_timidity) \ + elements/deinterleave \ elements/interleave \ elements/rganalysis \ elements/rglimiter \ diff --git a/tests/check/elements/deinterleave.c b/tests/check/elements/deinterleave.c new file mode 100644 index 0000000000..04b6f09286 --- /dev/null +++ b/tests/check/elements/deinterleave.c @@ -0,0 +1,358 @@ +/* GStreamer unit tests for the interleave element + * Copyright (C) 2008 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +GST_START_TEST (test_create_and_unref) +{ + GstElement *deinterleave; + + deinterleave = gst_element_factory_make ("deinterleave", NULL); + fail_unless (deinterleave != NULL); + + gst_element_set_state (deinterleave, GST_STATE_NULL); + gst_object_unref (deinterleave); +} + +GST_END_TEST; + +static GstPad *mysrcpad, **mysinkpads; +static gint nsinkpads; +static GstBus *bus; +static GstElement *deinterleave; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-float, " + "width = (int) 32, " + "channels = (int) 1, " + "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER")); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-float, " + "width = (int) 32, " + "channels = (int) 2, " + "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER")); + +#define CAPS_32khz \ + "audio/x-raw-float, " \ + "width = (int) 32, " \ + "channels = (int) 2, " \ + "rate = (int) 32000, " \ + "endianness = (int) BYTE_ORDER" + +#define CAPS_48khz \ + "audio/x-raw-float, " \ + "width = (int) 32, " \ + "channels = (int) 2, " \ + "rate = (int) 48000, " \ + "endianness = (int) BYTE_ORDER" + +#define CAPS_48khz_3CH \ + "audio/x-raw-float, " \ + "width = (int) 32, " \ + "channels = (int) 3, " \ + "rate = (int) 48000, " \ + "endianness = (int) BYTE_ORDER" + +static GstFlowReturn +deinterleave_chain_func (GstPad * pad, GstBuffer * buffer) +{ + gint i; + gfloat *indata; + + fail_unless (GST_IS_BUFFER (buffer)); + fail_unless_equals_int (GST_BUFFER_SIZE (buffer), 48000 * sizeof (gfloat)); + fail_unless (GST_BUFFER_DATA (buffer) != NULL); + + indata = (gfloat *) GST_BUFFER_DATA (buffer); + + if (strcmp (GST_PAD_NAME (pad), "sink0") == 0) { + for (i = 0; i < 48000; i++) + fail_unless_equals_float (indata[i], -1.0); + } else if (strcmp (GST_PAD_NAME (pad), "sink1") == 0) { + for (i = 0; i < 48000; i++) + fail_unless_equals_float (indata[i], 1.0); + } else { + g_assert_not_reached (); + } + + gst_buffer_unref (buffer); + + return GST_FLOW_OK; +} + +static void +deinterleave_pad_added (GstElement * src, GstPad * pad, gpointer data) +{ + gchar *name; + gint link = GPOINTER_TO_INT (data); + + if (nsinkpads >= link) + return; + + name = g_strdup_printf ("sink%d", nsinkpads); + + mysinkpads[nsinkpads] = + gst_pad_new_from_static_template (&sinktemplate, name); + g_free (name); + fail_if (mysinkpads[nsinkpads] == NULL); + + gst_pad_set_chain_function (mysinkpads[nsinkpads], deinterleave_chain_func); + fail_unless (gst_pad_link (pad, mysinkpads[nsinkpads]) == GST_PAD_LINK_OK); + gst_pad_set_active (mysinkpads[nsinkpads], TRUE); + nsinkpads++; +} + +GST_START_TEST (test_2_channels) +{ + GstPad *sinkpad; + gint i; + GstBuffer *inbuf; + GstCaps *caps; + gfloat *indata; + + mysinkpads = g_new0 (GstPad *, 2); + nsinkpads = 0; + + deinterleave = gst_element_factory_make ("deinterleave", NULL); + fail_unless (deinterleave != NULL); + + mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src"); + fail_unless (mysrcpad != NULL); + + caps = gst_caps_from_string (CAPS_48khz); + fail_unless (gst_pad_set_caps (mysrcpad, caps)); + gst_pad_use_fixed_caps (mysrcpad); + + sinkpad = gst_element_get_pad (deinterleave, "sink"); + fail_unless (sinkpad != NULL); + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK); + g_object_unref (sinkpad); + + g_signal_connect (deinterleave, "pad-added", + G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2)); + + bus = gst_bus_new (); + gst_element_set_bus (deinterleave, bus); + + fail_unless (gst_element_set_state (deinterleave, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS); + + inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat)); + indata = (gfloat *) GST_BUFFER_DATA (inbuf); + for (i = 0; i < 2 * 48000; i += 2) { + indata[i] = -1.0; + indata[i + 1] = 1.0; + } + gst_buffer_set_caps (inbuf, caps); + + fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK); + + fail_unless (gst_element_set_state (deinterleave, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + for (i = 0; i < nsinkpads; i++) + g_object_unref (mysinkpads[i]); + g_free (mysinkpads); + mysinkpads = NULL; + + g_object_unref (deinterleave); + g_object_unref (bus); + gst_caps_unref (caps); +} + +GST_END_TEST; + +GST_START_TEST (test_2_channels_1_linked) +{ + GstPad *sinkpad; + gint i; + GstBuffer *inbuf; + GstCaps *caps; + gfloat *indata; + + nsinkpads = 0; + mysinkpads = g_new0 (GstPad *, 2); + + deinterleave = gst_element_factory_make ("deinterleave", NULL); + fail_unless (deinterleave != NULL); + + mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src"); + fail_unless (mysrcpad != NULL); + + caps = gst_caps_from_string (CAPS_48khz); + fail_unless (gst_pad_set_caps (mysrcpad, caps)); + gst_pad_use_fixed_caps (mysrcpad); + + sinkpad = gst_element_get_pad (deinterleave, "sink"); + fail_unless (sinkpad != NULL); + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK); + g_object_unref (sinkpad); + + g_signal_connect (deinterleave, "pad-added", + G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (1)); + + bus = gst_bus_new (); + gst_element_set_bus (deinterleave, bus); + + fail_unless (gst_element_set_state (deinterleave, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS); + + inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat)); + indata = (gfloat *) GST_BUFFER_DATA (inbuf); + for (i = 0; i < 2 * 48000; i += 2) { + indata[i] = -1.0; + indata[i + 1] = 1.0; + } + gst_buffer_set_caps (inbuf, caps); + + fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK); + + fail_unless (gst_element_set_state (deinterleave, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + for (i = 0; i < nsinkpads; i++) + g_object_unref (mysinkpads[i]); + g_free (mysinkpads); + mysinkpads = NULL; + + g_object_unref (deinterleave); + g_object_unref (bus); + gst_caps_unref (caps); +} + +GST_END_TEST; + +GST_START_TEST (test_2_channels_caps_change) +{ + GstPad *sinkpad; + GstCaps *caps, *caps2; + gint i; + GstBuffer *inbuf; + gfloat *indata; + + nsinkpads = 0; + mysinkpads = g_new0 (GstPad *, 2); + + deinterleave = gst_element_factory_make ("deinterleave", NULL); + fail_unless (deinterleave != NULL); + + mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src"); + fail_unless (mysrcpad != NULL); + + caps = gst_caps_from_string (CAPS_48khz); + fail_unless (gst_pad_set_caps (mysrcpad, caps)); + gst_pad_use_fixed_caps (mysrcpad); + + sinkpad = gst_element_get_pad (deinterleave, "sink"); + fail_unless (sinkpad != NULL); + fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK); + g_object_unref (sinkpad); + + g_signal_connect (deinterleave, "pad-added", + G_CALLBACK (deinterleave_pad_added), GINT_TO_POINTER (2)); + + bus = gst_bus_new (); + gst_element_set_bus (deinterleave, bus); + + fail_unless (gst_element_set_state (deinterleave, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS); + + inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat)); + indata = (gfloat *) GST_BUFFER_DATA (inbuf); + for (i = 0; i < 2 * 48000; i += 2) { + indata[i] = -1.0; + indata[i + 1] = 1.0; + } + gst_buffer_set_caps (inbuf, caps); + + fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK); + + caps2 = gst_caps_from_string (CAPS_32khz); + gst_pad_set_caps (mysrcpad, caps2); + + inbuf = gst_buffer_new_and_alloc (2 * 48000 * sizeof (gfloat)); + indata = (gfloat *) GST_BUFFER_DATA (inbuf); + for (i = 0; i < 2 * 48000; i += 2) { + indata[i] = -1.0; + indata[i + 1] = 1.0; + } + gst_buffer_set_caps (inbuf, caps2); + + /* Should work fine because the caps changed in a compatible way */ + fail_unless (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK); + + gst_caps_unref (caps2); + + caps2 = gst_caps_from_string (CAPS_48khz_3CH); + gst_pad_set_caps (mysrcpad, caps2); + + inbuf = gst_buffer_new_and_alloc (3 * 48000 * sizeof (gfloat)); + indata = (gfloat *) GST_BUFFER_DATA (inbuf); + for (i = 0; i < 3 * 48000; i += 3) { + indata[i] = -1.0; + indata[i + 1] = 1.0; + indata[i + 2] = 0.0; + } + gst_buffer_set_caps (inbuf, caps2); + + /* Should break because the caps changed in an incompatible way */ + fail_if (gst_pad_push (mysrcpad, inbuf) == GST_FLOW_OK); + + fail_unless (gst_element_set_state (deinterleave, + GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS); + + for (i = 0; i < nsinkpads; i++) + g_object_unref (mysinkpads[i]); + g_free (mysinkpads); + mysinkpads = NULL; + + g_object_unref (deinterleave); + g_object_unref (bus); + gst_caps_unref (caps); + gst_caps_unref (caps2); +} + +GST_END_TEST; + + +static Suite * +deinterleave_suite (void) +{ + Suite *s = suite_create ("deinterleave"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_create_and_unref); + tcase_add_test (tc_chain, test_2_channels); + tcase_add_test (tc_chain, test_2_channels_1_linked); + tcase_add_test (tc_chain, test_2_channels_caps_change); + + return s; +} + +GST_CHECK_MAIN (deinterleave);