Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst / adder / gstadder.c
index cdf9648..b2e5903 100644 (file)
@@ -46,7 +46,7 @@
 #include "gstadder.h"
 #include <gst/audio/audio.h>
 #include <string.h>             /* strcmp */
-/*#include <liboil/liboil.h>*/
+#include "gstadderorc.h"
 
 /* highest positive/lowest negative x-bit value we can use for clamping */
 #define MAX_INT_32  ((gint32) (0x7fffffff))
@@ -116,8 +116,9 @@ GST_STATIC_PAD_TEMPLATE ("sink%d",
     GST_STATIC_CAPS (CAPS)
     );
 
-static void gst_adder_class_init (GstAdderClass * klass);
-static void gst_adder_init (GstAdder * adder);
+#define gst_adder_parent_class parent_class
+G_DEFINE_TYPE (GstAdder, gst_adder, GST_TYPE_ELEMENT);
+
 static void gst_adder_dispose (GObject * object);
 static void gst_adder_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
@@ -130,7 +131,7 @@ static gboolean gst_adder_src_event (GstPad * pad, GstEvent * event);
 static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
 
 static GstPad *gst_adder_request_new_pad (GstElement * element,
-    GstPadTemplate * temp, const gchar * unused);
+    GstPadTemplate * temp, const gchar * unused, const GstCaps * caps);
 static void gst_adder_release_pad (GstElement * element, GstPad * pad);
 
 static GstStateChangeReturn gst_adder_change_state (GstElement * element,
@@ -141,95 +142,23 @@ static GstBuffer *gst_adder_do_clip (GstCollectPads * pads,
 static GstFlowReturn gst_adder_collected (GstCollectPads * pads,
     gpointer user_data);
 
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_adder_get_type (void)
-{
-  static GType adder_type = 0;
-
-  if (G_UNLIKELY (adder_type == 0)) {
-    static const GTypeInfo adder_info = {
-      sizeof (GstAdderClass), NULL, NULL,
-      (GClassInitFunc) gst_adder_class_init, NULL, NULL,
-      sizeof (GstAdder), 0,
-      (GInstanceInitFunc) gst_adder_init,
-    };
-
-    adder_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAdder",
-        &adder_info, 0);
-    GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "adder", 0,
-        "audio channel mixing element");
-  }
-  return adder_type;
-}
-
-/* clipping versions (for int)
- * FIXME: what about: oil_add_s16 (out, out, in, bytes / sizeof (type))
- */
-#define MAKE_FUNC(name,type,ttype,min,max)                      \
-static void name (type *out, type *in, gint bytes) {            \
-  gint i;                                                       \
-  ttype add;                                                    \
-  for (i = 0; i < bytes / sizeof (type); i++) {                 \
-    add = (ttype)out[i] + (ttype)in[i];                         \
-    out[i] = CLAMP (add, min, max);                             \
-  }                                                             \
-}
-
-/* unsigned versions (for int) */
-#define MAKE_FUNC_US(name,type,ttype,max)                       \
-static void name (type *out, type *in, gint bytes) {            \
-  gint i;                                                       \
-  ttype add;                                                    \
-  for (i = 0; i < bytes / sizeof (type); i++) {                 \
-    add = (ttype)out[i] + (ttype)in[i];                         \
-    out[i] = ((add <= max) ? add : max);                        \
-  }                                                             \
-}
-
 /* non-clipping versions (for float) */
 #define MAKE_FUNC_NC(name,type)                                 \
-static void name (type *out, type *in, gint bytes) {            \
+static void name (type *out, type *in, gint samples) {          \
   gint i;                                                       \
-  for (i = 0; i < bytes / sizeof (type); i++)                   \
+  for (i = 0; i < samples; i++)                                 \
     out[i] += in[i];                                            \
 }
 
-#if 0
-/* right now, the liboil function don't seems to be faster on x86
- * time gst-launch audiotestsrc num-buffers=50000 ! audio/x-raw-float ! adder name=m ! fakesink audiotestsrc num-buffers=50000 ! audio/x-raw-float ! m.
- * time gst-launch audiotestsrc num-buffers=50000 ! audio/x-raw-float,width=32 ! adder name=m ! fakesink audiotestsrc num-buffers=50000 ! audio/x-raw-float,width=32 ! m.
- */
-static void
-add_float32 (gfloat * out, gfloat * in, gint bytes)
-{
-  oil_add_f32 (out, out, in, bytes / sizeof (gfloat));
-}
-
-static void
-add_float64 (gdouble * out, gdouble * in, gint bytes)
-{
-  oil_add_f64 (out, out, in, bytes / sizeof (gdouble));
-}
-#endif
-
 /* *INDENT-OFF* */
-MAKE_FUNC (add_int32, gint32, gint64, MIN_INT_32, MAX_INT_32)
-MAKE_FUNC (add_int16, gint16, gint32, MIN_INT_16, MAX_INT_16)
-MAKE_FUNC (add_int8, gint8, gint16, MIN_INT_8, MAX_INT_8)
-MAKE_FUNC_US (add_uint32, guint32, guint64, MAX_UINT_32)
-MAKE_FUNC_US (add_uint16, guint16, guint32, MAX_UINT_16)
-MAKE_FUNC_US (add_uint8, guint8, guint16, MAX_UINT_8)
 MAKE_FUNC_NC (add_float64, gdouble)
-MAKE_FUNC_NC (add_float32, gfloat)
 /* *INDENT-ON* */
 
 /* we can only accept caps that we and downstream can handle.
  * if we have filtercaps set, use those to constrain the target caps.
  */
 static GstCaps *
-gst_adder_sink_getcaps (GstPad * pad)
+gst_adder_sink_getcaps (GstPad * pad, GstCaps * filter)
 {
   GstAdder *adder;
   GstCaps *result, *peercaps, *sinkcaps, *filter_caps;
@@ -238,27 +167,39 @@ gst_adder_sink_getcaps (GstPad * pad)
 
   GST_OBJECT_LOCK (adder);
   /* take filter */
-  if ((filter_caps = adder->filter_caps))
-    gst_caps_ref (filter_caps);
+  if ((filter_caps = adder->filter_caps)) {
+    if (filter)
+      filter_caps =
+          gst_caps_intersect_full (filter, filter_caps,
+          GST_CAPS_INTERSECT_FIRST);
+    else
+      gst_caps_ref (filter_caps);
+  } else {
+    filter_caps = gst_caps_ref (filter);
+  }
   GST_OBJECT_UNLOCK (adder);
 
+  if (filter_caps && gst_caps_is_empty (filter_caps)) {
+    GST_WARNING_OBJECT (pad, "Empty filter caps");
+    return filter_caps;
+  }
+
   /* get the downstream possible caps */
-  peercaps = gst_pad_peer_get_caps (adder->srcpad);
+  peercaps = gst_pad_peer_get_caps (adder->srcpad, filter_caps);
+
+  /* get the allowed caps on this sinkpad */
+  sinkcaps = gst_pad_get_current_caps (pad);
+  if (sinkcaps == NULL) {
+    sinkcaps = gst_pad_get_pad_template_caps (pad);
+    if (!sinkcaps)
+      sinkcaps = gst_caps_new_any ();
+  }
 
-  /* get the allowed caps on this sinkpad, we use the fixed caps function so
-   * that it does not call recursively in this function. */
-  sinkcaps = gst_pad_get_fixed_caps_func (pad);
   if (peercaps) {
-    /* restrict with filter-caps if any */
-    if (filter_caps) {
-      GST_DEBUG_OBJECT (adder, "filtering peer caps");
-      result = gst_caps_intersect (peercaps, filter_caps);
-      gst_caps_unref (peercaps);
-      peercaps = result;
-    }
     /* if the peer has caps, intersect */
     GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
-    result = gst_caps_intersect (peercaps, sinkcaps);
+    result =
+        gst_caps_intersect_full (peercaps, sinkcaps, GST_CAPS_INTERSECT_FIRST);
     gst_caps_unref (peercaps);
     gst_caps_unref (sinkcaps);
   } else {
@@ -267,7 +208,9 @@ gst_adder_sink_getcaps (GstPad * pad)
     /* restrict with filter-caps if any */
     if (filter_caps) {
       GST_DEBUG_OBJECT (adder, "no peer caps, using filtered sinkcaps");
-      result = gst_caps_intersect (sinkcaps, filter_caps);
+      result =
+          gst_caps_intersect_full (filter_caps, sinkcaps,
+          GST_CAPS_INTERSECT_FIRST);
       gst_caps_unref (sinkcaps);
     } else {
       GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
@@ -284,6 +227,21 @@ gst_adder_sink_getcaps (GstPad * pad)
   return result;
 }
 
+typedef struct
+{
+  GstPad *pad;
+  GstCaps *caps;
+} IterData;
+
+static void
+setcapsfunc (const GValue * item, IterData * data)
+{
+  GstPad *otherpad = g_value_get_object (item);
+
+  if (otherpad != data->pad)
+    gst_pad_set_caps (data->pad, data->caps);
+}
+
 /* the first caps we receive on any of the sinkpads will define the caps for all
  * the other sinkpads because we can only mix streams with the same caps.
  */
@@ -291,28 +249,39 @@ static gboolean
 gst_adder_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstAdder *adder;
-  GList *pads;
   GstStructure *structure;
   const char *media_type;
+  GstIterator *it;
+  GstIteratorResult ires;
+  IterData idata;
+  gboolean done;
 
   adder = GST_ADDER (GST_PAD_PARENT (pad));
 
   GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
       GST_PAD_NAME (pad), caps);
 
+  it = gst_element_iterate_pads (GST_ELEMENT_CAST (adder));
+
   /* FIXME, see if the other pads can accept the format. Also lock the
    * format on the other pads to this new format. */
-  GST_OBJECT_LOCK (adder);
-  pads = GST_ELEMENT (adder)->pads;
-  while (pads) {
-    GstPad *otherpad = GST_PAD (pads->data);
+  idata.caps = caps;
+  idata.pad = pad;
+
+  done = FALSE;
+  while (!done) {
+    ires = gst_iterator_foreach (it, (GstIteratorForeachFunction) setcapsfunc,
+        &idata);
 
-    if (otherpad != pad) {
-      gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
+    switch (ires) {
+      case GST_ITERATOR_RESYNC:
+        gst_iterator_resync (it);
+        break;
+      default:
+        done = TRUE;
+        break;
     }
-    pads = g_list_next (pads);
   }
-  GST_OBJECT_UNLOCK (adder);
 
   /* parse caps now */
   structure = gst_caps_get_structure (caps, 0);
@@ -334,14 +303,17 @@ gst_adder_setcaps (GstPad * pad, GstCaps * caps)
       case 8:
         adder->func = (adder->is_signed ?
             (GstAdderFunction) add_int8 : (GstAdderFunction) add_uint8);
+        adder->sample_size = 1;
         break;
       case 16:
         adder->func = (adder->is_signed ?
             (GstAdderFunction) add_int16 : (GstAdderFunction) add_uint16);
+        adder->sample_size = 2;
         break;
       case 32:
         adder->func = (adder->is_signed ?
             (GstAdderFunction) add_int32 : (GstAdderFunction) add_uint32);
+        adder->sample_size = 4;
         break;
       default:
         goto not_supported;
@@ -360,9 +332,11 @@ gst_adder_setcaps (GstPad * pad, GstCaps * caps)
     switch (adder->width) {
       case 32:
         adder->func = (GstAdderFunction) add_float32;
+        adder->sample_size = 4;
         break;
       case 64:
         adder->func = (GstAdderFunction) add_float64;
+        adder->sample_size = 8;
         break;
       default:
         goto not_supported;
@@ -410,6 +384,7 @@ gst_adder_query_duration (GstAdder * adder, GstQuery * query)
   GstFormat format;
   GstIterator *it;
   gboolean done;
+  GValue item = { 0, };
 
   /* parse format */
   gst_query_parse_duration (query, &format, NULL);
@@ -422,8 +397,6 @@ gst_adder_query_duration (GstAdder * adder, GstQuery * query)
   while (!done) {
     GstIteratorResult ires;
 
-    gpointer item;
-
     ires = gst_iterator_next (it, &item);
     switch (ires) {
       case GST_ITERATOR_DONE:
@@ -431,8 +404,7 @@ gst_adder_query_duration (GstAdder * adder, GstQuery * query)
         break;
       case GST_ITERATOR_OK:
       {
-        GstPad *pad = GST_PAD_CAST (item);
-
+        GstPad *pad = g_value_get_object (&item);
         gint64 duration;
 
         /* ask sink peer for duration */
@@ -448,7 +420,7 @@ gst_adder_query_duration (GstAdder * adder, GstQuery * query)
           else if (duration > max)
             max = duration;
         }
-        gst_object_unref (pad);
+        g_value_reset (&item);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -462,6 +434,7 @@ gst_adder_query_duration (GstAdder * adder, GstQuery * query)
         break;
     }
   }
+  g_value_unset (&item);
   gst_iterator_free (it);
 
   if (res) {
@@ -482,6 +455,7 @@ gst_adder_query_latency (GstAdder * adder, GstQuery * query)
   gboolean res;
   GstIterator *it;
   gboolean done;
+  GValue item = { 0, };
 
   res = TRUE;
   done = FALSE;
@@ -495,8 +469,6 @@ gst_adder_query_latency (GstAdder * adder, GstQuery * query)
   while (!done) {
     GstIteratorResult ires;
 
-    gpointer item;
-
     ires = gst_iterator_next (it, &item);
     switch (ires) {
       case GST_ITERATOR_DONE:
@@ -504,7 +476,7 @@ gst_adder_query_latency (GstAdder * adder, GstQuery * query)
         break;
       case GST_ITERATOR_OK:
       {
-        GstPad *pad = GST_PAD_CAST (item);
+        GstPad *pad = g_value_get_object (&item);
         GstQuery *peerquery;
         GstClockTime min_cur, max_cur;
         gboolean live_cur;
@@ -530,7 +502,7 @@ gst_adder_query_latency (GstAdder * adder, GstQuery * query)
         }
 
         gst_query_unref (peerquery);
-        gst_object_unref (pad);
+        g_value_reset (&item);
         break;
       }
       case GST_ITERATOR_RESYNC:
@@ -546,6 +518,7 @@ gst_adder_query_latency (GstAdder * adder, GstQuery * query)
         break;
     }
   }
+  g_value_unset (&item);
   gst_iterator_free (it);
 
   if (res) {
@@ -575,7 +548,7 @@ gst_adder_query (GstPad * pad, GstQuery * query)
       switch (format) {
         case GST_FORMAT_TIME:
           /* FIXME, bring to stream time, might be tricky */
-          gst_query_set_position (query, format, adder->timestamp);
+          gst_query_set_position (query, format, adder->segment.position);
           res = TRUE;
           break;
         case GST_FORMAT_DEFAULT:
@@ -611,8 +584,9 @@ typedef struct
 } EventData;
 
 static gboolean
-forward_event_func (GstPad * pad, GValue * ret, EventData * data)
+forward_event_func (const GValue * val, GValue * ret, EventData * data)
 {
+  GstPad *pad = g_value_get_object (val);
   GstEvent *event = data->event;
 
   gst_event_ref (event);
@@ -629,7 +603,6 @@ forward_event_func (GstPad * pad, GValue * ret, EventData * data)
     GST_LOG_OBJECT (pad, "Sent event  %p (%s).",
         event, GST_EVENT_TYPE_NAME (event));
   }
-  gst_object_unref (pad);
 
   /* continue on other pads, even if one failed */
   return TRUE;
@@ -660,7 +633,8 @@ forward_event (GstAdder * adder, GstEvent * event, gboolean flush)
   g_value_set_boolean (&vret, FALSE);
   it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
   while (TRUE) {
-    ires = gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
+    ires =
+        gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
         &vret, &data);
     switch (ires) {
       case GST_ITERATOR_RESYNC:
@@ -698,14 +672,28 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
     case GST_EVENT_SEEK:
     {
       GstSeekFlags flags;
+      gdouble rate;
       GstSeekType curtype, endtype;
       gint64 cur, end;
       gboolean flush;
 
       /* parse the seek parameters */
-      gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
+      gst_event_parse_seek (event, &rate, NULL, &flags, &curtype,
           &cur, &endtype, &end);
 
+      if ((curtype != GST_SEEK_TYPE_NONE) && (curtype != GST_SEEK_TYPE_SET)) {
+        result = FALSE;
+        GST_DEBUG_OBJECT (adder,
+            "seeking failed, unhandled seek type for start: %d", curtype);
+        goto done;
+      }
+      if ((endtype != GST_SEEK_TYPE_NONE) && (endtype != GST_SEEK_TYPE_SET)) {
+        result = FALSE;
+        GST_DEBUG_OBJECT (adder,
+            "seeking failed, unhandled seek type for end: %d", endtype);
+        goto done;
+      }
+
       flush = (flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH;
 
       /* check if we are flushing */
@@ -716,6 +704,14 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
         /* flushing seek, start flush downstream, the flush will be done
          * when all pads received a FLUSH_STOP. */
         gst_pad_push_event (adder->srcpad, gst_event_new_flush_start ());
+
+        /* We can't send FLUSH_STOP here since upstream could start pushing data
+         * after we unlock adder->collect.
+         * We set flush_stop_pending to TRUE instead and send FLUSH_STOP after
+         * forwarding the seek upstream or from gst_adder_collected,
+         * whichever happens first.
+         */
+        adder->flush_stop_pending = TRUE;
       }
       GST_DEBUG_OBJECT (adder, "handling seek event: %" GST_PTR_FORMAT, event);
 
@@ -723,14 +719,15 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
        * segment. After we have the lock, no collect function is running and no
        * new collect function will be called for as long as we're flushing. */
       GST_OBJECT_LOCK (adder->collect);
+      adder->segment.rate = rate;
       if (curtype == GST_SEEK_TYPE_SET)
-        adder->segment_start = cur;
+        adder->segment.start = cur;
       else
-        adder->segment_start = 0;
+        adder->segment.start = 0;
       if (endtype == GST_SEEK_TYPE_SET)
-        adder->segment_end = end;
+        adder->segment.stop = end;
       else
-        adder->segment_end = GST_CLOCK_TIME_NONE;
+        adder->segment.stop = GST_CLOCK_TIME_NONE;
       /* make sure we push a new segment, to inform about new basetime
        * see FIXME in gst_adder_collected() */
       adder->segment_pending = TRUE;
@@ -739,10 +736,6 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
          * have stopped so that the cookie gets properly updated. */
         gst_collect_pads_set_flushing (adder->collect, TRUE);
       }
-      /* we might have a pending flush_stop event now. This event will either be
-       * sent by an upstream element when it completes the seek or we will push
-       * one in the collected callback ourself */
-      adder->flush_stop_pending = flush;
       GST_OBJECT_UNLOCK (adder->collect);
       GST_DEBUG_OBJECT (adder, "forwarding seek event: %" GST_PTR_FORMAT,
           event);
@@ -752,10 +745,11 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
         /* seek failed. maybe source is a live source. */
         GST_DEBUG_OBJECT (adder, "seeking failed");
       }
-      /* FIXME: ideally we would like to send a flush-stop event from here but
-       * collectpads does not have a method that allows us to do that. Instead
-       * we forward all flush-stop events we receive on the sinkpads. We might
-       * be sending too many flush-stop events. */
+      if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
+              TRUE, FALSE)) {
+        GST_DEBUG_OBJECT (adder, "pending flush stop");
+        gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ());
+      }
       break;
     }
     case GST_EVENT_QOS:
@@ -773,6 +767,8 @@ gst_adder_src_event (GstPad * pad, GstEvent * event)
       result = forward_event (adder, event, FALSE);
       break;
   }
+
+done:
   gst_object_unref (adder);
 
   return result;
@@ -837,17 +833,6 @@ gst_adder_class_init (GstAdderClass * klass)
   gobject_class->get_property = gst_adder_get_property;
   gobject_class->dispose = gst_adder_dispose;
 
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_adder_src_template));
-  gst_element_class_add_pad_template (gstelement_class,
-      gst_static_pad_template_get (&gst_adder_sink_template));
-  gst_element_class_set_details_simple (gstelement_class, "Adder",
-      "Generic/Audio",
-      "Add N audio channels together",
-      "Thomas Vander Stichele <thomas at apestaart dot org>");
-
-  parent_class = g_type_class_peek_parent (klass);
-
   /**
    * GstAdder:caps:
    *
@@ -860,6 +845,15 @@ gst_adder_class_init (GstAdderClass * klass)
           "object.", GST_TYPE_CAPS,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_adder_src_template));
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&gst_adder_sink_template));
+  gst_element_class_set_details_simple (gstelement_class, "Adder",
+      "Generic/Audio",
+      "Add N audio channels together",
+      "Thomas Vander Stichele <thomas at apestaart dot org>");
+
   gstelement_class->request_new_pad =
       GST_DEBUG_FUNCPTR (gst_adder_request_new_pad);
   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_adder_release_pad);
@@ -973,7 +967,7 @@ gst_adder_get_property (GObject * object, guint prop_id, GValue * value,
 
 static GstPad *
 gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
-    const gchar * unused)
+    const gchar * unused, const GstCaps * caps)
 {
   gchar *name;
   GstAdder *adder;
@@ -986,7 +980,11 @@ gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
   adder = GST_ADDER (element);
 
   /* increment pad counter */
+#if GLIB_CHECK_VERSION(2,29,5)
+  padcount = g_atomic_int_add (&adder->padcount, 1);
+#else
   padcount = g_atomic_int_exchange_and_add (&adder->padcount, 1);
+#endif
 
   name = g_strdup_printf ("sink%d", padcount);
   newpad = gst_pad_new_from_template (templ, name);
@@ -1084,9 +1082,10 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
   if (G_UNLIKELY (adder->func == NULL))
     goto not_negotiated;
 
-  if (adder->flush_stop_pending) {
+  if (g_atomic_int_compare_and_exchange (&adder->flush_stop_pending,
+          TRUE, FALSE)) {
+    GST_DEBUG_OBJECT (adder, "pending flush stop");
     gst_pad_push_event (adder->srcpad, gst_event_new_flush_stop ());
-    adder->flush_stop_pending = FALSE;
   }
 
   /* get available bytes for reading, this can be 0 which could mean empty
@@ -1140,20 +1139,15 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
 
       GST_LOG_OBJECT (adder, "channel %p: preparing output buffer of %d bytes",
           collect_data, outsize);
-      /* make data and metadata writable, can simply return the inbuf when we
-       * are the only one referencing this buffer. If this is the last (and
-       * only) GAP buffer, it will automatically copy the GAP flag. */
-      outbuf = gst_buffer_make_writable (inbuf);
-      outdata = GST_BUFFER_DATA (outbuf);
-      gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
+
+      outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
     } else {
       if (!is_gap) {
         /* we had a previous output buffer, mix this non-GAP buffer */
         guint8 *indata;
-        guint insize;
+        gsize insize;
 
-        indata = GST_BUFFER_DATA (inbuf);
-        insize = GST_BUFFER_SIZE (inbuf);
+        indata = gst_buffer_map (inbuf, &insize, NULL, GST_MAP_READ);
 
         /* all buffers should have outsize, there are no short buffers because we
          * asked for the max size above */
@@ -1163,7 +1157,9 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
             collect_data, insize, indata);
 
         /* further buffers, need to add them */
-        adder->func ((gpointer) outdata, (gpointer) indata, insize);
+        adder->func ((gpointer) outdata, (gpointer) indata,
+            insize / adder->sample_size);
+        gst_buffer_unmap (inbuf, indata, insize);
       } else {
         /* skip gap buffer */
         GST_LOG_OBJECT (adder, "channel %p: skipping GAP buffer", collect_data);
@@ -1171,6 +1167,8 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
       gst_buffer_unref (inbuf);
     }
   }
+  if (outbuf)
+    gst_buffer_unmap (outbuf, outdata, outsize);
 
   if (outbuf == NULL) {
     /* no output buffer, reuse one of the GAP buffers then if we have one */
@@ -1194,20 +1192,19 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
      * event. We also adjust offset & timestamp acordingly.
      * This basically ignores all newsegments sent by upstream.
      */
-    event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
-        1.0, GST_FORMAT_TIME, adder->segment_start, adder->segment_end,
-        adder->segment_start);
-    if (adder->segment_rate > 0.0) {
-      adder->timestamp = adder->segment_start;
+    event = gst_event_new_segment (&adder->segment);
+
+    if (adder->segment.rate > 0.0) {
+      adder->segment.position = adder->segment.start;
     } else {
-      adder->timestamp = adder->segment_end;
+      adder->segment.position = adder->segment.stop;
     }
-    adder->offset = gst_util_uint64_scale (adder->timestamp,
+    adder->offset = gst_util_uint64_scale (adder->segment.position,
         adder->rate, GST_SECOND);
     GST_INFO_OBJECT (adder, "seg_start %" G_GUINT64_FORMAT ", seg_end %"
-        G_GUINT64_FORMAT, adder->segment_start, adder->segment_end);
+        G_GUINT64_FORMAT, adder->segment.start, adder->segment.stop);
     GST_INFO_OBJECT (adder, "timestamp %" G_GINT64_FORMAT ",new offset %"
-        G_GINT64_FORMAT, adder->timestamp, adder->offset);
+        G_GINT64_FORMAT, adder->segment.position, adder->offset);
 
     if (event) {
       if (!gst_pad_push_event (adder->srcpad, event)) {
@@ -1218,7 +1215,7 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
     } else {
       GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for "
           "start:%" G_GINT64_FORMAT "  end:%" G_GINT64_FORMAT " failed",
-          adder->segment_start, adder->segment_end);
+          adder->segment.start, adder->segment.stop);
     }
   }
 
@@ -1237,7 +1234,7 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
 
   /* for the next timestamp, use the sample counter, which will
    * never accumulate rounding errors */
-  if (adder->segment_rate > 0.0) {
+  if (adder->segment.rate > 0.0) {
     next_offset = adder->offset + outsize / adder->bps;
   } else {
     next_offset = adder->offset - outsize / adder->bps;
@@ -1246,18 +1243,20 @@ gst_adder_collected (GstCollectPads * pads, gpointer user_data)
 
 
   /* set timestamps on the output buffer */
-  if (adder->segment_rate > 0.0) {
-    GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
+  if (adder->segment.rate > 0.0) {
+    GST_BUFFER_TIMESTAMP (outbuf) = adder->segment.position;
     GST_BUFFER_OFFSET (outbuf) = adder->offset;
-    GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->timestamp;
+    GST_BUFFER_OFFSET_END (outbuf) = next_offset;
+    GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->segment.position;
   } else {
     GST_BUFFER_TIMESTAMP (outbuf) = next_timestamp;
     GST_BUFFER_OFFSET (outbuf) = next_offset;
-    GST_BUFFER_DURATION (outbuf) = adder->timestamp - next_timestamp;
+    GST_BUFFER_OFFSET_END (outbuf) = adder->offset;
+    GST_BUFFER_DURATION (outbuf) = adder->segment.position - next_timestamp;
   }
 
   adder->offset = next_offset;
-  adder->timestamp = next_timestamp;
+  adder->segment.position = next_timestamp;
 
   /* send it out */
   GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT
@@ -1297,14 +1296,11 @@ gst_adder_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      adder->timestamp = 0;
+      adder->segment.position = 0;
       adder->offset = 0;
       adder->flush_stop_pending = FALSE;
       adder->segment_pending = TRUE;
-      adder->segment_start = 0;
-      adder->segment_end = GST_CLOCK_TIME_NONE;
-      adder->segment_rate = 1.0;
-      gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
+      gst_segment_init (&adder->segment, GST_FORMAT_TIME);
       gst_collect_pads_start (adder->collect);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
@@ -1332,7 +1328,10 @@ gst_adder_change_state (GstElement * element, GstStateChange transition)
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  /*oil_init (); */
+  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "adder", 0,
+      "audio channel mixing element");
+
+  gst_adder_orc_init ();
 
   if (!gst_element_register (plugin, "adder", GST_RANK_NONE, GST_TYPE_ADDER)) {
     return FALSE;