diff --git a/ChangeLog b/ChangeLog index 0554cae180..57220e1037 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2008-05-16 Sebastian Dröge + + * gst/interleave/Makefile.am: + * gst/interleave/deinterleave.c: (deinterleave_24), + (gst_deinterleave_finalize), (gst_deinterleave_base_init), + (gst_deinterleave_class_init), (gst_deinterleave_init), + (gst_deinterleave_add_new_pads), (gst_deinterleave_set_pads_caps), + (gst_deinterleave_set_process_function), + (gst_deinterleave_sink_setcaps), (__remove_channels), + (__set_channels), (gst_deinterleave_getcaps), + (gst_deinterleave_process), (gst_deinterleave_chain), + (gst_deinterleave_sink_activate_push): + * gst/interleave/deinterleave.h: + Add support for all raw audio formats and provide better negotiation + if the caps are changing. + + Don't allow changes of the channel positions and set the position of + the corresponding channel on the src pad caps. + + General cleanup and smaller bugfixes. + + * tests/check/elements/deinterleave.c: (float_buffer_check_probe): + Check the channel positions on the output buffer caps. + 2008-05-16 Jan Schmidt * docs/Makefile.am: diff --git a/gst/interleave/Makefile.am b/gst/interleave/Makefile.am index 62e7f3e3ce..3477933c7b 100644 --- a/gst/interleave/Makefile.am +++ b/gst/interleave/Makefile.am @@ -2,8 +2,8 @@ plugin_LTLIBRARIES = libgstinterleave.la libgstinterleave_la_SOURCES = plugin.c interleave.c deinterleave.c -libgstinterleave_la_CFLAGS = $(GST_CFLAGS) -libgstinterleave_la_LIBADD = $(GST_LIBS) +libgstinterleave_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) +libgstinterleave_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) libgstinterleave_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) noinst_HEADERS = plugin.h interleave.h deinterleave.h diff --git a/gst/interleave/deinterleave.c b/gst/interleave/deinterleave.c index 743eb9f5a6..c10396938a 100644 --- a/gst/interleave/deinterleave.c +++ b/gst/interleave/deinterleave.c @@ -23,11 +23,19 @@ * Boston, MA 02111-1307, USA. */ +/* TODO: + * - handle changes in number of channels + * - handle changes in channel positions + * - better capsnego by using a buffer alloc function + * and passing downstream caps changes upstream there + */ + #ifdef HAVE_CONFIG_H # include "config.h" #endif #include +#include #include "deinterleave.h" GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug); @@ -36,62 +44,131 @@ GST_DEBUG_CATEGORY_STATIC (gst_deinterleave_debug); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src%d", GST_PAD_SRC, GST_PAD_SOMETIMES, - GST_STATIC_CAPS ("audio/x-raw-float, " + GST_STATIC_CAPS ("audio/x-raw-int, " "rate = (int) [ 1, MAX ], " "channels = (int) 1, " - "endianness = (int) BYTE_ORDER, " "width = (int) 32") + "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " + "width = (int) { 8, 16, 24, 32 }, " + "depth = (int) [ 1, 32 ], " + "signed = (boolean) { true, false }; " + "audio/x-raw-float, " + "rate = (int) [ 1, MAX ], " + "channels = (int) 1, " + "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " + "width = (int) { 32, 64 }") ); static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-float, " + GST_STATIC_CAPS ("audio/x-raw-int, " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ], " - "endianness = (int) BYTE_ORDER, " "width = (int) 32") + "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " + "width = (int) { 8, 16, 24, 32 }, " + "depth = (int) [ 1, 32 ], " + "signed = (boolean) { true, false }; " + "audio/x-raw-float, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, MAX ], " + "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " + "width = (int) { 32, 64 }") ); +#define MAKE_FUNC(type) \ +static void deinterleave_##type (guint##type *out, guint##type *in, \ + guint stride, guint nframes) \ +{ \ + gint i; \ + \ + for (i = 0; i < nframes; i++) { \ + out[i] = *in; \ + in += stride; \ + } \ +} + +MAKE_FUNC (8); +MAKE_FUNC (16); +MAKE_FUNC (32); +MAKE_FUNC (64); + +static void +deinterleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes) +{ + gint i; + + for (i = 0; i < nframes; i++) { + memcpy (out, in, 3); + out += 3; + in += stride * 3; + } +} 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 GstCaps *gst_deinterleave_getcaps (GstPad * pad); static gboolean gst_deinterleave_sink_activate_push (GstPad * pad, gboolean active); +static void +gst_deinterleave_finalize (GObject * obj) +{ + GstDeinterleave *self = GST_DEINTERLEAVE (obj); + + if (self->pos) { + g_free (self->pos); + self->pos = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (obj); +} + static void gst_deinterleave_base_init (gpointer g_class) { - gst_element_class_set_details_simple (g_class, "Audio deinterleaver", + GstElementClass *gstelement_class = (GstElementClass *) g_class; + + gst_element_class_set_details_simple (gstelement_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_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (g_class, + gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&src_template)); } static void gst_deinterleave_class_init (GstDeinterleaveClass * klass) { + GObjectClass *gobject_class = (GObjectClass *) klass; + GST_DEBUG_CATEGORY_INIT (gst_deinterleave_debug, "deinterleave", 0, "deinterleave element"); + + gobject_class->finalize = gst_deinterleave_finalize; } static void gst_deinterleave_init (GstDeinterleave * self, GstDeinterleaveClass * klass) { - self->sink = gst_pad_new_from_static_template (&sink_template, "sink"); + self->channels = 0; + self->pos = NULL; + self->width = 0; + self->func = NULL; + /* Add sink pad */ + self->sink = gst_pad_new_from_static_template (&sink_template, "sink"); gst_pad_set_chain_function (self->sink, GST_DEBUG_FUNCPTR (gst_deinterleave_chain)); gst_pad_set_setcaps_function (self->sink, GST_DEBUG_FUNCPTR (gst_deinterleave_sink_setcaps)); + gst_pad_set_getcaps_function (self->sink, gst_deinterleave_getcaps); gst_pad_set_activatepush_function (self->sink, GST_DEBUG_FUNCPTR (gst_deinterleave_sink_activate_push)); - gst_element_add_pad (GST_ELEMENT (self), self->sink); } @@ -103,20 +180,63 @@ gst_deinterleave_add_new_pads (GstDeinterleave * self, GstCaps * caps) for (i = 0; i < self->channels; i++) { gchar *name = g_strdup_printf ("src%d", i); + GstCaps *srccaps; + GstStructure *s; pad = gst_pad_new_from_static_template (&src_template, name); g_free (name); - gst_pad_set_caps (pad, caps); + + /* Set channel position if we know it */ + if (self->pos) { + srccaps = gst_caps_copy (caps); + s = gst_caps_get_structure (srccaps, 0); + gst_audio_set_channel_positions (s, &self->pos[i]); + } else { + srccaps = caps; + } + + gst_pad_set_getcaps_function (pad, gst_deinterleave_getcaps); + gst_pad_set_caps (pad, srccaps); gst_pad_use_fixed_caps (pad); gst_pad_set_active (pad, TRUE); gst_element_add_pad (GST_ELEMENT (self), pad); self->srcpads = g_list_prepend (self->srcpads, gst_object_ref (pad)); + + if (self->pos) + gst_caps_unref (srccaps); } gst_element_no_more_pads (GST_ELEMENT (self)); self->srcpads = g_list_reverse (self->srcpads); } +static void +gst_deinterleave_set_pads_caps (GstDeinterleave * self, GstCaps * caps) +{ + GList *l; + GstStructure *s; + gint i; + + for (l = self->srcpads, i = 0; l; l = l->next, i++) { + GstPad *pad = GST_PAD (l->data); + GstCaps *srccaps; + + /* Set channel position if we know it */ + if (self->pos) { + srccaps = gst_caps_copy (caps); + s = gst_caps_get_structure (srccaps, 0); + gst_audio_set_channel_positions (s, &self->pos[i]); + } else { + srccaps = caps; + } + + gst_pad_set_caps (pad, srccaps); + + if (self->pos) + gst_caps_unref (srccaps); + } +} + static void gst_deinterleave_remove_pads (GstDeinterleave * self) { @@ -137,6 +257,37 @@ gst_deinterleave_remove_pads (GstDeinterleave * self) gst_caps_replace (&self->sinkcaps, NULL); } +static gboolean +gst_deinterleave_set_process_function (GstDeinterleave * self, GstCaps * caps) +{ + GstStructure *s; + + s = gst_caps_get_structure (caps, 0); + if (!gst_structure_get_int (s, "width", &self->width)) + return FALSE; + + switch (self->width) { + case 8: + self->func = (GstDeinterleaveFunc) deinterleave_8; + break; + case 16: + self->func = (GstDeinterleaveFunc) deinterleave_16; + break; + case 24: + self->func = (GstDeinterleaveFunc) deinterleave_24; + break; + case 32: + self->func = (GstDeinterleaveFunc) deinterleave_32; + break; + case 64: + self->func = (GstDeinterleaveFunc) deinterleave_64; + break; + default: + return FALSE; + } + return TRUE; +} + static gboolean gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps) { @@ -146,52 +297,72 @@ gst_deinterleave_sink_setcaps (GstPad * pad, GstCaps * caps) self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); - if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) { - GList *l; - gint new_channels; + GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps); - if (!caps) - goto cannot_change_caps; + if (self->sinkcaps && !gst_caps_is_equal (caps, self->sinkcaps)) { + gint new_channels; + GstAudioChannelPosition *pos; s = gst_caps_get_structure (caps, 0); - /* We allow caps changes as long as the number of channels doesn't change */ + /* We allow caps changes as long as the number of channels doesn't change + * and the channel positions stay the same. _getcaps() should've cared + * for this already but better be safe. + */ if (!gst_structure_get_int (s, "channels", &new_channels) || - new_channels != self->channels) + new_channels != self->channels || + !gst_deinterleave_set_process_function (self, caps)) goto cannot_change_caps; - GST_DEBUG_OBJECT (self, "got caps: %" GST_PTR_FORMAT, caps); - gst_caps_replace (&self->sinkcaps, caps); + if (gst_structure_has_field (s, "channel-positions")) { + gint i; + gboolean same = TRUE; - /* 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"); + if (!self->pos) + goto cannot_change_caps; - for (l = self->srcpads; l; l = l->next) { - GstPad *pad = GST_PAD (l->data); + pos = gst_audio_get_channel_positions (s); + for (i = 0; i < self->channels; i++) { + if (self->pos[i] != pos[i]) { + same = FALSE; + break; + } + } - if (!gst_pad_set_caps (pad, srccaps)) + g_free (pos); + if (!same) 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); + s = gst_caps_get_structure (caps, 0); - /* Add all srcpads */ - srccaps = gst_caps_copy (caps); - s = gst_caps_get_structure (srccaps, 0); if (!gst_structure_get_int (s, "channels", &self->channels)) goto no_channels; - gst_structure_set (s, "channels", G_TYPE_INT, 1, NULL); - gst_structure_remove_field (s, "channel-positions"); - gst_deinterleave_add_new_pads (self, srccaps); - gst_caps_unref (srccaps); + + if (!gst_deinterleave_set_process_function (self, caps)) + goto unsupported_caps; + + if (gst_structure_has_field (s, "channel-positions")) + self->pos = gst_audio_get_channel_positions (s); } + gst_caps_replace (&self->sinkcaps, caps); + + /* Get srcpad caps */ + 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"); + + /* If we already have pads, update the caps otherwise + * add new pads */ + if (self->srcpads) { + gst_deinterleave_set_pads_caps (self, srccaps); + } else { + gst_deinterleave_add_new_pads (self, srccaps); + } + + gst_caps_unref (srccaps); gst_object_unref (self); return TRUE; @@ -202,6 +373,12 @@ cannot_change_caps: gst_object_unref (self); return FALSE; } +unsupported_caps: + { + GST_ERROR_OBJECT (self, "caps not supported: %" GST_PTR_FORMAT, caps); + gst_object_unref (self); + return FALSE; + } no_channels: { GST_ERROR_OBJECT (self, "invalid caps"); @@ -210,21 +387,114 @@ no_channels: } } +static void +__remove_channels (GstCaps * caps) +{ + GstStructure *s; + gint i, size; + + size = gst_caps_get_size (caps); + for (i = 0; i < size; i++) { + s = gst_caps_get_structure (caps, i); + gst_structure_remove_field (s, "channel-positions"); + gst_structure_remove_field (s, "channels"); + } +} + +static void +__set_channels (GstCaps * caps, gint channels) +{ + GstStructure *s; + gint i, size; + + size = gst_caps_get_size (caps); + for (i = 0; i < size; i++) { + s = gst_caps_get_structure (caps, i); + if (channels > 0) + gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL); + else + gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL); + } +} + +static GstCaps * +gst_deinterleave_getcaps (GstPad * pad) +{ + GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); + GstCaps *ret; + GList *l; + + GST_OBJECT_LOCK (self); + + /* Intersect all of our pad template caps with the peer caps of the pad + * to get all formats that are possible up- and downstream. + * + * For the pad for which the caps are requested we don't remove the channel + * informations as they must be in the returned caps and incompatibilities + * will be detected here already + */ + ret = gst_caps_new_any (); + for (l = GST_ELEMENT (self)->pads; l != NULL; l = l->next) { + GstPad *ourpad = GST_PAD (l->data); + GstCaps *peercaps, *ourcaps; + + ourcaps = gst_caps_copy (gst_pad_get_pad_template_caps (ourpad)); + + if (pad == ourpad) { + if (GST_PAD_DIRECTION (pad) == GST_PAD_SINK) + __set_channels (ourcaps, self->channels); + else + __set_channels (ourcaps, 1); + } else { + __remove_channels (ourcaps); + } + + peercaps = gst_pad_peer_get_caps (ourpad); + if (pad != ourpad && peercaps) + __remove_channels (peercaps); + + /* If the peer exists and has caps add them to the intersection, + * otherwise assume that the peer accepts everything */ + if (peercaps) { + GstCaps *intersection; + GstCaps *oldret = ret; + + intersection = gst_caps_intersect (peercaps, ourcaps); + + ret = gst_caps_intersect (ret, intersection); + gst_caps_unref (intersection); + gst_caps_unref (peercaps); + gst_caps_unref (oldret); + } else { + GstCaps *oldret = ret; + + ret = gst_caps_intersect (ret, ourcaps); + gst_caps_unref (oldret); + } + gst_caps_unref (ourcaps); + } + + GST_OBJECT_UNLOCK (self); + + gst_object_unref (self); + + GST_DEBUG_OBJECT (pad, "Intersected caps to %" GST_PTR_FORMAT, ret); + + return ret; +} + static GstFlowReturn gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) { - GstFlowReturn ret = GST_FLOW_OK; /* initialized to silence a warning */ + GstFlowReturn ret = GST_FLOW_OK; + guint channels = self->channels; + guint pads_pushed = 0, buffers_allocated = 0; + guint nframes = GST_BUFFER_SIZE (buf) / channels / (self->width / 8); + guint bufsize = nframes * (self->width / 8); + guint i; GList *srcs; - guint bufsize, i, j, channels, pads_pushed, buffers_allocated, nframes; - GstBuffer **buffers_out; - gfloat *in, *out; - - channels = self->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; + GstBuffer **buffers_out = g_new0 (GstBuffer *, channels); + guint8 *in, *out; /* Allocate buffers */ for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) { @@ -235,10 +505,16 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) gst_pad_alloc_buffer (pad, GST_BUFFER_OFFSET_NONE, bufsize, GST_PAD_CAPS (pad), &buffers_out[i]); + /* Make sure we got a correct buffer. The only other case we allow + * here is an unliked pad */ 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) + else if (buffers_out[i] && GST_BUFFER_SIZE (buffers_out[i]) != bufsize) goto alloc_buffer_bad_size; + else if (buffers_out[i] && + !gst_caps_is_equal (GST_BUFFER_CAPS (buffers_out[i]), + GST_PAD_CAPS (pad))) + goto invalid_caps; if (buffers_out[i]) { gst_buffer_copy_metadata (buffers_out[i], buf, @@ -247,7 +523,7 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) } } - /* Return NOT_LINKED if we couldn't allocate any buffers */ + /* Return NOT_LINKED if no pad was linked */ if (!buffers_allocated) { ret = GST_FLOW_NOT_LINKED; goto done; @@ -257,12 +533,12 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) for (srcs = self->srcpads, i = 0; srcs; srcs = srcs->next, i++) { GstPad *pad = (GstPad *) srcs->data; - in = (gfloat *) GST_BUFFER_DATA (buf); - in += i; /* gfloat * arith */ + in = (guint8 *) GST_BUFFER_DATA (buf); + in += i * (self->width / 8); if (buffers_out[i]) { - out = (gfloat *) GST_BUFFER_DATA (buffers_out[i]); - for (j = 0; j < nframes * channels; j += channels) - *out++ = in[j]; + out = (guint8 *) GST_BUFFER_DATA (buffers_out[i]); + + self->func (out, in, channels, nframes); ret = gst_pad_push (pad, buffers_out[i]); buffers_out[i] = NULL; @@ -275,6 +551,7 @@ gst_deinterleave_process (GstDeinterleave * self, GstBuffer * buf) } } + /* Return NOT_LINKED if no pad was linked */ if (!pads_pushed) ret = GST_FLOW_NOT_LINKED; @@ -295,6 +572,12 @@ alloc_buffer_bad_size: ret = GST_FLOW_NOT_NEGOTIATED; goto clean_buffers; } +invalid_caps: + { + GST_WARNING ("called alloc_buffer(), but didn't get requested caps"); + ret = GST_FLOW_NOT_NEGOTIATED; + goto clean_buffers; + } push_failed: { GST_DEBUG ("push() failed, flow = %s", gst_flow_get_name (ret)); @@ -315,15 +598,17 @@ clean_buffers: static GstFlowReturn gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer) { - GstDeinterleave *self; + GstDeinterleave *self = GST_DEINTERLEAVE (GST_PAD_PARENT (pad)); GstFlowReturn ret; - self = GST_DEINTERLEAVE (GST_PAD_PARENT (pad)); + g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); + g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED); + g_return_val_if_fail (self->channels > 0, GST_FLOW_NOT_NEGOTIATED); ret = gst_deinterleave_process (self, buffer); if (ret != GST_FLOW_OK) - GST_DEBUG_OBJECT (self, "flow: %s", gst_flow_get_name (ret)); + GST_DEBUG_OBJECT (self, "flow return: %s", gst_flow_get_name (ret)); return ret; } @@ -331,12 +616,19 @@ gst_deinterleave_chain (GstPad * pad, GstBuffer * buffer) static gboolean gst_deinterleave_sink_activate_push (GstPad * pad, gboolean active) { - GstDeinterleave *self; + GstDeinterleave *self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); - self = GST_DEINTERLEAVE (gst_pad_get_parent (pad)); - - if (!active) + /* Reset everything when the pad is deactivated */ + if (!active) { gst_deinterleave_remove_pads (self); + if (self->pos) { + g_free (self->pos); + self->pos = NULL; + } + self->channels = 0; + self->width = 0; + self->func = NULL; + } gst_object_unref (self); diff --git a/gst/interleave/deinterleave.h b/gst/interleave/deinterleave.h index ee3f8e17ec..4a1c95789d 100644 --- a/gst/interleave/deinterleave.h +++ b/gst/interleave/deinterleave.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS #include +#include #define GST_TYPE_DEINTERLEAVE (gst_deinterleave_get_type()) #define GST_DEINTERLEAVE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DEINTERLEAVE,GstDeinterleave)) @@ -41,6 +42,8 @@ G_BEGIN_DECLS typedef struct _GstDeinterleave GstDeinterleave; typedef struct _GstDeinterleaveClass GstDeinterleaveClass; +typedef void (*GstDeinterleaveFunc) (gpointer out, gpointer in, guint stride, guint nframes); + struct _GstDeinterleave { GstElement element; @@ -49,8 +52,12 @@ struct _GstDeinterleave GList *srcpads; GstCaps *sinkcaps; gint channels; + GstAudioChannelPosition *pos; GstPad *sink; + + gint width; + GstDeinterleaveFunc func; }; struct _GstDeinterleaveClass diff --git a/tests/check/elements/deinterleave.c b/tests/check/elements/deinterleave.c index 22ac08423e..c22acacaeb 100644 --- a/tests/check/elements/deinterleave.c +++ b/tests/check/elements/deinterleave.c @@ -55,7 +55,7 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-float, " "width = (int) 32, " - "channels = (int) 2, " + "channels = (int) { 2, 3 }, " "rate = (int) {32000, 48000}, " "endianness = (int) BYTE_ORDER")); #define CAPS_32khz \ @@ -417,14 +417,30 @@ float_buffer_check_probe (GstPad * pad, GstBuffer * buf, gpointer userdata) gfloat *data; guint padnum, numpads; guint num, i; + GstCaps *caps; + GstStructure *s; + GstAudioChannelPosition *pos; + gint channels; fail_unless_equals_int (sscanf (GST_PAD_NAME (pad), "src%u", &padnum), 1); numpads = pads_created; + /* Check caps */ + caps = GST_BUFFER_CAPS (buf); + fail_unless (caps != NULL); + s = gst_caps_get_structure (caps, 0); + fail_unless (gst_structure_get_int (s, "channels", &channels)); + fail_unless_equals_int (channels, 1); + fail_unless (gst_structure_has_field (s, "channel-positions")); + pos = gst_audio_get_channel_positions (s); + fail_unless (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE); + g_free (pos); + data = (gfloat *) GST_BUFFER_DATA (buf); num = GST_BUFFER_SIZE (buf) / sizeof (gfloat); + /* Check buffer content */ for (i = 0; i < num; ++i) { guint val, rest;