Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / libs / gst / base / gstbasesink.c
index d60ba6f..e94a1e2 100644 (file)
  *
  * #GstBaseSink provides support for exactly one sink pad, which should be
  * named "sink". A sink implementation (subclass of #GstBaseSink) should
- * install a pad template in its base_init function, like so:
+ * install a pad template in its class_init function, like so:
  * |[
  * static void
- * my_element_base_init (gpointer g_class)
+ * my_element_class_init (GstMyElementClass *klass)
  * {
- *   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ *   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
  *
  *   // sinktemplate should be a #GstStaticPadTemplate with direction
  *   // #GST_PAD_SINK and name "sink"
  * very specific elements (such as file sinks) which need to handle the
  * newsegment event specially.
  *
- * #GstBaseSink provides an overridable #GstBaseSinkClass.buffer_alloc()
- * function that can be used by sinks that want to do reverse negotiation or to
- * provide custom buffers (hardware buffers for example) to upstream elements.
- *
  * The #GstBaseSinkClass.unlock() method is called when the elements should
  * unblock any blocking operations they perform in the
  * #GstBaseSinkClass.render() method. This is mostly useful when the
@@ -231,6 +227,8 @@ struct _GstBaseSinkPrivate
 
   /* if we already commited the state */
   gboolean commited;
+  /* state change to playing ongoing */
+  gboolean to_playing;
 
   /* when we received EOS */
   gboolean received_eos;
@@ -266,6 +264,8 @@ struct _GstBaseSinkPrivate
   /* for throttling and QoS */
   GstClockTime earliest_in_time;
   GstClockTime throttle_time;
+
+  gboolean reset_time;
 };
 
 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
@@ -364,13 +364,11 @@ static void gst_base_sink_get_property (GObject * object, guint prop_id,
 
 static gboolean gst_base_sink_send_event (GstElement * element,
     GstEvent * event);
-static gboolean gst_base_sink_query (GstElement * element, GstQuery * query);
+static gboolean default_element_query (GstElement * element, GstQuery * query);
 static const GstQueryType *gst_base_sink_get_query_types (GstElement * element);
 
-static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
+static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink, GstCaps * caps);
 static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
-static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink,
-    guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
 static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
     GstClockTime * start, GstClockTime * end);
 static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
@@ -385,6 +383,7 @@ static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
     GstStateChange transition);
 
+static gboolean gst_base_sink_sink_query (GstPad * pad, GstQuery * query);
 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
 static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
     GstBufferList * list);
@@ -395,13 +394,11 @@ static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active);
 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
 
+static gboolean default_sink_query (GstBaseSink * sink, GstQuery * query);
+
 static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
-static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad);
-static gboolean gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad, GstCaps * filter);
 static void gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps);
-static GstFlowReturn gst_base_sink_pad_buffer_alloc (GstPad * pad,
-    guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
-
 
 /* check if an object was too late */
 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
@@ -505,7 +502,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
    * Since: 0.10.15
    */
   g_object_class_install_property (gobject_class, PROP_LAST_BUFFER,
-      gst_param_spec_mini_object ("last-buffer", "Last Buffer",
+      g_param_spec_boxed ("last-buffer", "Last Buffer",
           "The last buffer received in the sink", GST_TYPE_BUFFER,
           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   /**
@@ -550,22 +547,20 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
-  gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query);
+  gstelement_class->query = GST_DEBUG_FUNCPTR (default_element_query);
   gstelement_class->get_query_types =
       GST_DEBUG_FUNCPTR (gst_base_sink_get_query_types);
 
   klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
   klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
-  klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
   klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
   klass->activate_pull =
       GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull);
+  klass->query = GST_DEBUG_FUNCPTR (default_sink_query);
 
   /* Registering debug symbols for function pointers */
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_getcaps);
-  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_setcaps);
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_fixate);
-  GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_buffer_alloc);
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate);
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_push);
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_pull);
@@ -575,7 +570,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
 }
 
 static GstCaps *
-gst_base_sink_pad_getcaps (GstPad * pad)
+gst_base_sink_pad_getcaps (GstPad * pad, GstCaps * filter)
 {
   GstBaseSinkClass *bclass;
   GstBaseSink *bsink;
@@ -586,14 +581,11 @@ gst_base_sink_pad_getcaps (GstPad * pad)
 
   if (bsink->pad_mode == GST_ACTIVATE_PULL) {
     /* if we are operating in pull mode we only accept the negotiated caps */
-    GST_OBJECT_LOCK (pad);
-    if ((caps = GST_PAD_CAPS (pad)))
-      gst_caps_ref (caps);
-    GST_OBJECT_UNLOCK (pad);
+    caps = gst_pad_get_current_caps (pad);
   }
   if (caps == NULL) {
     if (bclass->get_caps)
-      caps = bclass->get_caps (bsink);
+      caps = bclass->get_caps (bsink, filter);
 
     if (caps == NULL) {
       GstPadTemplate *pad_template;
@@ -602,7 +594,16 @@ gst_base_sink_pad_getcaps (GstPad * pad)
           gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass),
           "sink");
       if (pad_template != NULL) {
-        caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
+        caps = gst_pad_template_get_caps (pad_template);
+
+        if (filter) {
+          GstCaps *intersection;
+
+          intersection =
+              gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+          gst_caps_unref (caps);
+          caps = intersection;
+        }
       }
     }
   }
@@ -611,24 +612,6 @@ gst_base_sink_pad_getcaps (GstPad * pad)
   return caps;
 }
 
-static gboolean
-gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps)
-{
-  GstBaseSinkClass *bclass;
-  GstBaseSink *bsink;
-  gboolean res = TRUE;
-
-  bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
-  bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
-  if (res && bclass->set_caps)
-    res = bclass->set_caps (bsink, caps);
-
-  gst_object_unref (bsink);
-
-  return res;
-}
-
 static void
 gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps)
 {
@@ -644,29 +627,6 @@ gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps)
   gst_object_unref (bsink);
 }
 
-static GstFlowReturn
-gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
-    GstCaps * caps, GstBuffer ** buf)
-{
-  GstBaseSinkClass *bclass;
-  GstBaseSink *bsink;
-  GstFlowReturn result = GST_FLOW_OK;
-
-  bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
-  if (G_UNLIKELY (bsink == NULL))
-    return GST_FLOW_WRONG_STATE;
-  bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
-  if (bclass->buffer_alloc)
-    result = bclass->buffer_alloc (bsink, offset, size, caps, buf);
-  else
-    *buf = NULL;                /* fallback in gstpad.c will allocate generic buffer */
-
-  gst_object_unref (bsink);
-
-  return result;
-}
-
 static void
 gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
 {
@@ -682,30 +642,29 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
   basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
 
   gst_pad_set_getcaps_function (basesink->sinkpad, gst_base_sink_pad_getcaps);
-  gst_pad_set_setcaps_function (basesink->sinkpad, gst_base_sink_pad_setcaps);
   gst_pad_set_fixatecaps_function (basesink->sinkpad, gst_base_sink_pad_fixate);
-  gst_pad_set_bufferalloc_function (basesink->sinkpad,
-      gst_base_sink_pad_buffer_alloc);
   gst_pad_set_activate_function (basesink->sinkpad, gst_base_sink_pad_activate);
   gst_pad_set_activatepush_function (basesink->sinkpad,
       gst_base_sink_pad_activate_push);
   gst_pad_set_activatepull_function (basesink->sinkpad,
       gst_base_sink_pad_activate_pull);
+  gst_pad_set_query_function (basesink->sinkpad, gst_base_sink_sink_query);
   gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event);
   gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain);
   gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list);
   gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
 
   basesink->pad_mode = GST_ACTIVATE_NONE;
+  basesink->preroll_lock = g_mutex_new ();
+  basesink->preroll_cond = g_cond_new ();
   basesink->preroll_queue = g_queue_new ();
-  basesink->abidata.ABI.clip_segment = gst_segment_new ();
   priv->have_latency = FALSE;
 
   basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
   basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
 
   basesink->sync = DEFAULT_SYNC;
-  basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS;
+  basesink->max_lateness = DEFAULT_MAX_LATENESS;
   g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
   priv->async_enabled = DEFAULT_ASYNC;
   priv->ts_offset = DEFAULT_TS_OFFSET;
@@ -725,8 +684,9 @@ gst_base_sink_finalize (GObject * object)
 
   basesink = GST_BASE_SINK (object);
 
+  g_mutex_free (basesink->preroll_lock);
+  g_cond_free (basesink->preroll_cond);
   g_queue_free (basesink->preroll_queue);
-  gst_segment_free (basesink->abidata.ABI.clip_segment);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -797,7 +757,7 @@ gst_base_sink_set_max_lateness (GstBaseSink * sink, gint64 max_lateness)
   g_return_if_fail (GST_IS_BASE_SINK (sink));
 
   GST_OBJECT_LOCK (sink);
-  sink->abidata.ABI.max_lateness = max_lateness;
+  sink->max_lateness = max_lateness;
   GST_OBJECT_UNLOCK (sink);
 }
 
@@ -822,7 +782,7 @@ gst_base_sink_get_max_lateness (GstBaseSink * sink)
   g_return_val_if_fail (GST_IS_BASE_SINK (sink), -1);
 
   GST_OBJECT_LOCK (sink);
-  res = sink->abidata.ABI.max_lateness;
+  res = sink->max_lateness;
   GST_OBJECT_UNLOCK (sink);
 
   return res;
@@ -885,10 +845,10 @@ gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled)
 {
   g_return_if_fail (GST_IS_BASE_SINK (sink));
 
-  GST_PAD_PREROLL_LOCK (sink->sinkpad);
+  GST_BASE_SINK_PREROLL_LOCK (sink);
   g_atomic_int_set (&sink->priv->async_enabled, enabled);
   GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
-  GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+  GST_BASE_SINK_PREROLL_UNLOCK (sink);
 }
 
 /**
@@ -1364,9 +1324,9 @@ gst_base_sink_set_property (GObject * object, guint prop_id,
   switch (prop_id) {
     case PROP_PREROLL_QUEUE_LEN:
       /* preroll lock necessary to serialize with finish_preroll */
-      GST_PAD_PREROLL_LOCK (sink->sinkpad);
+      GST_BASE_SINK_PREROLL_LOCK (sink);
       g_atomic_int_set (&sink->preroll_queue_max_len, g_value_get_uint (value));
-      GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+      GST_BASE_SINK_PREROLL_UNLOCK (sink);
       break;
     case PROP_SYNC:
       gst_base_sink_set_sync (sink, g_value_get_boolean (value));
@@ -1449,7 +1409,7 @@ gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
 
 
 static GstCaps *
-gst_base_sink_get_caps (GstBaseSink * sink)
+gst_base_sink_get_caps (GstBaseSink * sink, GstCaps * filter)
 {
   return NULL;
 }
@@ -1460,14 +1420,6 @@ gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
   return TRUE;
 }
 
-static GstFlowReturn
-gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
-    GstCaps * caps, GstBuffer ** buf)
-{
-  *buf = NULL;
-  return GST_FLOW_OK;
-}
-
 /* with PREROLL_LOCK, STREAM_LOCK */
 static void
 gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
@@ -1495,7 +1447,7 @@ gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
     GST_OBJECT_UNLOCK (basesink);
   }
   /* and signal any waiters now */
-  GST_PAD_PREROLL_SIGNAL (pad);
+  GST_BASE_SINK_PREROLL_SIGNAL (basesink);
 }
 
 /* with STREAM_LOCK, configures given segment with the event information. */
@@ -1503,43 +1455,15 @@ static void
 gst_base_sink_configure_segment (GstBaseSink * basesink, GstPad * pad,
     GstEvent * event, GstSegment * segment)
 {
-  gboolean update;
-  gdouble rate, arate;
-  GstFormat format;
-  gint64 start;
-  gint64 stop;
-  gint64 time;
-
-  /* the newsegment event is needed to bring the buffer timestamps to the
-   * stream time and to drop samples outside of the playback segment. */
-  gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
-      &start, &stop, &time);
-
   /* The segment is protected with both the STREAM_LOCK and the OBJECT_LOCK.
    * We protect with the OBJECT_LOCK so that we can use the values to
    * safely answer a POSITION query. */
   GST_OBJECT_LOCK (basesink);
-  gst_segment_set_newsegment_full (segment, update, rate, arate, format, start,
-      stop, time);
-
-  if (format == GST_FORMAT_TIME) {
-    GST_DEBUG_OBJECT (basesink,
-        "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
-        "format GST_FORMAT_TIME, "
-        "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
-        ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
-        update, rate, arate, GST_TIME_ARGS (segment->start),
-        GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
-        GST_TIME_ARGS (segment->accum));
-  } else {
-    GST_DEBUG_OBJECT (basesink,
-        "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
-        "format %d, "
-        "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
-        G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate,
-        segment->format, segment->start, segment->stop, segment->time,
-        segment->accum);
-  }
+  /* the newsegment event is needed to bring the buffer timestamps to the
+   * stream time and to drop samples outside of the playback segment. */
+  gst_event_copy_segment (event, segment);
+  GST_DEBUG_OBJECT (basesink, "configured SEGMENT %" GST_SEGMENT_FORMAT,
+      segment);
   GST_OBJECT_UNLOCK (basesink);
 }
 
@@ -1552,6 +1476,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
   gboolean post_paused = FALSE;
   gboolean post_async_done = FALSE;
   gboolean post_playing = FALSE;
+  gboolean reset_time;
 
   /* we are certainly not playing async anymore now */
   basesink->playing_async = FALSE;
@@ -1561,15 +1486,12 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
   next = GST_STATE_NEXT (basesink);
   pending = GST_STATE_PENDING (basesink);
   post_pending = pending;
+  reset_time = basesink->priv->reset_time;
+  basesink->priv->reset_time = FALSE;
 
   switch (pending) {
     case GST_STATE_PLAYING:
     {
-      GstBaseSinkClass *bclass;
-      GstStateChangeReturn ret;
-
-      bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
       GST_DEBUG_OBJECT (basesink, "commiting state to PLAYING");
 
       basesink->need_preroll = FALSE;
@@ -1580,14 +1502,6 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
       if (current == GST_STATE_READY) {
         post_paused = TRUE;
       }
-
-      /* make sure we notify the subclass of async playing */
-      if (bclass->async_play) {
-        GST_WARNING_OBJECT (basesink, "deprecated async_play");
-        ret = bclass->async_play (basesink);
-        if (ret == GST_STATE_CHANGE_FAILURE)
-          goto async_failed;
-      }
       break;
     }
     case GST_STATE_PAUSED:
@@ -1624,7 +1538,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
   if (post_async_done) {
     GST_DEBUG_OBJECT (basesink, "posting async-done message");
     gst_element_post_message (GST_ELEMENT_CAST (basesink),
-        gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+        gst_message_new_async_done (GST_OBJECT_CAST (basesink), reset_time));
   }
   if (post_playing) {
     GST_DEBUG_OBJECT (basesink, "posting PLAYING state change message");
@@ -1672,13 +1586,6 @@ stopping:
     GST_OBJECT_UNLOCK (basesink);
     return FALSE;
   }
-async_failed:
-  {
-    GST_DEBUG_OBJECT (basesink, "async commit failed");
-    GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_FAILURE;
-    GST_OBJECT_UNLOCK (basesink);
-    return FALSE;
-  }
 }
 
 static void
@@ -1709,7 +1616,6 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
   /* set the new rate for the remainder of the segment */
   current->start_rate = segment->rate;
   segment->rate *= current->rate;
-  segment->abs_rate = ABS (segment->rate);
 
   /* save values */
   if (segment->rate > 0.0)
@@ -1723,27 +1629,19 @@ start_stepping (GstBaseSink * sink, GstSegment * segment,
       /* update the segment clipping regions for non-flushing seeks */
       if (segment->rate > 0.0) {
         segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
-        segment->last_stop = segment->stop;
+        segment->position = segment->stop;
       } else {
         gint64 position;
 
         position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
         segment->time = position;
         segment->start = position;
-        segment->last_stop = position;
+        segment->position = position;
       }
     }
   }
 
-  GST_DEBUG_OBJECT (sink,
-      "segment now rate %lf, applied rate %lf, "
-      "format GST_FORMAT_TIME, "
-      "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
-      ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
-      segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start),
-      GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
-      GST_TIME_ARGS (segment->accum));
-
+  GST_DEBUG_OBJECT (sink, "segment now %" GST_SEGMENT_FORMAT, segment);
   GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
       GST_TIME_ARGS (current->start));
 
@@ -1788,8 +1686,8 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
   gst_segment_set_running_time (segment, GST_FORMAT_TIME, position);
 
   if (current->flush) {
-    /* and remove the accumulated time we flushed, start time did not change */
-    segment->accum = current->start;
+    /* and remove the time we flushed, start time did not change */
+    segment->base = current->start;
   } else {
     /* start time is now the stepped position */
     gst_element_set_start_time (GST_ELEMENT_CAST (sink), position);
@@ -1797,7 +1695,6 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
 
   /* restore the previous rate */
   segment->rate = current->start_rate;
-  segment->abs_rate = ABS (segment->rate);
 
   if (segment->rate > 0.0)
     segment->stop = current->start_stop;
@@ -1805,7 +1702,7 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
     segment->start = current->start_start;
 
   /* the clip segment is used for position report in paused... */
-  memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment));
+  gst_segment_copy_into (segment, &sink->clip_segment);
 
   /* post the step done when we know the stepped duration in TIME */
   message =
@@ -1824,8 +1721,8 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
 
 static gboolean
 handle_stepping (GstBaseSink * sink, GstSegment * segment,
-    GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart,
-    gint64 * rstop)
+    GstStepInfo * current, guint64 * cstart, guint64 * cstop, guint64 * rstart,
+    guint64 * rstop)
 {
   gboolean step_end = FALSE;
 
@@ -1834,7 +1731,8 @@ handle_stepping (GstBaseSink * sink, GstSegment * segment,
     case GST_FORMAT_TIME:
     {
       guint64 end;
-      gint64 first, last;
+      guint64 first, last;
+      gdouble abs_rate;
 
       if (segment->rate > 0.0) {
         if (segment->stop == *cstop)
@@ -1853,8 +1751,9 @@ handle_stepping (GstBaseSink * sink, GstSegment * segment,
       end = current->start + current->amount;
       current->position = first - current->start;
 
-      if (G_UNLIKELY (segment->abs_rate != 1.0))
-        current->position /= segment->abs_rate;
+      abs_rate = ABS (segment->rate);
+      if (G_UNLIKELY (abs_rate != 1.0))
+        current->position /= abs_rate;
 
       GST_DEBUG_OBJECT (sink,
           "buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
@@ -1924,8 +1823,8 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
   GstBaseSinkClass *bclass;
   GstBuffer *buffer;
   GstClockTime start, stop;     /* raw start/stop timestamps */
-  gint64 cstart, cstop;         /* clipped raw timestamps */
-  gint64 rstart, rstop;         /* clipped timestamps converted to running time */
+  guint64 cstart, cstop;        /* clipped raw timestamps */
+  guint64 rstart, rstop;        /* clipped timestamps converted to running time */
   GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */
   GstFormat format;
   GstBaseSinkPrivate *priv;
@@ -1970,11 +1869,6 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
       }
       default:
         /* other events do not need syncing */
-        /* FIXME, maybe NEWSEGMENT might need synchronisation
-         * since the POSITION query depends on accumulated times and
-         * we cannot accumulate the current segment before the previous
-         * one completed.
-         */
         return FALSE;
     }
   }
@@ -2008,19 +1902,9 @@ again:
   /* collect segment and format for code clarity */
   format = segment->format;
 
-  /* no timestamp clipping if we did not get a TIME segment format */
-  if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
-    cstart = start;
-    cstop = stop;
-    /* do running and stream time in TIME format */
-    format = GST_FORMAT_TIME;
-    GST_LOG_OBJECT (basesink, "not time format, don't clip");
-    goto do_times;
-  }
-
-  /* clip, only when we know about time */
-  if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
-              (gint64) start, (gint64) stop, &cstart, &cstop))) {
+  /* clip */
+  if (G_UNLIKELY (!gst_segment_clip (segment, format,
+              start, stop, &cstart, &cstop))) {
     if (step->valid) {
       GST_DEBUG_OBJECT (basesink, "step out of segment");
       /* when we are stepping, pretend we're at the end of the segment */
@@ -2044,9 +1928,9 @@ again:
 
   /* set last stop position */
   if (G_LIKELY (stop != GST_CLOCK_TIME_NONE && cstop != GST_CLOCK_TIME_NONE))
-    gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
+    segment->position = cstop;
   else
-    gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart);
+    segment->position = cstart;
 
 do_times:
   rstart = gst_segment_to_running_time (segment, format, cstart);
@@ -2189,8 +2073,8 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
   /* FIXME: Casting to GstClockEntry only works because the types
    * are the same */
   if (G_LIKELY (sink->priv->cached_clock_id != NULL
-          && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->
-              priv->cached_clock_id) == clock)) {
+          && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv->
+              cached_clock_id) == clock)) {
     if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id,
             time)) {
       gst_clock_id_unref (sink->priv->cached_clock_id);
@@ -2209,11 +2093,11 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
    * entry. */
   sink->clock_id = sink->priv->cached_clock_id;
   /* release the preroll lock while waiting */
-  GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+  GST_BASE_SINK_PREROLL_UNLOCK (sink);
 
   ret = gst_clock_id_wait (sink->priv->cached_clock_id, jitter);
 
-  GST_PAD_PREROLL_LOCK (sink->sinkpad);
+  GST_BASE_SINK_PREROLL_LOCK (sink);
   sink->clock_id = NULL;
 
   return ret;
@@ -2265,7 +2149,7 @@ gst_base_sink_wait_preroll (GstBaseSink * sink)
   sink->have_preroll = TRUE;
   GST_DEBUG_OBJECT (sink, "waiting in preroll for flush or PLAYING");
   /* block until the state changes, or we get a flush, or something */
-  GST_PAD_PREROLL_WAIT (sink->sinkpad);
+  GST_BASE_SINK_PREROLL_WAIT (sink);
   sink->have_preroll = FALSE;
   if (G_UNLIKELY (sink->flushing))
     goto stopping;
@@ -2641,7 +2525,7 @@ gst_base_sink_send_qos (GstBaseSink * basesink, GstQOSType type,
       "qos: type %d, proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
       GST_TIME_FORMAT, type, proportion, diff, GST_TIME_ARGS (time));
 
-  event = gst_event_new_qos_full (type, proportion, diff, time);
+  event = gst_event_new_qos (type, proportion, diff, time);
 
   /* send upstream */
   res = gst_pad_push_event (basesink->sinkpad, event);
@@ -2822,7 +2706,7 @@ gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj,
     GstClockReturn status, GstClockTimeDiff jitter)
 {
   gboolean late;
-  gint64 max_lateness;
+  guint64 max_lateness;
   GstBaseSinkPrivate *priv;
 
   priv = basesink->priv;
@@ -2833,7 +2717,7 @@ gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj,
   if (G_LIKELY (status != GST_CLOCK_EARLY))
     goto in_time;
 
-  max_lateness = basesink->abidata.ABI.max_lateness;
+  max_lateness = basesink->max_lateness;
 
   /* check if frame dropping is enabled */
   if (max_lateness == -1)
@@ -2961,7 +2845,7 @@ gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
      * If buffer list, use the first group buffer within the list
      * for syncing
      */
-    sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
+    sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0);
     g_assert (NULL != sync_obj);
   } else {
     sync_obj = obj;
@@ -3076,12 +2960,24 @@ again:
           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
           break;
         }
-        case GST_EVENT_NEWSEGMENT:
+        case GST_EVENT_SEGMENT:
           /* configure the segment */
           gst_base_sink_configure_segment (basesink, pad, event,
               &basesink->segment);
           break;
-        case GST_EVENT_SINK_MESSAGE:{
+        case GST_EVENT_TAG:
+        {
+          GstTagList *taglist;
+
+          gst_event_parse_tag (event, &taglist);
+
+          gst_element_post_message (GST_ELEMENT_CAST (basesink),
+              gst_message_new_tag (GST_OBJECT_CAST (basesink),
+                  gst_tag_list_copy (taglist)));
+          break;
+        }
+        case GST_EVENT_SINK_MESSAGE:
+        {
           GstMessage *msg = NULL;
 
           gst_event_parse_sink_message (event, &msg);
@@ -3182,7 +3078,7 @@ gst_base_sink_preroll_object (GstBaseSink * basesink, guint8 obj_type,
     GstClockTime timestamp;
 
     if (OBJ_IS_BUFFERLIST (obj_type)) {
-      buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
+      buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0);
       g_assert (NULL != buf);
     } else {
       buf = GST_BUFFER_CAST (obj);
@@ -3335,7 +3231,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad,
 {
   GstFlowReturn ret;
 
-  GST_PAD_PREROLL_LOCK (pad);
+  GST_BASE_SINK_PREROLL_LOCK (basesink);
   if (G_UNLIKELY (basesink->flushing))
     goto flushing;
 
@@ -3345,7 +3241,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad,
   ret =
       gst_base_sink_queue_object_unlocked (basesink, pad, _PR_IS_EVENT, obj,
       prerollable);
-  GST_PAD_PREROLL_UNLOCK (pad);
+  GST_BASE_SINK_PREROLL_UNLOCK (basesink);
 
   return ret;
 
@@ -3353,7 +3249,7 @@ gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad,
 flushing:
   {
     GST_DEBUG_OBJECT (basesink, "sink is flushing");
-    GST_PAD_PREROLL_UNLOCK (pad);
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
     gst_mini_object_unref (obj);
     return GST_FLOW_WRONG_STATE;
   }
@@ -3361,7 +3257,7 @@ was_eos:
   {
     GST_DEBUG_OBJECT (basesink,
         "we are EOS, dropping object, return UNEXPECTED");
-    GST_PAD_PREROLL_UNLOCK (pad);
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
     gst_mini_object_unref (obj);
     return GST_FLOW_UNEXPECTED;
   }
@@ -3385,6 +3281,9 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
   if (basesink->priv->async_enabled) {
     gst_element_lost_state (GST_ELEMENT_CAST (basesink));
   } else {
+    /* start time reset in above case as well;
+     * arranges for a.o. proper position reporting when flushing in PAUSED */
+    gst_element_set_start_time (GST_ELEMENT_CAST (basesink), 0);
     basesink->priv->have_latency = TRUE;
   }
   gst_base_sink_set_last_buffer (basesink, NULL);
@@ -3392,7 +3291,8 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
 }
 
 static void
-gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
+gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad,
+    gboolean reset_time)
 {
   /* unset flushing so we can accept new data, this also flushes out any EOS
    * event. */
@@ -3409,9 +3309,12 @@ gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
   if (basesink->pad_mode == GST_ACTIVATE_PUSH) {
     /* we need new segment info after the flush. */
     basesink->have_newsegment = FALSE;
-    gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
-    gst_segment_init (basesink->abidata.ABI.clip_segment, GST_FORMAT_UNDEFINED);
+    if (reset_time) {
+      gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
+      gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED);
+    }
   }
+  basesink->priv->reset_time = reset_time;
   GST_OBJECT_UNLOCK (basesink);
 }
 
@@ -3438,66 +3341,70 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
     {
       GstFlowReturn ret;
 
-      GST_PAD_PREROLL_LOCK (pad);
+      GST_BASE_SINK_PREROLL_LOCK (basesink);
       if (G_UNLIKELY (basesink->flushing))
         goto flushing;
 
-      if (G_UNLIKELY (basesink->priv->received_eos)) {
-        /* we can't accept anything when we are EOS */
+      if (G_UNLIKELY (basesink->priv->received_eos))
+        goto after_eos;
+
+      /* we set the received EOS flag here so that we can use it when testing if
+       * we are prerolled and to refuse more buffers. */
+      basesink->priv->received_eos = TRUE;
+
+      /* EOS is a prerollable object, we call the unlocked version because it
+       * does not check the received_eos flag. */
+      ret = gst_base_sink_queue_object_unlocked (basesink, pad,
+          _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE);
+      if (G_UNLIKELY (ret != GST_FLOW_OK))
         result = FALSE;
-        gst_event_unref (event);
-      } else {
-        /* we set the received EOS flag here so that we can use it when testing if
-         * we are prerolled and to refuse more buffers. */
-        basesink->priv->received_eos = TRUE;
-
-        /* EOS is a prerollable object, we call the unlocked version because it
-         * does not check the received_eos flag. */
-        ret = gst_base_sink_queue_object_unlocked (basesink, pad,
-            _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE);
-        if (G_UNLIKELY (ret != GST_FLOW_OK))
-          result = FALSE;
-      }
-      GST_PAD_PREROLL_UNLOCK (pad);
+
+      GST_BASE_SINK_PREROLL_UNLOCK (basesink);
+      break;
+    }
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      GST_DEBUG_OBJECT (basesink, "caps %p", event);
+
+      gst_event_parse_caps (event, &caps);
+      if (bclass->set_caps)
+        result = bclass->set_caps (basesink, caps);
+
+      gst_event_unref (event);
       break;
     }
-    case GST_EVENT_NEWSEGMENT:
+    case GST_EVENT_SEGMENT:
     {
       GstFlowReturn ret;
-      gboolean update;
 
-      GST_DEBUG_OBJECT (basesink, "newsegment %p", event);
+      GST_DEBUG_OBJECT (basesink, "segment %p", event);
 
-      GST_PAD_PREROLL_LOCK (pad);
+      GST_BASE_SINK_PREROLL_LOCK (basesink);
       if (G_UNLIKELY (basesink->flushing))
         goto flushing;
 
-      gst_event_parse_new_segment_full (event, &update, NULL, NULL, NULL, NULL,
-          NULL, NULL);
+      if (G_UNLIKELY (basesink->priv->received_eos))
+        goto after_eos;
+
+      /* the new segment is a non prerollable item and does not block anything,
+       * we need to configure the current clipping segment and insert the event
+       * in the queue to serialize it with the buffers for rendering. */
+      gst_base_sink_configure_segment (basesink, pad, event,
+          &basesink->clip_segment);
 
-      if (G_UNLIKELY (basesink->priv->received_eos && !update)) {
-        /* we can't accept anything when we are EOS */
+      ret =
+          gst_base_sink_queue_object_unlocked (basesink, pad,
+          _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE);
+      if (G_UNLIKELY (ret != GST_FLOW_OK))
         result = FALSE;
-        gst_event_unref (event);
-      } else {
-        /* the new segment is a non prerollable item and does not block anything,
-         * we need to configure the current clipping segment and insert the event
-         * in the queue to serialize it with the buffers for rendering. */
-        gst_base_sink_configure_segment (basesink, pad, event,
-            basesink->abidata.ABI.clip_segment);
-
-        ret =
-            gst_base_sink_queue_object_unlocked (basesink, pad,
-            _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE);
-        if (G_UNLIKELY (ret != GST_FLOW_OK))
-          result = FALSE;
-        else {
-          GST_OBJECT_LOCK (basesink);
-          basesink->have_newsegment = TRUE;
-          GST_OBJECT_UNLOCK (basesink);
-        }
+      else {
+        GST_OBJECT_LOCK (basesink);
+        basesink->have_newsegment = TRUE;
+        GST_OBJECT_UNLOCK (basesink);
       }
-      GST_PAD_PREROLL_UNLOCK (pad);
+      GST_BASE_SINK_PREROLL_UNLOCK (basesink);
       break;
     }
     case GST_EVENT_FLUSH_START:
@@ -3511,15 +3418,21 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
       gst_event_unref (event);
       break;
     case GST_EVENT_FLUSH_STOP:
+    {
+      gboolean reset_time;
+
       if (bclass->event)
         bclass->event (basesink, event);
 
-      GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
+      gst_event_parse_flush_stop (event, &reset_time);
+      GST_DEBUG_OBJECT (basesink, "flush-stop %p, reset_time: %d", event,
+          reset_time);
 
-      gst_base_sink_flush_stop (basesink, pad);
+      gst_base_sink_flush_stop (basesink, pad, reset_time);
 
       gst_event_unref (event);
       break;
+    }
     default:
       /* other events are sent to queue or subclass depending on if they
        * are serialized. */
@@ -3542,7 +3455,16 @@ done:
 flushing:
   {
     GST_DEBUG_OBJECT (basesink, "we are flushing");
-    GST_PAD_PREROLL_UNLOCK (pad);
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
+    result = FALSE;
+    gst_event_unref (event);
+    goto done;
+  }
+
+after_eos:
+  {
+    GST_DEBUG_OBJECT (basesink, "Event received after EOS, dropping");
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
     result = FALSE;
     gst_event_unref (event);
     goto done;
@@ -3614,14 +3536,14 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
     goto was_eos;
 
   if (OBJ_IS_BUFFERLIST (obj_type)) {
-    time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
+    time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0);
     g_assert (NULL != time_buf);
   } else {
     time_buf = GST_BUFFER_CAST (obj);
   }
 
   /* for code clarity */
-  clip_segment = basesink->abidata.ABI.clip_segment;
+  clip_segment = &basesink->clip_segment;
 
   if (G_UNLIKELY (!basesink->have_newsegment)) {
     gboolean sync;
@@ -3663,7 +3585,7 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
   if (GST_CLOCK_TIME_IS_VALID (start) &&
       (clip_segment->format == GST_FORMAT_TIME)) {
     if (G_UNLIKELY (!gst_segment_clip (clip_segment,
-                GST_FORMAT_TIME, (gint64) start, (gint64) end, NULL, NULL)))
+                GST_FORMAT_TIME, start, end, NULL, NULL)))
       goto out_of_segment;
   }
 
@@ -3706,9 +3628,9 @@ gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
   if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
     goto wrong_mode;
 
-  GST_PAD_PREROLL_LOCK (pad);
+  GST_BASE_SINK_PREROLL_LOCK (basesink);
   result = gst_base_sink_chain_unlocked (basesink, pad, obj_type, obj);
-  GST_PAD_PREROLL_UNLOCK (pad);
+  GST_BASE_SINK_PREROLL_UNLOCK (basesink);
 
 done:
   return result;
@@ -3752,32 +3674,21 @@ gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
   if (G_LIKELY (bclass->render_list)) {
     result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFERLIST, list);
   } else {
-    GstBufferListIterator *it;
-    GstBuffer *group;
+    guint i, len;
+    GstBuffer *buffer;
 
     GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
 
-    it = gst_buffer_list_iterate (list);
+    len = gst_buffer_list_len (list);
 
-    if (gst_buffer_list_iterator_next_group (it)) {
-      do {
-        group = gst_buffer_list_iterator_merge_group (it);
-        if (group == NULL) {
-          group = gst_buffer_new ();
-          GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
-        } else {
-          GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
-        }
-        result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, group);
-      } while (result == GST_FLOW_OK
-          && gst_buffer_list_iterator_next_group (it));
-    } else {
-      GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
-      result =
-          gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER,
-          gst_buffer_new ());
+    result = GST_FLOW_OK;
+    for (i = 0; i < len; i++) {
+      buffer = gst_buffer_list_get (list, 0);
+      result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER,
+          gst_buffer_ref (buffer));
+      if (result != GST_FLOW_OK)
+        break;
     }
-    gst_buffer_list_iterator_free (it);
     gst_buffer_list_unref (list);
   }
   return result;
@@ -3819,17 +3730,16 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
   GstSeekType cur_type, stop_type;
   gint64 cur, stop;
   GstSeekFlags flags;
-  GstFormat seek_format, dest_format;
+  GstFormat seek_format;
   gdouble rate;
   gboolean update;
   gboolean res = TRUE;
 
   gst_event_parse_seek (event, &rate, &seek_format, &flags,
       &cur_type, &cur, &stop_type, &stop);
-  dest_format = segment->format;
 
-  if (seek_format == dest_format) {
-    gst_segment_set_seek (segment, rate, seek_format, flags,
+  if (seek_format == segment->format) {
+    gst_segment_do_seek (segment, rate, seek_format, flags,
         cur_type, cur, stop_type, stop, &update);
     return TRUE;
   }
@@ -3837,7 +3747,7 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
   if (cur_type != GST_SEEK_TYPE_NONE) {
     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
     res =
-        gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format,
+        gst_pad_query_convert (sink->sinkpad, seek_format, cur, segment->format,
         &cur);
     cur_type = GST_SEEK_TYPE_SET;
   }
@@ -3845,13 +3755,13 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
   if (res && stop_type != GST_SEEK_TYPE_NONE) {
     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
     res =
-        gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format,
-        &stop);
+        gst_pad_query_convert (sink->sinkpad, seek_format, stop,
+        segment->format, &stop);
     stop_type = GST_SEEK_TYPE_SET;
   }
 
   /* And finally, configure our output segment in the desired format */
-  gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur,
+  gst_segment_do_seek (segment, rate, segment->format, flags, cur_type, cur,
       stop_type, stop, &update);
 
   if (!res)
@@ -3924,7 +3834,7 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
       } else {
         /* The seek format matches our processing format, no need to ask the
          * the subclass to configure the segment. */
-        gst_segment_set_seek (&seeksegment, rate, seek_format, flags,
+        gst_segment_do_seek (&seeksegment, rate, seek_format, flags,
             cur_type, cur, stop_type, stop, &update);
       }
     }
@@ -3935,22 +3845,22 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
   if (res) {
     GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT
         " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
-        seeksegment.start, seeksegment.stop, seeksegment.last_stop);
+        seeksegment.start, seeksegment.stop, seeksegment.position);
 
-    /* do the seek, segment.last_stop contains the new position. */
+    /* do the seek, segment.position contains the new position. */
     res = gst_base_sink_default_do_seek (sink, &seeksegment);
   }
 
 
   if (flush) {
     GST_DEBUG_OBJECT (sink, "stop flushing upstream");
-    gst_pad_push_event (pad, gst_event_new_flush_stop ());
-    gst_base_sink_flush_stop (sink, pad);
-  } else if (res && sink->abidata.ABI.running) {
+    gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
+    gst_base_sink_flush_stop (sink, pad, TRUE);
+  } else if (res && sink->running) {
     /* we are running the current segment and doing a non-flushing seek,
-     * close the segment first based on the last_stop. */
+     * close the segment first based on the position. */
     GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT
-        " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop);
+        " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.position);
   }
 
   /* The subclass must have converted the segment to the processing format
@@ -3964,17 +3874,17 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
   /* if successfull seek, we update our real segment and push
    * out the new segment. */
   if (res) {
-    memcpy (&sink->segment, &seeksegment, sizeof (GstSegment));
+    gst_segment_copy_into (&seeksegment, &sink->segment);
 
     if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
       gst_element_post_message (GST_ELEMENT (sink),
           gst_message_new_segment_start (GST_OBJECT (sink),
-              sink->segment.format, sink->segment.last_stop));
+              sink->segment.format, sink->segment.position));
     }
   }
 
   sink->priv->discont = TRUE;
-  sink->abidata.ABI.running = TRUE;
+  sink->running = TRUE;
 
   GST_PAD_STREAM_UNLOCK (pad);
 
@@ -4037,7 +3947,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
     if (bclass->unlock)
       bclass->unlock (sink);
 
-    GST_PAD_PREROLL_LOCK (sink->sinkpad);
+    GST_BASE_SINK_PREROLL_LOCK (sink);
     /* now that we have the PREROLL lock, clear our unlock request */
     if (bclass->unlock_stop)
       bclass->unlock_stop (sink);
@@ -4052,7 +3962,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
       sink->playing_async = TRUE;
       priv->pending_step.need_preroll = TRUE;
       sink->need_preroll = FALSE;
-      gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE);
+      gst_element_lost_state (GST_ELEMENT_CAST (sink));
     } else {
       sink->priv->have_latency = TRUE;
       sink->need_preroll = FALSE;
@@ -4071,9 +3981,9 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
     if (sink->have_preroll) {
       GST_DEBUG_OBJECT (sink, "signal waiter");
       priv->step_unlock = TRUE;
-      GST_PAD_PREROLL_SIGNAL (sink->sinkpad);
+      GST_BASE_SINK_PREROLL_SIGNAL (sink);
     }
-    GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+    GST_BASE_SINK_PREROLL_UNLOCK (sink);
   } else {
     /* update the stepinfo and make it valid */
     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
@@ -4101,7 +4011,7 @@ gst_base_sink_loop (GstPad * pad)
   if ((blocksize = basesink->priv->blocksize) == 0)
     blocksize = -1;
 
-  offset = basesink->segment.last_stop;
+  offset = basesink->segment.position;
 
   GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
       offset, blocksize);
@@ -4113,13 +4023,13 @@ gst_base_sink_loop (GstPad * pad)
   if (G_UNLIKELY (buf == NULL))
     goto no_buffer;
 
-  offset += GST_BUFFER_SIZE (buf);
+  offset += gst_buffer_get_size (buf);
 
-  gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset);
+  basesink->segment.position = offset;
 
-  GST_PAD_PREROLL_LOCK (pad);
+  GST_BASE_SINK_PREROLL_LOCK (basesink);
   result = gst_base_sink_chain_unlocked (basesink, pad, _PR_IS_BUFFER, buf);
-  GST_PAD_PREROLL_UNLOCK (pad);
+  GST_BASE_SINK_PREROLL_UNLOCK (basesink);
   if (G_UNLIKELY (result != GST_FLOW_OK))
     goto paused;
 
@@ -4136,7 +4046,7 @@ paused:
       if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
         gst_element_post_message (GST_ELEMENT_CAST (basesink),
             gst_message_new_segment_done (GST_OBJECT_CAST (basesink),
-                basesink->segment.format, basesink->segment.last_stop));
+                basesink->segment.format, basesink->segment.position));
       } else {
         gst_base_sink_event (pad, gst_event_new_eos ());
       }
@@ -4179,7 +4089,7 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
       bclass->unlock (basesink);
   }
 
-  GST_PAD_PREROLL_LOCK (pad);
+  GST_BASE_SINK_PREROLL_LOCK (basesink);
   basesink->flushing = flushing;
   if (flushing) {
     /* step 1, now that we have the PREROLL lock, clear our unlock request */
@@ -4201,7 +4111,7 @@ gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
         "flushing out data thread, need preroll to TRUE");
     gst_base_sink_preroll_queue_flush (basesink, pad);
   }
-  GST_PAD_PREROLL_UNLOCK (pad);
+  GST_BASE_SINK_PREROLL_UNLOCK (basesink);
 
   return TRUE;
 }
@@ -4228,6 +4138,8 @@ gst_base_sink_pad_activate (GstPad * pad)
 {
   gboolean result = FALSE;
   GstBaseSink *basesink;
+  GstQuery *query;
+  gboolean pull_mode;
 
   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
 
@@ -4242,7 +4154,19 @@ gst_base_sink_pad_activate (GstPad * pad)
   }
 
   /* check if downstreams supports pull mode at all */
-  if (!gst_pad_check_pull_range (pad)) {
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (pad, query)) {
+    gst_query_unref (query);
+    GST_DEBUG_OBJECT (basesink, "peer query faild, no pull mode");
+    goto fallback;
+  }
+
+  /* parse result of the query */
+  gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
+  gst_query_unref (query);
+
+  if (!pull_mode) {
     GST_DEBUG_OBJECT (basesink, "pull mode not supported");
     goto fallback;
   }
@@ -4343,10 +4267,8 @@ gst_base_sink_negotiate_pull (GstBaseSink * basesink)
   caps = gst_caps_make_writable (caps);
   /* get the first (prefered) format */
   gst_caps_truncate (caps);
-  /* try to fixate */
-  gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
 
-  GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
+  GST_DEBUG_OBJECT (basesink, "have caps: %" GST_PTR_FORMAT, caps);
 
   if (gst_caps_is_any (caps)) {
     GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
@@ -4354,15 +4276,22 @@ gst_base_sink_negotiate_pull (GstBaseSink * basesink)
     /* neither side has template caps in this case, so they are prepared for
        pull() without setcaps() */
     result = TRUE;
-  } else if (gst_caps_is_fixed (caps)) {
-    if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps))
-      goto could_not_set_caps;
+  } else {
+    /* try to fixate */
+    gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
+    GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
 
-    GST_OBJECT_LOCK (basesink);
-    gst_caps_replace (&basesink->priv->pull_caps, caps);
-    GST_OBJECT_UNLOCK (basesink);
+    if (gst_caps_is_fixed (caps)) {
+      if (!gst_pad_send_event (GST_BASE_SINK_PAD (basesink),
+              gst_event_new_caps (caps)))
+        goto could_not_set_caps;
 
-    result = TRUE;
+      GST_OBJECT_LOCK (basesink);
+      gst_caps_replace (&basesink->priv->pull_caps, caps);
+      GST_OBJECT_UNLOCK (basesink);
+
+      result = TRUE;
+    }
   }
 
   gst_caps_unref (caps);
@@ -4397,28 +4326,24 @@ gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active)
   bclass = GST_BASE_SINK_GET_CLASS (basesink);
 
   if (active) {
-    GstFormat format;
     gint64 duration;
 
     /* we mark we have a newsegment here because pull based
      * mode works just fine without having a newsegment before the
      * first buffer */
-    format = GST_FORMAT_BYTES;
-
-    gst_segment_init (&basesink->segment, format);
-    gst_segment_init (basesink->abidata.ABI.clip_segment, format);
+    gst_segment_init (&basesink->segment, GST_FORMAT_BYTES);
+    gst_segment_init (&basesink->clip_segment, GST_FORMAT_BYTES);
     GST_OBJECT_LOCK (basesink);
     basesink->have_newsegment = TRUE;
     GST_OBJECT_UNLOCK (basesink);
 
     /* get the peer duration in bytes */
-    result = gst_pad_query_peer_duration (pad, &format, &duration);
+    result = gst_pad_query_peer_duration (pad, GST_FORMAT_BYTES, &duration);
     if (result) {
       GST_DEBUG_OBJECT (basesink,
           "setting duration in bytes to %" G_GINT64_FORMAT, duration);
-      gst_segment_set_duration (basesink->abidata.ABI.clip_segment, format,
-          duration);
-      gst_segment_set_duration (&basesink->segment, format, duration);
+      basesink->clip_segment.duration = duration;
+      basesink->segment.duration = duration;
     } else {
       GST_DEBUG_OBJECT (basesink, "unknown duration");
     }
@@ -4534,11 +4459,11 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
 {
   GstClock *clock = NULL;
   gboolean res = FALSE;
-  GstFormat oformat, tformat;
+  GstFormat oformat;
   GstSegment *segment;
   GstClockTime now, latency;
-  GstClockTimeDiff base;
-  gint64 time, accum, duration;
+  GstClockTimeDiff base_time;
+  gint64 time, base, duration;
   gdouble rate;
   gint64 last;
   gboolean last_seen, with_clock, in_paused;
@@ -4561,12 +4486,10 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
    * main segment directly with the new segment values without it having to be
    * activated by the rendering after preroll */
   if (basesink->pad_mode == GST_ACTIVATE_PUSH)
-    segment = basesink->abidata.ABI.clip_segment;
+    segment = &basesink->clip_segment;
   else
     segment = &basesink->segment;
 
-  /* our intermediate time format */
-  tformat = GST_FORMAT_TIME;
   /* get the format in the segment */
   oformat = segment->format;
 
@@ -4584,6 +4507,14 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
   else
     gst_object_ref (clock);
 
+  /* mainloop might be querying position when going to playing async,
+   * while (audio) rendering might be quickly advancing stream position,
+   * so use clock asap rather than last reported position */
+  if (in_paused && with_clock && g_atomic_int_get (&basesink->priv->to_playing)) {
+    GST_DEBUG_OBJECT (basesink, "going to PLAYING, so not PAUSED");
+    in_paused = FALSE;
+  }
+
   /* collect all data we need holding the lock */
   if (GST_CLOCK_TIME_IS_VALID (segment->time))
     time = segment->time;
@@ -4595,7 +4526,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
   else
     duration = 0;
 
-  accum = segment->accum;
+  base = segment->base;
   rate = segment->rate * segment->applied_rate;
   latency = basesink->priv->latency;
 
@@ -4620,28 +4551,28 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
     }
   } else {
     /* convert last stop to stream time */
-    last = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
+    last = gst_segment_to_stream_time (segment, oformat, segment->position);
   }
 
   if (in_paused) {
     /* in paused, use start_time */
-    base = GST_ELEMENT_START_TIME (basesink);
+    base_time = GST_ELEMENT_START_TIME (basesink);
     GST_DEBUG_OBJECT (basesink, "in paused, using start time %" GST_TIME_FORMAT,
-        GST_TIME_ARGS (base));
+        GST_TIME_ARGS (base_time));
   } else if (with_clock) {
     /* else use clock when needed */
-    base = GST_ELEMENT_CAST (basesink)->base_time;
+    base_time = GST_ELEMENT_CAST (basesink)->base_time;
     GST_DEBUG_OBJECT (basesink, "using clock and base time %" GST_TIME_FORMAT,
-        GST_TIME_ARGS (base));
+        GST_TIME_ARGS (base_time));
   } else {
     /* else, no sync or clock -> no base time */
     GST_DEBUG_OBJECT (basesink, "no sync or no clock");
-    base = -1;
+    base_time = -1;
   }
 
-  /* no base, we can't calculate running_time, use last seem timestamp to report
+  /* no base_time, we can't calculate running_time, use last seem timestamp to report
    * time */
-  if (base == -1)
+  if (base_time == -1)
     last_seen = TRUE;
 
   /* need to release the object lock before we can get the time,
@@ -4663,47 +4594,47 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
         GST_TIME_ARGS (last));
     *cur = last;
   } else {
-    if (oformat != tformat) {
-      /* convert accum, time and duration to time */
-      if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat,
-              &accum))
+    if (oformat != GST_FORMAT_TIME) {
+      /* convert base, time and duration to time */
+      if (!gst_pad_query_convert (basesink->sinkpad, oformat, base,
+              GST_FORMAT_TIME, &base))
         goto convert_failed;
       if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration,
-              &tformat, &duration))
+              GST_FORMAT_TIME, &duration))
         goto convert_failed;
-      if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat,
-              &time))
+      if (!gst_pad_query_convert (basesink->sinkpad, oformat, time,
+              GST_FORMAT_TIME, &time))
         goto convert_failed;
-      if (!gst_pad_query_convert (basesink->sinkpad, oformat, last, &tformat,
-              &last))
+      if (!gst_pad_query_convert (basesink->sinkpad, oformat, last,
+              GST_FORMAT_TIME, &last))
         goto convert_failed;
 
       /* assume time format from now on */
-      oformat = tformat;
+      oformat = GST_FORMAT_TIME;
     }
 
     if (!in_paused && with_clock) {
       now = gst_clock_get_time (clock);
     } else {
-      now = base;
-      base = 0;
+      now = base_time;
+      base_time = 0;
     }
 
-    /* subtract base time and accumulated time from the clock time.
+    /* subtract base time and base time from the clock time.
      * Make sure we don't go negative. This is the current time in
      * the segment which we need to scale with the combined
      * rate and applied rate. */
-    base += accum;
-    base += latency;
-    if (GST_CLOCK_DIFF (base, now) < 0)
-      base = now;
+    base_time += base;
+    base_time += latency;
+    if (GST_CLOCK_DIFF (base_time, now) < 0)
+      base_time = now;
 
     /* for negative rates we need to count back from the segment
      * duration. */
     if (rate < 0.0)
       time += duration;
 
-    *cur = time + gst_guint64_to_gdouble (now - base) * rate;
+    *cur = time + gst_guint64_to_gdouble (now - base_time) * rate;
 
     if (in_paused) {
       /* never report less than segment values in paused */
@@ -4716,15 +4647,15 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
     }
 
     GST_DEBUG_OBJECT (basesink,
-        "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
+        "now %" GST_TIME_FORMAT " - base_time %" GST_TIME_FORMAT " - base %"
         GST_TIME_FORMAT " + time %" GST_TIME_FORMAT "  last %" GST_TIME_FORMAT,
-        GST_TIME_ARGS (now), GST_TIME_ARGS (base), GST_TIME_ARGS (accum),
+        GST_TIME_ARGS (now), GST_TIME_ARGS (base_time), GST_TIME_ARGS (base),
         GST_TIME_ARGS (time), GST_TIME_ARGS (last));
   }
 
   if (oformat != format) {
     /* convert to final format */
-    if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur))
+    if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, format, cur))
       goto convert_failed;
   }
 
@@ -4765,20 +4696,22 @@ gst_base_sink_get_duration (GstBaseSink * basesink, GstFormat format,
   gboolean res = FALSE;
 
   if (basesink->pad_mode == GST_ACTIVATE_PULL) {
-    GstFormat uformat = GST_FORMAT_BYTES;
     gint64 uduration;
 
     /* get the duration in bytes, in pull mode that's all we are sure to
      * know. We have to explicitly get this value from upstream instead of
      * using our cached value because it might change. Duration caching
      * should be done at a higher level. */
-    res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, &uduration);
+    res =
+        gst_pad_query_peer_duration (basesink->sinkpad, GST_FORMAT_BYTES,
+        &uduration);
     if (res) {
-      gst_segment_set_duration (&basesink->segment, uformat, uduration);
-      if (format != uformat) {
+      basesink->segment.duration = uduration;
+      if (format != GST_FORMAT_BYTES) {
         /* convert to the requested format */
-        res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration,
-            &format, dur);
+        res =
+            gst_pad_query_convert (basesink->sinkpad, GST_FORMAT_BYTES,
+            uduration, format, dur);
       } else {
         *dur = uduration;
       }
@@ -4806,7 +4739,7 @@ gst_base_sink_get_query_types (GstElement * element)
 }
 
 static gboolean
-gst_base_sink_query (GstElement * element, GstQuery * query)
+default_element_query (GstElement * element, GstQuery * query)
 {
   gboolean res = FALSE;
 
@@ -4836,20 +4769,21 @@ gst_base_sink_query (GstElement * element, GstQuery * query)
         /* we can handle a few things if upstream failed */
         if (format == GST_FORMAT_PERCENT) {
           gint64 dur = 0;
-          GstFormat uformat = GST_FORMAT_TIME;
 
           res = gst_base_sink_get_position (basesink, GST_FORMAT_TIME, &cur,
               &upstream);
           if (!res && upstream) {
-            res = gst_pad_query_peer_position (basesink->sinkpad, &uformat,
+            res =
+                gst_pad_query_peer_position (basesink->sinkpad, GST_FORMAT_TIME,
                 &cur);
           }
           if (res) {
             res = gst_base_sink_get_duration (basesink, GST_FORMAT_TIME, &dur,
                 &upstream);
             if (!res && upstream) {
-              res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat,
-                  &dur);
+              res =
+                  gst_pad_query_peer_duration (basesink->sinkpad,
+                  GST_FORMAT_TIME, &dur);
             }
           }
           if (res) {
@@ -4931,6 +4865,56 @@ gst_base_sink_query (GstElement * element, GstQuery * query)
   return res;
 }
 
+
+static gboolean
+default_sink_query (GstBaseSink * basesink, GstQuery * query)
+{
+  gboolean res;
+  GstBaseSinkClass *bclass;
+
+  bclass = GST_BASE_SINK_GET_CLASS (basesink);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_ALLOCATION:
+    {
+      if (bclass->setup_allocation)
+        res = bclass->setup_allocation (basesink, query);
+      else
+        res = FALSE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (basesink->sinkpad, query);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_base_sink_sink_query (GstPad * pad, GstQuery * query)
+{
+  GstBaseSink *basesink;
+  GstBaseSinkClass *bclass;
+  gboolean res;
+
+  basesink = GST_BASE_SINK_CAST (gst_pad_get_parent (pad));
+  if (G_UNLIKELY (basesink == NULL)) {
+    gst_query_unref (query);
+    return FALSE;
+  }
+
+  bclass = GST_BASE_SINK_GET_CLASS (basesink);
+
+  if (bclass->query)
+    res = bclass->query (basesink, query);
+  else
+    res = FALSE;
+
+  gst_object_unref (basesink);
+
+  return res;
+}
+
 static GstStateChangeReturn
 gst_base_sink_change_state (GstElement * element, GstStateChange transition)
 {
@@ -4952,17 +4936,17 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       /* need to complete preroll before this state change completes, there
        * is no data flow in READY so we can safely assume we need to preroll. */
-      GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_LOCK (basesink);
       GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
       basesink->have_newsegment = FALSE;
       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
-      gst_segment_init (basesink->abidata.ABI.clip_segment,
-          GST_FORMAT_UNDEFINED);
+      gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED);
       basesink->offset = 0;
       basesink->have_preroll = FALSE;
       priv->step_unlock = FALSE;
       basesink->need_preroll = TRUE;
       basesink->playing_async = TRUE;
+      basesink->priv->reset_time = FALSE;
       priv->current_sstart = GST_CLOCK_TIME_NONE;
       priv->current_sstop = GST_CLOCK_TIME_NONE;
       priv->eos_rtime = GST_CLOCK_TIME_NONE;
@@ -4980,14 +4964,15 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
          * the state change function */
         ret = GST_STATE_CHANGE_ASYNC;
         gst_element_post_message (GST_ELEMENT_CAST (basesink),
-            gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
+            gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
       } else {
         priv->have_latency = TRUE;
       }
-      GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_UNLOCK (basesink);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
-      GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_LOCK (basesink);
+      g_atomic_int_set (&basesink->priv->to_playing, TRUE);
       if (!gst_base_sink_needs_preroll (basesink)) {
         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
         /* no preroll needed anymore now. */
@@ -5003,7 +4988,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
         } else {
           GST_DEBUG_OBJECT (basesink, "signal preroll");
-          GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
+          GST_BASE_SINK_PREROLL_SIGNAL (basesink);
         }
       } else {
         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
@@ -5015,10 +5000,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
           GST_DEBUG_OBJECT (basesink, "doing async state change");
           ret = GST_STATE_CHANGE_ASYNC;
           gst_element_post_message (GST_ELEMENT_CAST (basesink),
-              gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
+              gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
         }
       }
-      GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_UNLOCK (basesink);
       break;
     default:
       break;
@@ -5033,7 +5018,14 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
   }
 
   switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      /* completed transition, so need not be marked any longer
+       * And it should be unmarked, since e.g. losing our position upon flush
+       * does not really change state to PAUSED ... */
+      g_atomic_int_set (&basesink->priv->to_playing, FALSE);
+      break;
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      g_atomic_int_set (&basesink->priv->to_playing, FALSE);
       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
       /* FIXME, make sure we cannot enter _render first */
 
@@ -5042,7 +5034,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
       if (bclass->unlock)
         bclass->unlock (basesink);
 
-      GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_LOCK (basesink);
       GST_DEBUG_OBJECT (basesink, "got preroll lock");
       /* now that we have the PREROLL lock, clear our unlock request */
       if (bclass->unlock_stop)
@@ -5077,8 +5069,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
             GST_DEBUG_OBJECT (basesink, "doing async state change");
             ret = GST_STATE_CHANGE_ASYNC;
             gst_element_post_message (GST_ELEMENT_CAST (basesink),
-                gst_message_new_async_start (GST_OBJECT_CAST (basesink),
-                    FALSE));
+                gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
           }
         }
       }
@@ -5086,10 +5077,10 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
           ", dropped: %" G_GUINT64_FORMAT, priv->rendered, priv->dropped);
 
       gst_base_sink_reset_qos (basesink);
-      GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_UNLOCK (basesink);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
-      GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_LOCK (basesink);
       /* start by reseting our position state with the object lock so that the
        * position query gets the right idea. We do this before we post the
        * messages so that the message handlers pick this up. */
@@ -5116,13 +5107,13 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
                   GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY));
 
           gst_element_post_message (GST_ELEMENT_CAST (basesink),
-              gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+              gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE));
         }
         priv->commited = TRUE;
       } else {
         GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
       }
-      GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+      GST_BASE_SINK_PREROLL_UNLOCK (basesink);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
       if (bclass->stop) {