Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / interleave / interleave.c
index 020d576..e09b37f 100644 (file)
  * <refsect2>
  * <title>Example launch line</title>
  * |[
- * gst-launch filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw-int,channels=2" ! deinterleave name=d  interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav    d.src0 ! queue ! audioconvert ! i.sink1    d.src1 ! queue ! audioconvert ! i.sink0
+ * gst-launch filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2" ! deinterleave name=d  interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav    d.src_0 ! queue ! audioconvert ! i.sink_1    d.src_1 ! queue ! audioconvert ! i.sink_0
  * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and
  * then interleaves the channels again to a WAV file with the channel with the
  * channels exchanged.
  * |[
- * gst-launch interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav  filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw-int,channels=1" ! queue ! i.sink0   filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw-int,channels=1" ! queue ! i.sink1
+ * gst-launch interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav  filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1" ! queue ! i.sink_0   filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1" ! queue ! i.sink_1
  * ]| Interleaves two Mono WAV files to a single Stereo WAV file.
  * </refsect2>
  */
 #include <string.h>
 #include "interleave.h"
 
-#include <gst/audio/multichannel.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/audio-enumtypes.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",
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
     GST_PAD_SINK,
     GST_PAD_REQUEST,
-    GST_STATIC_CAPS ("audio/x-raw-int, "
+    GST_STATIC_CAPS ("audio/x-raw, "
         "rate = (int) [ 1, MAX ], "
         "channels = (int) 1, "
-        "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
-        "width = (int) { 8, 16, 24, 32 }, "
-        "depth = (int) [ 1, 32 ], "
-        "signed = (boolean) true; "
-        "audio/x-raw-float, "
-        "rate = (int) [ 1, MAX ], "
-        "channels = (int) 1, "
-        "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
-        "width = (int) { 32, 64 }")
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
+        "layout = (string) {non-interleaved, interleaved}")
     );
 
 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS ("audio/x-raw-int, "
-        "rate = (int) [ 1, MAX ], "
-        "channels = (int) [ 1, MAX ], "
-        "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
-        "width = (int) { 8, 16, 24, 32 }, "
-        "depth = (int) [ 1, 32 ], "
-        "signed = (boolean) true; "
-        "audio/x-raw-float, "
+    GST_STATIC_CAPS ("audio/x-raw, "
         "rate = (int) [ 1, MAX ], "
         "channels = (int) [ 1, MAX ], "
-        "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, "
-        "width = (int) { 32, 64 }")
+        "format = (string) " GST_AUDIO_FORMATS_ALL ", "
+        "layout = (string) interleaved")
     );
 
 #define MAKE_FUNC(type) \
@@ -200,7 +187,8 @@ gst_interleave_pad_class_init (GstPadClass * klass)
           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
-GST_BOILERPLATE (GstInterleave, gst_interleave, GstElement, GST_TYPE_ELEMENT);
+#define gst_interleave_parent_class parent_class
+G_DEFINE_TYPE (GstInterleave, gst_interleave, GST_TYPE_ELEMENT);
 
 enum
 {
@@ -215,21 +203,26 @@ static void gst_interleave_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
 
 static GstPad *gst_interleave_request_new_pad (GstElement * element,
-    GstPadTemplate * templ, const gchar * name);
+    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
 static void gst_interleave_release_pad (GstElement * element, GstPad * pad);
 
 static GstStateChangeReturn gst_interleave_change_state (GstElement * element,
     GstStateChange transition);
 
-static gboolean gst_interleave_src_query (GstPad * pad, GstQuery * query);
+static gboolean gst_interleave_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
 
-static gboolean gst_interleave_src_event (GstPad * pad, GstEvent * event);
+static gboolean gst_interleave_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event);
 
-static gboolean gst_interleave_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_interleave_sink_event (GstCollectPads2 * pads,
+    GstCollectData2 * data, GstEvent * event, gpointer user_data);
 
-static gboolean gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean gst_interleave_sink_setcaps (GstInterleave * self,
+    GstPad * pad, const GstCaps * caps);
 
-static GstCaps *gst_interleave_sink_getcaps (GstPad * pad);
+static GstCaps *gst_interleave_sink_getcaps (GstPad * pad, GstObject * parent,
+    GstCaps * filter);
 
 static GstFlowReturn gst_interleave_collected (GstCollectPads2 * pads,
     GstInterleave * self);
@@ -246,12 +239,12 @@ gst_interleave_finalize (GObject * object)
 
   if (self->channel_positions
       && self->channel_positions != self->input_channel_positions) {
-    g_value_array_free (self->channel_positions);
+    g_array_free (self->channel_positions, TRUE);
     self->channel_positions = NULL;
   }
 
   if (self->input_channel_positions) {
-    g_value_array_free (self->input_channel_positions);
+    g_array_free (self->input_channel_positions, TRUE);
     self->input_channel_positions = NULL;
   }
 
@@ -261,23 +254,24 @@ gst_interleave_finalize (GObject * object)
 }
 
 static gboolean
-gst_interleave_check_channel_positions (GValueArray * positions)
+gst_interleave_check_channel_positions (GArray * positions)
 {
   gint i;
   guint channels;
   GstAudioChannelPosition *pos;
   gboolean ret;
+  GValue val;
 
-  channels = positions->n_values;
-  pos = g_new (GstAudioChannelPosition, positions->n_values);
+  channels = positions->len;
+  pos = g_new (GstAudioChannelPosition, channels);
 
   for (i = 0; i < channels; i++) {
-    GValue *v = g_value_array_get_nth (positions, i);
-
-    pos[i] = g_value_get_enum (v);
+    val = g_array_index (positions, GValue, i);
+    pos[i] = g_value_get_enum (&val);
+    g_value_reset (&val);
   }
 
-  ret = gst_audio_check_channel_positions (pos, channels);
+  ret = gst_audio_check_valid_channel_positions (pos, channels, FALSE);
   g_free (pos);
 
   return ret;
@@ -286,46 +280,22 @@ gst_interleave_check_channel_positions (GValueArray * positions)
 static void
 gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s)
 {
-  GValue pos_array = { 0, };
   gint i;
+  guint64 channel_mask = 0;
+  GValue val;
 
-  g_value_init (&pos_array, GST_TYPE_ARRAY);
-
-  if (self->channel_positions
-      && self->channels == self->channel_positions->n_values
+  if (self->channel_positions && self->channels == self->channel_positions->len
       && gst_interleave_check_channel_positions (self->channel_positions)) {
     GST_DEBUG_OBJECT (self, "Using provided channel positions");
-    for (i = 0; i < self->channels; i++)
-      gst_value_array_append_value (&pos_array,
-          g_value_array_get_nth (self->channel_positions, i));
+    for (i = 0; i < self->channels; i++) {
+      val = g_array_index (self->channel_positions, GValue, i);
+      channel_mask |= G_GUINT64_CONSTANT (1) << g_value_get_enum (&val);
+      g_value_reset (&val);
+    }
   } else {
-    GValue pos_none = { 0, };
-
     GST_WARNING_OBJECT (self, "Using NONE channel positions");
-
-    g_value_init (&pos_none, GST_TYPE_AUDIO_CHANNEL_POSITION);
-    g_value_set_enum (&pos_none, GST_AUDIO_CHANNEL_POSITION_NONE);
-
-    for (i = 0; i < self->channels; i++)
-      gst_value_array_append_value (&pos_array, &pos_none);
-
-    g_value_unset (&pos_none);
   }
-  gst_structure_set_value (s, "channel-positions", &pos_array);
-  g_value_unset (&pos_array);
-}
-
-static void
-gst_interleave_base_init (gpointer g_class)
-{
-  gst_element_class_set_details_simple (g_class, "Audio interleaver",
-      "Filter/Converter/Audio",
-      "Folds many mono channels into one interleaved audio stream",
-      "Andy Wingo <wingo at pobox.com>, "
-      "Sebastian Dröge <slomo@circular-chaos.org>");
-
-  gst_element_class_add_static_pad_template (g_class, &sink_template);
-  gst_element_class_add_static_pad_template (g_class, &src_template);
+  gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL);
 }
 
 static void
@@ -340,6 +310,17 @@ gst_interleave_class_init (GstInterleaveClass * klass)
   GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0,
       "interleave element");
 
+  gst_element_class_set_details_simple (gstelement_class, "Audio interleaver",
+      "Filter/Converter/Audio",
+      "Folds many mono channels into one interleaved audio stream",
+      "Andy Wingo <wingo at pobox.com>, "
+      "Sebastian Dröge <slomo@circular-chaos.org>");
+
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&sink_template));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&src_template));
+
   /* Reference GstInterleavePad class to have the type registered from
    * a threadsafe context
    */
@@ -364,13 +345,8 @@ gst_interleave_class_init (GstInterleaveClass * klass)
    *
    */
   g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS,
-      g_param_spec_value_array ("channel-positions", "Channel positions",
-          "Channel positions used on the output",
-          g_param_spec_enum ("channel-position", "Channel position",
-              "Channel position of the n-th input",
-              GST_TYPE_AUDIO_CHANNEL_POSITION,
-              GST_AUDIO_CHANNEL_POSITION_NONE,
-              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+      g_param_spec_boxed ("channel-positions", "Channel positions",
+          "Channel position of the n-th output", G_TYPE_ARRAY,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   /**
@@ -398,7 +374,7 @@ gst_interleave_class_init (GstInterleaveClass * klass)
 }
 
 static void
-gst_interleave_init (GstInterleave * self, GstInterleaveClass * klass)
+gst_interleave_init (GstInterleave * self)
 {
   self->src = gst_pad_new_from_static_template (&src_template, "src");
 
@@ -407,13 +383,14 @@ gst_interleave_init (GstInterleave * self, GstInterleaveClass * klass)
   gst_pad_set_event_function (self->src,
       GST_DEBUG_FUNCPTR (gst_interleave_src_event));
 
+  gst_pad_set_active (self->src, TRUE);
   gst_element_add_pad (GST_ELEMENT (self), self->src);
 
   self->collect = gst_collect_pads2_new ();
   gst_collect_pads2_set_function (self->collect,
       (GstCollectPads2Function) gst_interleave_collected, self);
 
-  self->input_channel_positions = g_value_array_new (0);
+  self->input_channel_positions = g_array_new (FALSE, TRUE, sizeof (GValue));
   self->channel_positions_from_input = TRUE;
   self->channel_positions = self->input_channel_positions;
 }
@@ -423,15 +400,22 @@ gst_interleave_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
   GstInterleave *self = GST_INTERLEAVE (object);
+  int i;
+  GArray *arr;
 
   switch (prop_id) {
     case PROP_CHANNEL_POSITIONS:
       if (self->channel_positions &&
           self->channel_positions != self->input_channel_positions)
-        g_value_array_free (self->channel_positions);
+        g_array_free (self->channel_positions, TRUE);
 
-      self->channel_positions = g_value_dup_boxed (value);
+      arr = g_value_get_boxed (value);
+      self->channel_positions = g_array_new (FALSE, TRUE, sizeof (GValue));
+      for (i = 0; i < arr->len; i++)
+        g_array_append_val (self->channel_positions, g_array_index (arr, GValue,
+                i));
       self->channel_positions_from_input = FALSE;
+      self->channels = self->channel_positions->len;
       break;
     case PROP_CHANNEL_POSITIONS_FROM_INPUT:
       self->channel_positions_from_input = g_value_get_boolean (value);
@@ -439,7 +423,7 @@ gst_interleave_set_property (GObject * object, guint prop_id,
       if (self->channel_positions_from_input) {
         if (self->channel_positions &&
             self->channel_positions != self->input_channel_positions)
-          g_value_array_free (self->channel_positions);
+          g_array_free (self->channel_positions, TRUE);
         self->channel_positions = self->input_channel_positions;
       }
       break;
@@ -470,7 +454,7 @@ gst_interleave_get_property (GObject * object, guint prop_id,
 
 static GstPad *
 gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
-    const gchar * req_name)
+    const gchar * req_name, const GstCaps * caps)
 {
   GstInterleave *self = GST_INTERLEAVE (element);
   GstPad *new_pad;
@@ -481,15 +465,13 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
   if (templ->direction != GST_PAD_SINK)
     goto not_sink_pad;
 
-#if GLIB_CHECK_VERSION(2,29,5)
-  channels = g_atomic_int_add (&self->channels, 1);
   padnumber = g_atomic_int_add (&self->padcounter, 1);
-#else
-  channels = g_atomic_int_exchange_and_add (&self->channels, 1);
-  padnumber = g_atomic_int_exchange_and_add (&self->padcounter, 1);
-#endif
+  if (self->channel_positions_from_input)
+    channels = g_atomic_int_add (&self->channels, 1);
+  else
+    channels = padnumber;
 
-  pad_name = g_strdup_printf ("sink%d", padnumber);
+  pad_name = g_strdup_printf ("sink_%u", padnumber);
   new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD,
           "name", pad_name, "direction", templ->direction,
           "template", templ, NULL));
@@ -497,19 +479,13 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
   GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name);
   g_free (pad_name);
 
-  gst_pad_set_setcaps_function (new_pad,
-      GST_DEBUG_FUNCPTR (gst_interleave_sink_setcaps));
-  gst_pad_set_getcaps_function (new_pad,
-      GST_DEBUG_FUNCPTR (gst_interleave_sink_getcaps));
+  gst_pad_use_fixed_caps (new_pad);
 
   gst_collect_pads2_add_pad (self->collect, new_pad, sizeof (GstCollectData2));
 
-  /* FIXME: hacked way to override/extend the event function of
-   * GstCollectPads2; because it sets its own event function giving the
-   * element no access to events */
-  self->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (new_pad);
-  gst_pad_set_event_function (new_pad,
-      GST_DEBUG_FUNCPTR (gst_interleave_sink_event));
+  gst_collect_pads2_set_event_function (self->collect,
+      (GstCollectPads2EventFunction)
+      GST_DEBUG_FUNCPTR (gst_interleave_sink_event), self);
 
   if (!gst_element_add_pad (element, new_pad))
     goto could_not_add;
@@ -517,7 +493,7 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
   g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
   g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE);
   self->input_channel_positions =
-      g_value_array_append (self->input_channel_positions, &val);
+      g_array_append_val (self->input_channel_positions, val);
   g_value_unset (&val);
 
   /* Update the src caps if we already have them */
@@ -534,6 +510,7 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ,
     gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
     gst_interleave_set_channel_positions (self, s);
 
+    gst_pad_set_active (self->src, TRUE);
     gst_pad_set_caps (self->src, srccaps);
     gst_caps_unref (srccaps);
 
@@ -562,6 +539,7 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad)
 {
   GstInterleave *self = GST_INTERLEAVE (element);
   GList *l;
+  GstAudioChannelPosition position;
 
   g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad));
 
@@ -570,8 +548,8 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad)
 
   g_atomic_int_add (&self->channels, -1);
 
-  g_value_array_remove (self->input_channel_positions,
-      GST_INTERLEAVE_PAD_CAST (pad)->channel);
+  position = GST_INTERLEAVE_PAD_CAST (pad)->channel;
+  g_array_remove_index (self->input_channel_positions, position);
 
   /* Update channel numbers */
   GST_OBJECT_LOCK (self);
@@ -595,11 +573,11 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad)
       gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
       gst_interleave_set_channel_positions (self, s);
 
+      gst_pad_set_active (self->src, TRUE);
       gst_pad_set_caps (self->src, srccaps);
       gst_caps_unref (srccaps);
     } else {
       gst_caps_replace (&self->sinkcaps, NULL);
-      gst_pad_set_caps (self->src, NULL);
     }
   }
 
@@ -648,7 +626,6 @@ gst_interleave_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      gst_pad_set_caps (self->src, NULL);
       gst_caps_replace (&self->sinkcaps, NULL);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -669,7 +646,7 @@ __remove_channels (GstCaps * caps)
   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, "channel-mask");
     gst_structure_remove_field (s, "channels");
   }
 }
@@ -692,9 +669,9 @@ __set_channels (GstCaps * caps, gint channels)
 
 /* we can only accept caps that we and downstream can handle. */
 static GstCaps *
-gst_interleave_sink_getcaps (GstPad * pad)
+gst_interleave_sink_getcaps (GstPad * pad, GstObject * parent, GstCaps * filter)
 {
-  GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
+  GstInterleave *self = GST_INTERLEAVE (parent);
   GstCaps *result, *peercaps, *sinkcaps;
 
   GST_OBJECT_LOCK (self);
@@ -704,7 +681,8 @@ gst_interleave_sink_getcaps (GstPad * pad)
     result = gst_caps_copy (self->sinkcaps);
   } else {
     /* get the downstream possible caps */
-    peercaps = gst_pad_peer_get_caps (self->src);
+    peercaps = gst_pad_peer_query_caps (self->src, NULL);
+
     /* get the allowed caps on this sinkpad */
     sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
     __remove_channels (sinkcaps);
@@ -726,8 +704,6 @@ gst_interleave_sink_getcaps (GstPad * pad)
 
   GST_OBJECT_UNLOCK (self);
 
-  gst_object_unref (self);
-
   GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result);
 
   return result;
@@ -759,14 +735,11 @@ gst_interleave_set_process_function (GstInterleave * self)
 }
 
 static gboolean
-gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps)
+gst_interleave_sink_setcaps (GstInterleave * self, GstPad * pad,
+    const GstCaps * caps)
 {
-  GstInterleave *self;
-
   g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE);
 
-  self = GST_INTERLEAVE (gst_pad_get_parent (pad));
-
   /* First caps that are set on a sink pad are used as output caps */
   /* TODO: handle caps changes */
   if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) {
@@ -775,38 +748,35 @@ gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps)
     GstCaps *srccaps;
     GstStructure *s;
     gboolean res;
+    GstAudioInfo info;
+    GValue *val;
+    guint channel;
 
-    s = gst_caps_get_structure (caps, 0);
+    if (!gst_audio_info_from_caps (&info, caps))
+      goto invalid_caps;
 
-    if (!gst_structure_get_int (s, "width", &self->width))
-      goto no_width;
+    self->width = GST_AUDIO_INFO_WIDTH (&info);
+    self->rate = GST_AUDIO_INFO_RATE (&info);
 
-    if (!gst_structure_get_int (s, "rate", &self->rate))
-      goto no_rate;
 
     gst_interleave_set_process_function (self);
+    channel = GST_INTERLEAVE_PAD_CAST (pad)->channel;
 
-    if (gst_structure_has_field (s, "channel-positions")) {
-      const GValue *pos_array;
-
-      pos_array = gst_structure_get_value (s, "channel-positions");
-      if (GST_VALUE_HOLDS_ARRAY (pos_array)
-          && gst_value_array_get_size (pos_array) == 1) {
-        const GValue *pos = gst_value_array_get_value (pos_array, 0);
-
-        GValue *apos = g_value_array_get_nth (self->input_channel_positions,
-            GST_INTERLEAVE_PAD_CAST (pad)->channel);
-
-        g_value_set_enum (apos, g_value_get_enum (pos));
-      }
+    if (self->channel_positions_from_input
+        && GST_AUDIO_INFO_CHANNELS (&info) == 1) {
+      val = &g_array_index (self->input_channel_positions, GValue, channel);
+      g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
     }
 
     srccaps = gst_caps_copy (caps);
     s = gst_caps_get_structure (srccaps, 0);
 
+    gst_structure_remove_field (s, "channel-mask");
+
     gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
     gst_interleave_set_channel_positions (self, s);
 
+    gst_pad_set_active (self->src, TRUE);
     res = gst_pad_set_caps (self->src, srccaps);
     gst_caps_unref (srccaps);
 
@@ -818,53 +788,42 @@ gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps)
     GstCaps *sinkcaps = gst_caps_copy (caps);
     GstStructure *s = gst_caps_get_structure (sinkcaps, 0);
 
-    gst_structure_remove_field (s, "channel-positions");
+    gst_structure_remove_field (s, "channel-mask");
 
     gst_caps_replace (&self->sinkcaps, sinkcaps);
 
     gst_caps_unref (sinkcaps);
   }
 
-  gst_object_unref (self);
-
   return TRUE;
 
 cannot_change_caps:
   {
     GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
         "change", self->sinkcaps);
-    gst_object_unref (self);
     return FALSE;
   }
 src_did_not_accept:
   {
     GST_WARNING_OBJECT (self, "src did not accept setcaps()");
-    gst_object_unref (self);
-    return FALSE;
-  }
-no_width:
-  {
-    GST_WARNING_OBJECT (self, "caps did not have width: %" GST_PTR_FORMAT,
-        caps);
-    gst_object_unref (self);
     return FALSE;
   }
-no_rate:
+invalid_caps:
   {
-    GST_WARNING_OBJECT (self, "caps did not have rate: %" GST_PTR_FORMAT, caps);
-    gst_object_unref (self);
+    GST_WARNING_OBJECT (self, "invalid sink caps");
     return FALSE;
   }
 }
 
 static gboolean
-gst_interleave_sink_event (GstPad * pad, GstEvent * event)
+gst_interleave_sink_event (GstCollectPads2 * pads, GstCollectData2 * data,
+    GstEvent * event, gpointer user_data)
 {
-  GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
-  gboolean ret;
+  GstInterleave *self = GST_INTERLEAVE (user_data);
+  gboolean ret = FALSE;
 
   GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
-      GST_DEBUG_PAD_NAME (pad));
+      GST_DEBUG_PAD_NAME (data->pad));
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_STOP:
@@ -876,14 +835,21 @@ gst_interleave_sink_event (GstPad * pad, GstEvent * event)
        */
       self->segment_pending = TRUE;
       break;
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_interleave_sink_setcaps (self, data->pad, caps);
+      gst_event_unref (event);
+      break;
+    }
     default:
+      ret = gst_pad_event_default (data->pad, GST_OBJECT (self), event);
       break;
   }
 
   /* now GstCollectPads2 can take care of the rest, e.g. EOS */
-  ret = self->collect_event (pad, event);
-
-  gst_object_unref (self);
   return ret;
 }
 
@@ -908,7 +874,7 @@ gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
   while (!done) {
     GstIteratorResult ires;
 
-    gpointer item;
+    GValue item = { 0, };
 
     ires = gst_iterator_next (it, &item);
     switch (ires) {
@@ -917,12 +883,12 @@ gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
         break;
       case GST_ITERATOR_OK:
       {
-        GstPad *pad = GST_PAD_CAST (item);
+        GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));
 
         gint64 duration;
 
         /* ask sink peer for duration */
-        res &= gst_pad_query_peer_duration (pad, &format, &duration);
+        res &= gst_pad_peer_query_duration (pad, format, &duration);
         /* take max from all valid return values */
         if (res) {
           /* valid unknown length, stop searching */
@@ -935,6 +901,7 @@ gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query)
             max = duration;
         }
         gst_object_unref (pad);
+        g_value_unset (&item);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -985,7 +952,7 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query)
   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self));
   while (!done) {
     GstIteratorResult ires;
-    gpointer item;
+    GValue item = { 0, };
 
     ires = gst_iterator_next (it, &item);
     switch (ires) {
@@ -994,7 +961,7 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query)
         break;
       case GST_ITERATOR_OK:
       {
-        GstPad *pad = GST_PAD_CAST (item);
+        GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item));
         GstQuery *peerquery;
         GstClockTime min_cur, max_cur;
         gboolean live_cur;
@@ -1021,6 +988,7 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query)
 
         gst_query_unref (peerquery);
         gst_object_unref (pad);
+        g_value_unset (&item);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -1050,9 +1018,9 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query)
 }
 
 static gboolean
-gst_interleave_src_query (GstPad * pad, GstQuery * query)
+gst_interleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
 {
-  GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
+  GstInterleave *self = GST_INTERLEAVE (parent);
   gboolean res = FALSE;
 
   switch (GST_QUERY_TYPE (query)) {
@@ -1088,20 +1056,30 @@ gst_interleave_src_query (GstPad * pad, GstQuery * query)
     case GST_QUERY_LATENCY:
       res = gst_interleave_src_query_latency (self, query);
       break;
+    case GST_QUERY_CAPS:
+    {
+      GstCaps *filter, *caps;
+
+      gst_query_parse_caps (query, &filter);
+      caps = gst_interleave_sink_getcaps (pad, parent, filter);
+      gst_query_set_caps_result (query, caps);
+      gst_caps_unref (caps);
+      res = TRUE;
+    }
     default:
       /* FIXME, needs a custom query handler because we have multiple
        * sinkpads */
-      res = gst_pad_query_default (pad, query);
+      res = gst_pad_query_default (pad, parent, query);
       break;
   }
 
-  gst_object_unref (self);
   return res;
 }
 
 static gboolean
-forward_event_func (GstPad * pad, GValue * ret, GstEvent * event)
+forward_event_func (const GValue * item, GValue * ret, GstEvent * event)
 {
+  GstPad *pad = GST_PAD_CAST (g_value_dup_object (item));
   gst_event_ref (event);
   GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event));
   if (!gst_pad_push_event (pad, event)) {
@@ -1138,9 +1116,9 @@ forward_event (GstInterleave * self, GstEvent * event)
 
 
 static gboolean
-gst_interleave_src_event (GstPad * pad, GstEvent * event)
+gst_interleave_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
 {
-  GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad));
+  GstInterleave *self = GST_INTERLEAVE (parent);
   gboolean result;
 
   switch (GST_EVENT_TYPE (event)) {
@@ -1190,7 +1168,6 @@ gst_interleave_src_event (GstPad * pad, GstEvent * event)
       result = forward_event (self, event);
       break;
   }
-  gst_object_unref (self);
 
   return result;
 }
@@ -1206,6 +1183,7 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self)
   guint ncollected = 0;
   gboolean empty = TRUE;
   gint width = self->width / 8;
+  GstMapInfo write_info;
 
   g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED);
   g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED);
@@ -1221,27 +1199,21 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self)
 
   nsamples = size / width;
 
-  ret =
-      gst_pad_alloc_buffer (self->src, GST_BUFFER_OFFSET_NONE,
-      size * self->channels, GST_PAD_CAPS (self->src), &outbuf);
+  outbuf = gst_buffer_new_allocate (NULL, size * self->channels, 0);
 
-  if (ret != GST_FLOW_OK) {
-    return ret;
-  } else if (outbuf == NULL || GST_BUFFER_SIZE (outbuf) < size * self->channels) {
-    gst_buffer_unref (outbuf);
-    return GST_FLOW_NOT_NEGOTIATED;
-  } else if (!gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
-          GST_PAD_CAPS (self->src))) {
+  if (outbuf == NULL || gst_buffer_get_size (outbuf) < size * self->channels) {
     gst_buffer_unref (outbuf);
     return GST_FLOW_NOT_NEGOTIATED;
   }
 
-  memset (GST_BUFFER_DATA (outbuf), 0, size * self->channels);
+  gst_buffer_map (outbuf, &write_info, GST_MAP_WRITE);
+  memset (write_info.data, 0, size * self->channels);
 
   for (collected = pads->data; collected != NULL; collected = collected->next) {
     GstCollectData2 *cdata;
     GstBuffer *inbuf;
     guint8 *outdata;
+    GstMapInfo input_info;
 
     cdata = (GstCollectData2 *) collected->data;
 
@@ -1251,30 +1223,33 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self)
       goto next;
     }
     ncollected++;
+    gst_buffer_map (inbuf, &input_info, GST_MAP_READ);
 
     if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))
       goto next;
 
     empty = FALSE;
     outdata =
-        GST_BUFFER_DATA (outbuf) +
-        width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
+        write_info.data + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
 
-    self->func (outdata, GST_BUFFER_DATA (inbuf), self->channels, nsamples);
+    self->func (outdata, input_info.data, self->channels, nsamples);
+    gst_buffer_unmap (inbuf, &input_info);
 
   next:
     if (inbuf)
       gst_buffer_unref (inbuf);
   }
 
-  if (ncollected == 0)
+  if (ncollected == 0) {
+    gst_buffer_unmap (outbuf, &write_info);
     goto eos;
+  }
 
   if (self->segment_pending) {
     GstEvent *event;
 
-    event = gst_event_new_new_segment_full (FALSE, self->segment_rate,
-        1.0, GST_FORMAT_TIME, self->timestamp, -1, self->segment_position);
+    self->segment.format = GST_FORMAT_TIME;
+    event = gst_event_new_segment (&self->segment);
 
     gst_pad_push_event (self->src, event);
     self->segment_pending = FALSE;
@@ -1294,6 +1269,8 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self)
   if (empty)
     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
 
+  gst_buffer_unmap (outbuf, &write_info);
+
   GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT,
       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
   ret = gst_pad_push (self->src, outbuf);
@@ -1305,6 +1282,6 @@ eos:
     GST_DEBUG_OBJECT (self, "no data available, must be EOS");
     gst_buffer_unref (outbuf);
     gst_pad_push_event (self->src, gst_event_new_eos ());
-    return GST_FLOW_UNEXPECTED;
+    return GST_FLOW_EOS;
   }
 }