gstreamer_core/libs/gst/base/gstbasesink.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
--- a/gstreamer_core/libs/gst/base/gstbasesink.c	Tue Aug 31 15:30:33 2010 +0300
+++ b/gstreamer_core/libs/gst/base/gstbasesink.c	Wed Sep 01 12:16:41 2010 +0100
@@ -163,26 +163,6 @@
 #define GST_BASE_SINK_GET_PRIVATE(obj)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate))
 
-#define GST_FLOW_STEP GST_FLOW_CUSTOM_ERROR
-
-typedef struct
-{
-  gboolean valid;               /* if this info is valid */
-  guint32 seqnum;               /* the seqnum of the STEP event */
-  GstFormat format;             /* the format of the amount */
-  guint64 amount;               /* the total amount of data to skip */
-  guint64 position;             /* the position in the stepped data */
-  guint64 duration;             /* the duration in time of the skipped data */
-  guint64 start;                /* running_time of the start */
-  gdouble rate;                 /* rate of skipping */
-  gdouble start_rate;           /* rate before skipping */
-  guint64 start_start;          /* start position skipping */
-  guint64 start_stop;           /* stop position skipping */
-  gboolean flush;               /* if this was a flushing step */
-  gboolean intermediate;        /* if this is an intermediate step */
-  gboolean need_preroll;        /* if we need preroll after this step */
-} GstStepInfo;
-
 /* FIXME, some stuff in ABI.data and other in Private...
  * Make up your mind please.
  */
@@ -191,7 +171,6 @@
   gint qos_enabled;             /* ATOMIC */
   gboolean async_enabled;
   GstClockTimeDiff ts_offset;
-  GstClockTime render_delay;
 
   /* start, stop of current buffer, stream time, used to report position */
   GstClockTime current_sstart;
@@ -242,24 +221,6 @@
 
   /* the last buffer we prerolled or rendered. Useful for making snapshots */
   GstBuffer *last_buffer;
-
-  /* caps for pull based scheduling */
-  GstCaps *pull_caps;
-
-  /* blocksize for pulling */
-  guint blocksize;
-
-  gboolean discont;
-
-  /* seqnum of the stream */
-  guint32 seqnum;
-
-  gboolean call_preroll;
-  gboolean step_unlock;
-
-  /* we have a pending and a current step operation */
-  GstStepInfo current_step;
-  GstStepInfo pending_step;
 };
 
 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
@@ -275,6 +236,7 @@
 
 /* BaseSink properties */
 
+#define DEFAULT_SIZE 1024
 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
 
@@ -284,8 +246,6 @@
 #define DEFAULT_QOS			FALSE
 #define DEFAULT_ASYNC			TRUE
 #define DEFAULT_TS_OFFSET		0
-#define DEFAULT_BLOCKSIZE 		4096
-#define DEFAULT_RENDER_DELAY 		0
 
 enum
 {
@@ -297,8 +257,6 @@
   PROP_ASYNC,
   PROP_TS_OFFSET,
   PROP_LAST_BUFFER,
-  PROP_BLOCKSIZE,
-  PROP_RENDER_DELAY,
   PROP_LAST
 };
 
@@ -315,10 +273,9 @@
 GType
 gst_base_sink_get_type (void)
 {
-  static volatile gsize base_sink_type = 0;
-
-  if (g_once_init_enter (&base_sink_type)) {
-    GType _type;
+  static GType base_sink_type = 0;
+
+  if (G_UNLIKELY (base_sink_type == 0)) {
     static const GTypeInfo base_sink_info = {
       sizeof (GstBaseSinkClass),
       NULL,
@@ -331,9 +288,8 @@
       (GInstanceInitFunc) gst_base_sink_init,
     };
 
-    _type = g_type_register_static (GST_TYPE_ELEMENT,
+    base_sink_type = g_type_register_static (GST_TYPE_ELEMENT,
         "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
-    g_once_init_leave (&base_sink_type, _type);
   }
   return base_sink_type;
 }
@@ -357,18 +313,11 @@
     GstPad * pad, gboolean flushing);
 static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
     gboolean active);
-static gboolean gst_base_sink_default_do_seek (GstBaseSink * sink,
-    GstSegment * segment);
-static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
-    GstEvent * event, GstSegment * segment);
 
 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
     GstStateChange transition);
 
 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
-static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
-    GstBufferList * list);
-
 static void gst_base_sink_loop (GstPad * pad);
 static gboolean gst_base_sink_pad_activate (GstPad * pad);
 static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
@@ -376,14 +325,10 @@
 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
 static gboolean gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query);
 
-static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
-
 /* check if an object was too late */
 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
     GstMiniObject * obj, GstClockTime start, GstClockTime stop,
     GstClockReturn status, GstClockTimeDiff jitter);
-static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink,
-    gboolean is_list, GstMiniObject * obj);
 
 static void
 gst_base_sink_class_init (GstBaseSinkClass * klass)
@@ -410,23 +355,22 @@
   g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN,
       g_param_spec_uint ("preroll-queue-len", "Preroll queue length",
           "Number of buffers to queue during preroll", 0, G_MAXUINT,
-          DEFAULT_PREROLL_QUEUE_LEN,
-          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+          DEFAULT_PREROLL_QUEUE_LEN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (gobject_class, PROP_SYNC,
       g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
       g_param_spec_int64 ("max-lateness", "Max Lateness",
           "Maximum number of nanoseconds that a buffer can be late before it "
           "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class, PROP_QOS,
       g_param_spec_boolean ("qos", "Qos",
           "Generate Quality-of-Service events upstream", DEFAULT_QOS,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READWRITE));
   /**
    * GstBaseSink:async
    *
@@ -439,8 +383,7 @@
    */
   g_object_class_install_property (gobject_class, PROP_ASYNC,
       g_param_spec_boolean ("async", "Async",
-          "Go asynchronously to PAUSED", DEFAULT_ASYNC,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          "Go asynchronously to PAUSED", DEFAULT_ASYNC, G_PARAM_READWRITE));
   /**
    * GstBaseSink:ts-offset
    *
@@ -453,7 +396,8 @@
   g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
       g_param_spec_int64 ("ts-offset", "TS Offset",
           "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
-          DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          DEFAULT_TS_OFFSET, G_PARAM_READWRITE));
+
   /**
    * GstBaseSink:last-buffer
    *
@@ -466,31 +410,7 @@
   g_object_class_install_property (gobject_class, PROP_LAST_BUFFER,
       gst_param_spec_mini_object ("last-buffer", "Last Buffer",
           "The last buffer received in the sink", GST_TYPE_BUFFER,
-          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-  /**
-   * GstBaseSink:blocksize
-   *
-   * The amount of bytes to pull when operating in pull mode.
-   *
-   * Since: 0.10.22
-   */
-  g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
-      g_param_spec_uint ("blocksize", "Block size",
-          "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
-          DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  /**
-   * GstBaseSink:render-delay
-   *
-   * The additional delay between synchronisation and actual rendering of the
-   * media. This property will add additional latency to the device in order to
-   * make other sinks compensate for the delay.
-   *
-   * Since: 0.10.22
-   */
-  g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
-      g_param_spec_uint64 ("render-delay", "Render Delay",
-          "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
-          DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+          G_PARAM_READABLE));
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
@@ -514,27 +434,16 @@
 
   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
   bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
-  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);
-  }
+  if (bclass->get_caps)
+    caps = bclass->get_caps (bsink);
+
   if (caps == NULL) {
-    if (bclass->get_caps)
-      caps = bclass->get_caps (bsink);
-
-    if (caps == NULL) {
-      GstPadTemplate *pad_template;
-
-      pad_template =
-          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));
-      }
+    GstPadTemplate *pad_template;
+
+    pad_template =
+        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));
     }
   }
   gst_object_unref (bsink);
@@ -552,6 +461,18 @@
   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
   bclass = GST_BASE_SINK_GET_CLASS (bsink);
 
+  if (bsink->pad_mode == GST_ACTIVATE_PULL) {
+    GstPad *peer = gst_pad_get_peer (pad);
+
+    if (peer)
+      res = gst_pad_set_caps (peer, caps);
+    else
+      res = FALSE;
+
+    if (!res)
+      GST_DEBUG_OBJECT (bsink, "peer setcaps() failed");
+  }
+
   if (res && bclass->set_caps)
     res = bclass->set_caps (bsink, caps);
 
@@ -628,8 +549,6 @@
       GST_DEBUG_FUNCPTR (gst_base_sink_event));
   gst_pad_set_chain_function (basesink->sinkpad,
       GST_DEBUG_FUNCPTR (gst_base_sink_chain));
-  gst_pad_set_chain_list_function (basesink->sinkpad,
-      GST_DEBUG_FUNCPTR (gst_base_sink_chain_list));
   gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
 
   basesink->pad_mode = GST_ACTIVATE_NONE;
@@ -642,11 +561,9 @@
 
   basesink->sync = DEFAULT_SYNC;
   basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS;
-  g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
+  gst_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
   priv->async_enabled = DEFAULT_ASYNC;
   priv->ts_offset = DEFAULT_TS_OFFSET;
-  priv->render_delay = DEFAULT_RENDER_DELAY;
-  priv->blocksize = DEFAULT_BLOCKSIZE;
 
   GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
 }
@@ -795,7 +712,7 @@
 {
   g_return_if_fail (GST_IS_BASE_SINK (sink));
 
-  g_atomic_int_set (&sink->priv->qos_enabled, enabled);
+  gst_atomic_int_set (&sink->priv->qos_enabled, enabled);
 }
 
 /**
@@ -848,7 +765,6 @@
 
   GST_PAD_PREROLL_LOCK (sink->sinkpad);
   sink->priv->async_enabled = enabled;
-  GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
   GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
 }
 
@@ -905,7 +821,6 @@
 
   GST_OBJECT_LOCK (sink);
   sink->priv->ts_offset = offset;
-  GST_LOG_OBJECT (sink, "set time offset to %" G_GINT64_FORMAT, offset);
   GST_OBJECT_UNLOCK (sink);
 }
 
@@ -976,21 +891,15 @@
 {
   GstBuffer *old;
 
+  if (buffer)
+    gst_buffer_ref (buffer);
+
   GST_OBJECT_LOCK (sink);
   old = sink->priv->last_buffer;
-  if (G_LIKELY (old != buffer)) {
-    GST_DEBUG_OBJECT (sink, "setting last buffer to %p", buffer);
-    if (G_LIKELY (buffer))
-      gst_buffer_ref (buffer);
-    sink->priv->last_buffer = buffer;
-  } else {
-    old = NULL;
-  }
+  sink->priv->last_buffer = buffer;
   GST_OBJECT_UNLOCK (sink);
 
-  /* avoid unreffing with the lock because cleanup code might want to take the
-   * lock too */
-  if (G_LIKELY (old))
+  if (old)
     gst_buffer_unref (old);
 }
 
@@ -1053,7 +962,7 @@
     GstClockTime * max_latency)
 {
   gboolean l, us_live, res, have_latency;
-  GstClockTime min, max, render_delay;
+  GstClockTime min, max;
   GstQuery *query;
   GstClockTime us_min, us_max;
 
@@ -1061,7 +970,6 @@
   GST_OBJECT_LOCK (sink);
   l = sink->sync;
   have_latency = sink->priv->have_latency;
-  render_delay = sink->priv->render_delay;
   GST_OBJECT_UNLOCK (sink);
 
   /* assume no latency */
@@ -1069,16 +977,19 @@
   max = -1;
   us_live = FALSE;
 
-  if (have_latency) {
-    GST_DEBUG_OBJECT (sink, "we are ready for LATENCY query");
-    /* we are ready for a latency query this is when we preroll or when we are
-     * not async. */
-    query = gst_query_new_latency ();
-
-    /* ask the peer for the latency */
-    if ((res = gst_base_sink_peer_query (sink, query))) {
+  /* we are live */
+  if (l) {
+    if (have_latency) {
+      /* we are live and ready for a latency query */
+      query = gst_query_new_latency ();
+
+      /* ask the peer for the latency */
+      if (!(res = gst_base_sink_peer_query (sink, query)))
+        goto query_failed;
+
       /* get upstream min and max latency */
       gst_query_parse_latency (query, &us_live, &us_min, &us_max);
+      gst_query_unref (query);
 
       if (us_live) {
         /* upstream live, use its latency, subclasses should use these
@@ -1086,170 +997,37 @@
         min = us_min;
         max = us_max;
       }
-      if (l) {
-        /* we need to add the render delay if we are live */
-        if (min != -1)
-          min += render_delay;
-        if (max != -1)
-          max += render_delay;
-      }
+    } else {
+      /* we are live but are not yet ready for a latency query */
+      res = FALSE;
     }
-    gst_query_unref (query);
   } else {
-    GST_DEBUG_OBJECT (sink, "we are not yet ready for LATENCY query");
-    res = FALSE;
-  }
-
-  /* not live, we tried to do the query, if it failed we return TRUE anyway */
-  if (!res) {
-    if (!l) {
-      res = TRUE;
-      GST_DEBUG_OBJECT (sink, "latency query failed but we are not live");
-    } else {
-      GST_DEBUG_OBJECT (sink, "latency query failed and we are live");
-    }
-  }
-
-  if (res) {
-    GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d,"
-        " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l,
-        have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
-
-    if (live)
-      *live = l;
-    if (upstream_live)
-      *upstream_live = us_live;
-    if (min_latency)
-      *min_latency = min;
-    if (max_latency)
-      *max_latency = max;
+    /* not live, result is always TRUE */
+    res = TRUE;
   }
-  return res;
-}
-
-/**
- * gst_base_sink_set_render_delay:
- * @sink: a #GstBaseSink
- * @delay: the new delay
- *
- * Set the render delay in @sink to @delay. The render delay is the time 
- * between actual rendering of a buffer and its synchronisation time. Some
- * devices might delay media rendering which can be compensated for with this
- * function. 
- *
- * After calling this function, this sink will report additional latency and
- * other sinks will adjust their latency to delay the rendering of their media.
- *
- * This function is usually called by subclasses.
- *
- * Since: 0.10.21
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-void
-gst_base_sink_set_render_delay (GstBaseSink * sink, GstClockTime delay)
-{
-  GstClockTime old_render_delay;
-
-  g_return_if_fail (GST_IS_BASE_SINK (sink));
-
-  GST_OBJECT_LOCK (sink);
-  old_render_delay = sink->priv->render_delay;
-  sink->priv->render_delay = delay;
-  GST_LOG_OBJECT (sink, "set render delay to %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (delay));
-  GST_OBJECT_UNLOCK (sink);
-
-  if (delay != old_render_delay) {
-    GST_DEBUG_OBJECT (sink, "posting latency changed");
-    gst_element_post_message (GST_ELEMENT_CAST (sink),
-        gst_message_new_latency (GST_OBJECT_CAST (sink)));
-  }
-}
-
-/**
- * gst_base_sink_get_render_delay:
- * @sink: a #GstBaseSink
- *
- * Get the render delay of @sink. see gst_base_sink_set_render_delay() for more
- * information about the render delay.
- *
- * Returns: the render delay of @sink.
- *
- * Since: 0.10.21
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-GstClockTime
-gst_base_sink_get_render_delay (GstBaseSink * sink)
-{
-  GstClockTimeDiff res;
-
-  g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
-
-  GST_OBJECT_LOCK (sink);
-  res = sink->priv->render_delay;
-  GST_OBJECT_UNLOCK (sink);
+
+  GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d,"
+      " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l,
+      have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
+
+  if (live)
+    *live = l;
+  if (upstream_live)
+    *upstream_live = us_live;
+  if (min_latency)
+    *min_latency = min;
+  if (max_latency)
+    *max_latency = max;
 
   return res;
-}
-
-/**
- * gst_base_sink_set_blocksize:
- * @sink: a #GstBaseSink
- * @blocksize: the blocksize in bytes
- *
- * Set the number of bytes that the sink will pull when it is operating in pull
- * mode.
- *
- * Since: 0.10.22
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-void
-gst_base_sink_set_blocksize (GstBaseSink * sink, guint blocksize)
-{
-  g_return_if_fail (GST_IS_BASE_SINK (sink));
-
-  GST_OBJECT_LOCK (sink);
-  sink->priv->blocksize = blocksize;
-  GST_LOG_OBJECT (sink, "set blocksize to %u", blocksize);
-  GST_OBJECT_UNLOCK (sink);
-}
-
-/**
- * gst_base_sink_get_blocksize:
- * @sink: a #GstBaseSink
- *
- * Get the number of bytes that the sink will pull when it is operating in pull
- * mode.
- *
- * Returns: the number of bytes @sink will pull in pull mode.
- *
- * Since: 0.10.22
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-guint
-gst_base_sink_get_blocksize (GstBaseSink * sink)
-{
-  guint res;
-
-  g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
-
-  GST_OBJECT_LOCK (sink);
-  res = sink->priv->blocksize;
-  GST_OBJECT_UNLOCK (sink);
-
-  return res;
+
+  /* ERRORS */
+query_failed:
+  {
+    GST_DEBUG_OBJECT (sink, "latency query failed");
+    gst_query_unref (query);
+    return FALSE;
+  }
 }
 
 static void
@@ -1280,12 +1058,6 @@
     case PROP_TS_OFFSET:
       gst_base_sink_set_ts_offset (sink, g_value_get_int64 (value));
       break;
-    case PROP_BLOCKSIZE:
-      gst_base_sink_set_blocksize (sink, g_value_get_uint (value));
-      break;
-    case PROP_RENDER_DELAY:
-      gst_base_sink_set_render_delay (sink, g_value_get_uint64 (value));
-      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1322,12 +1094,6 @@
     case PROP_LAST_BUFFER:
       gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink));
       break;
-    case PROP_BLOCKSIZE:
-      g_value_set_uint (value, gst_base_sink_get_blocksize (sink));
-      break;
-    case PROP_RENDER_DELAY:
-      g_value_set_uint64 (value, gst_base_sink_get_render_delay (sink));
-      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1370,7 +1136,6 @@
   basesink->eos = FALSE;
   basesink->priv->received_eos = FALSE;
   basesink->have_preroll = FALSE;
-  basesink->priv->step_unlock = FALSE;
   basesink->eos_queued = FALSE;
   basesink->preroll_queued = 0;
   basesink->buffers_queued = 0;
@@ -1439,6 +1204,7 @@
   gboolean post_paused = FALSE;
   gboolean post_async_done = FALSE;
   gboolean post_playing = FALSE;
+  gboolean sync;
 
   /* we are certainly not playing async anymore now */
   basesink->playing_async = FALSE;
@@ -1448,6 +1214,7 @@
   next = GST_STATE_NEXT (basesink);
   pending = GST_STATE_PENDING (basesink);
   post_pending = pending;
+  sync = basesink->sync;
 
   switch (pending) {
     case GST_STATE_PLAYING:
@@ -1470,7 +1237,6 @@
 
       /* 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;
@@ -1568,227 +1334,6 @@
   }
 }
 
-static void
-start_stepping (GstBaseSink * sink, GstSegment * segment,
-    GstStepInfo * pending, GstStepInfo * current)
-{
-  gint64 end;
-  GstMessage *message;
-
-  GST_DEBUG_OBJECT (sink, "update pending step");
-
-  GST_OBJECT_LOCK (sink);
-  memcpy (current, pending, sizeof (GstStepInfo));
-  pending->valid = FALSE;
-  GST_OBJECT_UNLOCK (sink);
-
-  /* post message first */
-  message =
-      gst_message_new_step_start (GST_OBJECT (sink), TRUE, current->format,
-      current->amount, current->rate, current->flush, current->intermediate);
-  gst_message_set_seqnum (message, current->seqnum);
-  gst_element_post_message (GST_ELEMENT (sink), message);
-
-  /* get the running time of where we paused and remember it */
-  current->start = gst_element_get_start_time (GST_ELEMENT_CAST (sink));
-  gst_segment_set_running_time (segment, GST_FORMAT_TIME, current->start);
-
-  /* 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)
-    current->start_stop = segment->stop;
-  else
-    current->start_start = segment->start;
-
-  if (current->format == GST_FORMAT_TIME) {
-    end = current->start + current->amount;
-    if (!current->flush) {
-      /* 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;
-      } else {
-        gint64 position;
-
-        position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
-        segment->time = position;
-        segment->start = position;
-        segment->last_stop = 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, "step started at running_time %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (current->start));
-
-  if (current->amount == -1) {
-    GST_DEBUG_OBJECT (sink, "step amount == -1, stop stepping");
-    current->valid = FALSE;
-  } else {
-    GST_DEBUG_OBJECT (sink, "step amount: %" G_GUINT64_FORMAT ", format: %s, "
-        "rate: %f", current->amount, gst_format_get_name (current->format),
-        current->rate);
-  }
-}
-
-static void
-stop_stepping (GstBaseSink * sink, GstSegment * segment,
-    GstStepInfo * current, gint64 rstart, gint64 rstop, gboolean eos)
-{
-  gint64 stop, position;
-  GstMessage *message;
-
-  GST_DEBUG_OBJECT (sink, "step complete");
-
-  if (segment->rate > 0.0)
-    stop = rstart;
-  else
-    stop = rstop;
-
-  GST_DEBUG_OBJECT (sink,
-      "step stop at running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (stop));
-
-  if (stop == -1)
-    current->duration = current->position;
-  else
-    current->duration = stop - current->start;
-
-  GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (current->duration));
-
-  position = current->start + current->duration;
-
-  /* now move the segment to the new running time */
-  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;
-  } else {
-    /* start time is now the stepped position */
-    gst_element_set_start_time (GST_ELEMENT_CAST (sink), position);
-  }
-
-  /* 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;
-  else
-    segment->start = current->start_start;
-
-  /* the clip segment is used for position report in paused... */
-  memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment));
-
-  /* post the step done when we know the stepped duration in TIME */
-  message =
-      gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
-      current->amount, current->rate, current->flush, current->intermediate,
-      current->duration, eos);
-  gst_message_set_seqnum (message, current->seqnum);
-  gst_element_post_message (GST_ELEMENT_CAST (sink), message);
-
-  if (!current->intermediate)
-    sink->need_preroll = current->need_preroll;
-
-  /* and the current step info finished and becomes invalid */
-  current->valid = FALSE;
-}
-
-static gboolean
-handle_stepping (GstBaseSink * sink, GstSegment * segment,
-    GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart,
-    gint64 * rstop)
-{
-  GstBaseSinkPrivate *priv;
-  gboolean step_end = FALSE;
-
-  priv = sink->priv;
-
-  /* see if we need to skip this buffer because of stepping */
-  switch (current->format) {
-    case GST_FORMAT_TIME:
-    {
-      guint64 end;
-      gint64 first, last;
-
-      if (segment->rate > 0.0) {
-        first = *rstart;
-        last = *rstop;
-      } else {
-        first = *rstop;
-        last = *rstart;
-      }
-
-      end = current->start + current->amount;
-      current->position = first - current->start;
-
-      if (G_UNLIKELY (segment->abs_rate != 1.0))
-        current->position /= segment->abs_rate;
-
-      GST_DEBUG_OBJECT (sink,
-          "buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
-          GST_TIME_ARGS (first), GST_TIME_ARGS (last));
-      GST_DEBUG_OBJECT (sink,
-          "got time step %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "/%"
-          GST_TIME_FORMAT, GST_TIME_ARGS (current->position),
-          GST_TIME_ARGS (last - current->start),
-          GST_TIME_ARGS (current->amount));
-
-      if ((current->flush && current->position >= current->amount)
-          || last >= end) {
-        GST_DEBUG_OBJECT (sink, "step ended, we need clipping");
-        step_end = TRUE;
-        if (segment->rate > 0.0) {
-          *rstart = end;
-          *cstart = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
-        } else {
-          *rstop = end;
-          *cstop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
-        }
-      }
-      GST_DEBUG_OBJECT (sink,
-          "cstart %" GST_TIME_FORMAT ", rstart %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (*cstart), GST_TIME_ARGS (*rstart));
-      GST_DEBUG_OBJECT (sink,
-          "cstop %" GST_TIME_FORMAT ", rstop %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (*cstop), GST_TIME_ARGS (*rstop));
-      break;
-    }
-    case GST_FORMAT_BUFFERS:
-      GST_DEBUG_OBJECT (sink,
-          "got default step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
-          current->position, current->amount);
-
-      if (current->position < current->amount) {
-        current->position++;
-      } else {
-        step_end = TRUE;
-      }
-      break;
-    case GST_FORMAT_DEFAULT:
-    default:
-      GST_DEBUG_OBJECT (sink,
-          "got unknown step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
-          current->position, current->amount);
-      break;
-  }
-  return step_end;
-}
 
 /* with STREAM_LOCK, PREROLL_LOCK
  *
@@ -1802,8 +1347,7 @@
 gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
     GstClockTime * rsstart, GstClockTime * rsstop,
     GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync,
-    gboolean * stepped, GstSegment * segment, GstStepInfo * step,
-    gboolean * step_end)
+    GstSegment * segment)
 {
   GstBaseSinkClass *bclass;
   GstBuffer *buffer;
@@ -1813,12 +1357,11 @@
   GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */
   GstFormat format;
   GstBaseSinkPrivate *priv;
-  gboolean eos;
 
   priv = basesink->priv;
 
   /* start with nothing */
-  start = stop = -1;
+  start = stop = sstart = sstop = rstart = rstop = -1;
 
   if (G_UNLIKELY (GST_IS_EVENT (obj))) {
     GstEvent *event = GST_EVENT_CAST (obj);
@@ -1826,58 +1369,33 @@
     switch (GST_EVENT_TYPE (event)) {
         /* EOS event needs syncing */
       case GST_EVENT_EOS:
-      {
-        if (basesink->segment.rate >= 0.0) {
-          sstart = sstop = priv->current_sstop;
-          if (sstart == -1) {
-            /* we have not seen a buffer yet, use the segment values */
-            sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
-                basesink->segment.format, basesink->segment.stop);
-          }
-        } else {
-          sstart = sstop = priv->current_sstart;
-          if (sstart == -1) {
-            /* we have not seen a buffer yet, use the segment values */
-            sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
-                basesink->segment.format, basesink->segment.start);
-          }
-        }
-
+        sstart = sstop = priv->current_sstop;
         rstart = rstop = priv->eos_rtime;
         *do_sync = rstart != -1;
         GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT,
             GST_TIME_ARGS (rstart));
-        /* if we are stepping, we end now */
-        *step_end = step->valid;
-        eos = TRUE;
-        goto eos_done;
-      }
-      default:
+        goto done;
         /* 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.
          */
+      default:
         return FALSE;
     }
   }
 
-  eos = FALSE;
-
   /* else do buffer sync code */
   buffer = GST_BUFFER_CAST (obj);
 
   bclass = GST_BASE_SINK_GET_CLASS (basesink);
 
-  /* just get the times to see if we need syncing, if the start returns -1 we
-   * don't sync. */
+  /* just get the times to see if we need syncing */
   if (bclass->get_times)
     bclass->get_times (basesink, buffer, &start, &stop);
 
   if (start == -1) {
-    /* we don't need to sync but we still want to get the timestamps for
-     * tracking the position */
     gst_base_sink_get_times (basesink, buffer, &start, &stop);
     *do_sync = FALSE;
   } else {
@@ -1891,33 +1409,19 @@
   /* collect segment and format for code clarity */
   format = segment->format;
 
-  /* no timestamp clipping if we did not get a TIME 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 */
+  /* clip */
   if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
-              (gint64) start, (gint64) 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 */
-      if (segment->rate > 0.0) {
-        cstart = segment->stop;
-        cstop = segment->stop;
-      } else {
-        cstart = segment->start;
-        cstop = segment->start;
-      }
-      goto do_times;
-    }
+              (gint64) start, (gint64) stop, &cstart, &cstop)))
     goto out_of_segment;
-  }
 
   if (G_UNLIKELY (start != cstart || stop != cstop)) {
     GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT
@@ -1926,35 +1430,17 @@
   }
 
   /* set last stop position */
-  if (G_LIKELY (cstop != GST_CLOCK_TIME_NONE))
-    gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
-  else
-    gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart);
+  gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
 
 do_times:
-  rstart = gst_segment_to_running_time (segment, format, cstart);
-  rstop = gst_segment_to_running_time (segment, format, cstop);
-
-  if (G_UNLIKELY (step->valid)) {
-    if (!(*step_end = handle_stepping (basesink, segment, step, &cstart, &cstop,
-                &rstart, &rstop))) {
-      /* step is still busy, we discard data when we are flushing */
-      *stepped = step->flush;
-    }
-  }
   /* this can produce wrong values if we accumulated non-TIME segments. If this happens,
    * upstream is behaving very badly */
   sstart = gst_segment_to_stream_time (segment, format, cstart);
   sstop = gst_segment_to_stream_time (segment, format, cstop);
-
-eos_done:
-  /* eos_done label only called when doing EOS, we also stop stepping then */
-  if (*step_end && step->flush) {
-    GST_DEBUG_OBJECT (basesink, "flushing step ended");
-    stop_stepping (basesink, segment, step, rstart, rstop, eos);
-    *step_end = FALSE;
-  }
-
+  rstart = gst_segment_to_running_time (segment, format, cstart);
+  rstop = gst_segment_to_running_time (segment, format, cstop);
+
+done:
   /* save times */
   *rsstart = sstart;
   *rsstop = sstop;
@@ -1967,25 +1453,49 @@
   /* special cases */
 out_of_segment:
   {
-    /* we usually clip in the chain function already but stepping could cause
-     * the segment to be updated later. we return FALSE so that we don't try
-     * to sync on it. */
+    /* should not happen since we clip them in the chain function already, 
+     * we return FALSE so that we don't try to sync on it. */
+    GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
+        (NULL), ("unexpected buffer out of segment found."));
     GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
     return FALSE;
   }
 }
 
-/* with STREAM_LOCK, PREROLL_LOCK, LOCK
- * adjust a timestamp with the latency and timestamp offset */
-static GstClockTime
-gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time)
+/* with STREAM_LOCK, PREROLL_LOCK
+ *
+ * Waits for the clock to reach @time. If @time is not valid, no
+ * synchronisation is done and BADTIME is returned. 
+ * If synchronisation is disabled in the element or there is no
+ * clock, no synchronisation is done and BADTIME is returned.
+ *
+ * Else a blocking wait is performed on the clock. We save the ClockID
+ * so we can unlock the entry at any time. While we are blocking, we 
+ * release the PREROLL_LOCK so that other threads can interrupt the entry.
+ *
+ * @time is expressed in running time.
+ */
+static GstClockReturn
+gst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time,
+    GstClockTimeDiff * jitter)
 {
+  GstClockID id;
+  GstClockReturn ret;
+  GstClock *clock;
   GstClockTimeDiff ts_offset;
 
-  /* don't do anything funny with invalid timestamps */
   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
-    return time;
-
+    goto invalid_time;
+
+  GST_OBJECT_LOCK (basesink);
+  if (G_UNLIKELY (!basesink->sync))
+    goto no_sync;
+
+  if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
+    goto no_clock;
+
+  /* add base time and latency */
+  time += GST_ELEMENT_CAST (basesink)->base_time;
   time += basesink->priv->latency;
 
   /* apply offset, be carefull for underflows */
@@ -1999,94 +1509,37 @@
   } else
     time += ts_offset;
 
-  return time;
-}
-
-/**
- * gst_base_sink_wait_clock:
- * @sink: the sink
- * @time: the running_time to be reached
- * @jitter: the jitter to be filled with time diff (can be NULL)
- *
- * This function will block until @time is reached. It is usually called by
- * subclasses that use their own internal synchronisation.
- *
- * If @time is not valid, no sycnhronisation is done and #GST_CLOCK_BADTIME is
- * returned. Likewise, if synchronisation is disabled in the element or there
- * is no clock, no synchronisation is done and #GST_CLOCK_BADTIME is returned.
- *
- * This function should only be called with the PREROLL_LOCK held, like when
- * receiving an EOS event in the ::event vmethod or when receiving a buffer in
- * the ::render vmethod.
- *
- * The @time argument should be the running_time of when this method should
- * return and is not adjusted with any latency or offset configured in the
- * sink.
- *
- * Since 0.10.20
- *
- * Returns: #GstClockReturn
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-GstClockReturn
-gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
-    GstClockTimeDiff * jitter)
-{
-  GstClockID id;
-  GstClockReturn ret;
-  GstClock *clock;
-
-  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
-    goto invalid_time;
-
-  GST_OBJECT_LOCK (sink);
-  if (G_UNLIKELY (!sink->sync))
-    goto no_sync;
-
-  if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (sink)) == NULL))
-    goto no_clock;
-
-  /* add base_time to running_time to get the time against the clock */
-  time += GST_ELEMENT_CAST (sink)->base_time;
-
   id = gst_clock_new_single_shot_id (clock, time);
-  GST_OBJECT_UNLOCK (sink);
-
-  /* A blocking wait is performed on the clock. We save the ClockID
-   * so we can unlock the entry at any time. While we are blocking, we 
-   * release the PREROLL_LOCK so that other threads can interrupt the
-   * entry. */
-  sink->clock_id = id;
+  GST_OBJECT_UNLOCK (basesink);
+
+  basesink->clock_id = id;
   /* release the preroll lock while waiting */
-  GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+  GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
 
   ret = gst_clock_id_wait (id, jitter);
 
-  GST_PAD_PREROLL_LOCK (sink->sinkpad);
+  GST_PAD_PREROLL_LOCK (basesink->sinkpad);
   gst_clock_id_unref (id);
-  sink->clock_id = NULL;
+  basesink->clock_id = NULL;
 
   return ret;
 
   /* no syncing needed */
 invalid_time:
   {
-    GST_DEBUG_OBJECT (sink, "time not valid, no sync needed");
+    GST_DEBUG_OBJECT (basesink, "time not valid, no sync needed");
     return GST_CLOCK_BADTIME;
   }
 no_sync:
   {
-    GST_DEBUG_OBJECT (sink, "sync disabled");
-    GST_OBJECT_UNLOCK (sink);
+    GST_DEBUG_OBJECT (basesink, "sync disabled");
+    GST_OBJECT_UNLOCK (basesink);
     return GST_CLOCK_BADTIME;
   }
 no_clock:
   {
-    GST_DEBUG_OBJECT (sink, "no clock, can't sync");
-    GST_OBJECT_UNLOCK (sink);
+    GST_DEBUG_OBJECT (basesink, "no clock, can't sync");
+    GST_OBJECT_UNLOCK (basesink);
     return GST_CLOCK_BADTIME;
   }
 }
@@ -2104,9 +1557,6 @@
  * to a state change to READY or a FLUSH event (in which case this function
  * returns #GST_FLOW_WRONG_STATE).
  *
- * This function should only be called with the PREROLL_LOCK held, like in the
- * render function.
- *
  * Since: 0.10.11
  *
  * Returns: #GST_FLOW_OK if the preroll completed and processing can
@@ -2126,8 +1576,6 @@
   sink->have_preroll = FALSE;
   if (G_UNLIKELY (sink->flushing))
     goto stopping;
-  if (G_UNLIKELY (sink->priv->step_unlock))
-    goto step_unlocked;
   GST_DEBUG_OBJECT (sink, "continue after preroll");
 
   return GST_FLOW_OK;
@@ -2135,71 +1583,9 @@
   /* ERRORS */
 stopping:
   {
-    GST_DEBUG_OBJECT (sink, "preroll interrupted because of flush");
+    GST_DEBUG_OBJECT (sink, "preroll interrupted");
     return GST_FLOW_WRONG_STATE;
   }
-step_unlocked:
-  {
-    sink->priv->step_unlock = FALSE;
-    GST_DEBUG_OBJECT (sink, "preroll interrupted because of step");
-    return GST_FLOW_STEP;
-  }
-}
-
-/**
- * gst_base_sink_do_preroll:
- * @sink: the sink
- * @obj: the object that caused the preroll
- *
- * If the @sink spawns its own thread for pulling buffers from upstream it
- * should call this method after it has pulled a buffer. If the element needed
- * to preroll, this function will perform the preroll and will then block
- * until the element state is changed.
- *
- * This function should be called with the PREROLL_LOCK held.
- *
- * Since 0.10.22
- *
- * Returns: #GST_FLOW_OK if the preroll completed and processing can
- * continue. Any other return value should be returned from the render vmethod.
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-GstFlowReturn
-gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj)
-{
-  GstFlowReturn ret;
-
-  while (G_UNLIKELY (sink->need_preroll)) {
-    GST_DEBUG_OBJECT (sink, "prerolling object %p", obj);
-
-    ret = gst_base_sink_preroll_object (sink, FALSE, obj);
-    if (ret != GST_FLOW_OK)
-      goto preroll_failed;
-
-    /* need to recheck here because the commit state could have
-     * made us not need the preroll anymore */
-    if (G_LIKELY (sink->need_preroll)) {
-      /* block until the state changes, or we get a flush, or something */
-      ret = gst_base_sink_wait_preroll (sink);
-      if (ret != GST_FLOW_OK) {
-        if (ret == GST_FLOW_STEP)
-          ret = GST_FLOW_OK;
-        else
-          goto preroll_failed;
-      }
-    }
-  }
-  return GST_FLOW_OK;
-
-  /* ERRORS */
-preroll_failed:
-  {
-    GST_DEBUG_OBJECT (sink, "preroll failed %d", ret);
-    return ret;
-  }
 }
 
 /**
@@ -2215,9 +1601,6 @@
  * This function should only be called with the PREROLL_LOCK held, like when
  * receiving an EOS event in the ::event vmethod.
  *
- * The @time argument should be the running_time of when the EOS should happen
- * and will be adjusted with any latency and offset configured in the sink.
- *
  * Since 0.10.15
  *
  * Returns: #GstFlowReturn
@@ -2234,32 +1617,22 @@
   GstFlowReturn ret;
 
   do {
-    GstClockTime stime;
-
     GST_DEBUG_OBJECT (sink, "checking preroll");
 
     /* first wait for the playing state before we can continue */
     if (G_UNLIKELY (sink->need_preroll)) {
       ret = gst_base_sink_wait_preroll (sink);
-      if (ret != GST_FLOW_OK) {
-        if (ret == GST_FLOW_STEP)
-          ret = GST_FLOW_OK;
-        else
-          goto flushing;
-      }
+      if (ret != GST_FLOW_OK)
+        goto flushing;
     }
 
     /* preroll done, we can sync since we are in PLAYING now. */
     GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %"
         GST_TIME_FORMAT, GST_TIME_ARGS (time));
 
-    /* compensate for latency and ts_offset. We don't adjust for render delay
-     * because we don't interact with the device on EOS normally. */
-    stime = gst_base_sink_adjust_time (sink, time);
-
     /* wait for the clock, this can be interrupted because we got shut down or 
      * we PAUSED. */
-    status = gst_base_sink_wait_clock (sink, stime, jitter);
+    status = gst_base_sink_wait_clock (sink, time, jitter);
 
     GST_DEBUG_OBJECT (sink, "clock returned %d", status);
 
@@ -2311,38 +1684,25 @@
  */
 static GstFlowReturn
 gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,
-    GstMiniObject * obj, gboolean * late, gboolean * step_end)
+    GstMiniObject * obj, gboolean * late)
 {
   GstClockTimeDiff jitter;
   gboolean syncable;
   GstClockReturn status = GST_CLOCK_OK;
-  GstClockTime rstart, rstop, sstart, sstop, stime;
+  GstClockTime rstart, rstop, sstart, sstop;
   gboolean do_sync;
   GstBaseSinkPrivate *priv;
-  GstFlowReturn ret;
-  GstStepInfo *current, *pending;
-  gboolean stepped;
 
   priv = basesink->priv;
 
-do_step:
   sstart = sstop = rstart = rstop = -1;
   do_sync = TRUE;
-  stepped = FALSE;
 
   priv->current_rstart = -1;
 
-  /* get stepping info */
-  current = &priv->current_step;
-  pending = &priv->pending_step;
-
   /* get timing information for this object against the render segment */
   syncable = gst_base_sink_get_sync_times (basesink, obj,
-      &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment,
-      current, step_end);
-
-  if (G_UNLIKELY (stepped))
-    goto step_skipped;
+      &sstart, &sstop, &rstart, &rstop, &do_sync, &basesink->segment);
 
   /* a syncable object needs to participate in preroll and
    * clocking. All buffers and EOS are syncable. */
@@ -2352,17 +1712,31 @@
   /* store timing info for current object */
   priv->current_rstart = rstart;
   priv->current_rstop = (rstop != -1 ? rstop : rstart);
-
   /* save sync time for eos when the previous object needed sync */
   priv->eos_rtime = (do_sync ? priv->current_rstop : -1);
 
 again:
   /* first do preroll, this makes sure we commit our state
    * to PAUSED and can continue to PLAYING. We cannot perform
-   * any clock sync in PAUSED because there is no clock. */
-  ret = gst_base_sink_do_preroll (basesink, obj);
-  if (G_UNLIKELY (ret != GST_FLOW_OK))
-    goto preroll_failed;
+   * any clock sync in PAUSED because there is no clock. 
+   */
+  while (G_UNLIKELY (basesink->need_preroll)) {
+    GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
+
+    if (G_LIKELY (basesink->playing_async)) {
+      /* commit state */
+      if (G_UNLIKELY (!gst_base_sink_commit_state (basesink)))
+        goto stopping;
+    }
+
+    /* need to recheck here because the commit state could have
+     * made us not need the preroll anymore */
+    if (G_LIKELY (basesink->need_preroll)) {
+      /* block until the state changes, or we get a flush, or something */
+      if (gst_base_sink_wait_preroll (basesink) != GST_FLOW_OK)
+        goto flushing;
+    }
+  }
 
   /* After rendering we store the position of the last buffer so that we can use
    * it to report the position. We need to take the lock here. */
@@ -2371,35 +1745,16 @@
   priv->current_sstop = (sstop != -1 ? sstop : sstart);
   GST_OBJECT_UNLOCK (basesink);
 
-  /* update the segment with a pending step if the current one is invalid and we
-   * have a new pending one. We only accept new step updates after a preroll */
-  if (G_UNLIKELY (pending->valid && !current->valid)) {
-    start_stepping (basesink, &basesink->segment, pending, current);
-    goto do_step;
-  }
-
   if (!do_sync)
     goto done;
 
-  /* adjust for latency */
-  stime = gst_base_sink_adjust_time (basesink, rstart);
-
-  /* adjust for render-delay, avoid underflows */
-  if (stime != -1) {
-    if (stime > priv->render_delay)
-      stime -= priv->render_delay;
-    else
-      stime = 0;
-  }
-
   /* preroll done, we can sync since we are in PLAYING now. */
   GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %"
-      GST_TIME_FORMAT ", adjusted %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (rstart), GST_TIME_ARGS (stime));
-
-  /* This function will return immediatly if start == -1, no clock
+      GST_TIME_FORMAT, GST_TIME_ARGS (rstart));
+
+  /* this function will return immediatly if start == -1, no clock
    * or sync is disabled with GST_CLOCK_BADTIME. */
-  status = gst_base_sink_wait_clock (basesink, stime, &jitter);
+  status = gst_base_sink_wait_clock (basesink, rstart, &jitter);
 
   GST_DEBUG_OBJECT (basesink, "clock returned %d", status);
 
@@ -2415,7 +1770,6 @@
    * we can try to preroll on the current buffer. */
   if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
     GST_DEBUG_OBJECT (basesink, "unscheduled, waiting some more");
-    priv->call_preroll = TRUE;
     goto again;
   }
 
@@ -2430,12 +1784,6 @@
   return GST_FLOW_OK;
 
   /* ERRORS */
-step_skipped:
-  {
-    GST_DEBUG_OBJECT (basesink, "skipped stepped object %p", obj);
-    *late = TRUE;
-    return GST_FLOW_OK;
-  }
 not_syncable:
   {
     GST_DEBUG_OBJECT (basesink, "non syncable object %p", obj);
@@ -2446,11 +1794,10 @@
     GST_DEBUG_OBJECT (basesink, "we are flushing");
     return GST_FLOW_WRONG_STATE;
   }
-preroll_failed:
+stopping:
   {
-    GST_DEBUG_OBJECT (basesink, "preroll failed");
-    *step_end = FALSE;
-    return ret;
+    GST_DEBUG_OBJECT (basesink, "stopping while commiting state");
+    return GST_FLOW_WRONG_STATE;
   }
 }
 
@@ -2488,9 +1835,6 @@
 
   start = priv->current_rstart;
 
-  if (priv->current_step.valid)
-    return;
-
   /* if Quality-of-Service disabled, do nothing */
   if (!g_atomic_int_get (&priv->qos_enabled) || start == -1)
     return;
@@ -2498,19 +1842,10 @@
   stop = priv->current_rstop;
   jitter = priv->current_jitter;
 
-  if (jitter < 0) {
-    /* this is the time the buffer entered the sink */
-    if (start < -jitter)
-      entered = 0;
-    else
-      entered = start + jitter;
-    left = start;
-  } else {
-    /* this is the time the buffer entered the sink */
-    entered = start + jitter;
-    /* this is the time the buffer left the sink */
-    left = start + jitter;
-  }
+  /* this is the time the buffer entered the sink */
+  entered = start + jitter;
+  /* this is the time the buffer left the sink */
+  left = start + (jitter < 0 ? 0 : jitter);
 
   /* calculate duration of the buffer */
   if (stop != -1)
@@ -2578,14 +1913,8 @@
       GST_TIME_ARGS (priv->avg_pt), priv->avg_rate);
 
 
+  /* if we have a valid rate, start sending QoS messages */
   if (priv->avg_rate >= 0.0) {
-    /* if we have a valid rate, start sending QoS messages */
-    if (priv->current_jitter < 0) {
-      /* make sure we never go below 0 when adding the jitter to the
-       * timestamp. */
-      if (priv->current_rstart < -priv->current_jitter)
-        priv->current_jitter = -priv->current_rstart;
-    }
     gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart,
         priv->current_jitter);
   }
@@ -2661,18 +1990,14 @@
 
   /* if the jitter bigger than duration and lateness we are too late */
   if ((late = start + jitter > max_lateness)) {
-    GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink,
-        "buffer is too late %" GST_TIME_FORMAT
+    GST_DEBUG_OBJECT (basesink, "buffer is too late %" GST_TIME_FORMAT
         " > %" GST_TIME_FORMAT, GST_TIME_ARGS (start + jitter),
         GST_TIME_ARGS (max_lateness));
     /* !!emergency!!, if we did not receive anything valid for more than a 
      * second, render it anyway so the user sees something */
-    if (priv->last_in_time != -1 && start - priv->last_in_time > GST_SECOND) {
+    if (priv->last_in_time && start - priv->last_in_time > GST_SECOND) {
       late = FALSE;
-      GST_ELEMENT_WARNING (basesink, CORE, CLOCK,
-          (_("A lot of buffers are being dropped.")),
-          ("There may be a timestamping problem, or this computer is too slow."));
-      GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink,
+      GST_DEBUG_OBJECT (basesink,
           "**emergency** last buffer at %" GST_TIME_FORMAT " > GST_SECOND",
           GST_TIME_ARGS (priv->last_in_time));
     }
@@ -2707,9 +2032,6 @@
   }
 }
 
-/* called before and after calling the render vmethod. It keeps track of how
- * much time was spent in the render method and is used to check if we are
- * flooded */
 static void
 gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start)
 {
@@ -2744,88 +2066,53 @@
  */
 static GstFlowReturn
 gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
-    gboolean is_list, gpointer obj)
+    GstMiniObject * obj)
 {
-  GstFlowReturn ret;
+  GstFlowReturn ret = GST_FLOW_OK;
   GstBaseSinkClass *bclass;
-  gboolean late, step_end;
-  gpointer sync_obj;
-
+  gboolean late = FALSE;
   GstBaseSinkPrivate *priv;
 
   priv = basesink->priv;
 
-  if (is_list) {
-    /*
-     * 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);
-    g_assert (NULL != sync_obj);
-  } else {
-    sync_obj = obj;
-  }
-
-again:
-  late = FALSE;
-  step_end = FALSE;
-  ret = GST_FLOW_OK;
-
   /* synchronize this object, non syncable objects return OK
    * immediatly. */
-  ret = gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end);
+  ret = gst_base_sink_do_sync (basesink, pad, obj, &late);
   if (G_UNLIKELY (ret != GST_FLOW_OK))
     goto sync_failed;
 
-  /* and now render, event or buffer/buffer list. */
-  if (G_LIKELY (is_list || GST_IS_BUFFER (obj))) {
+  /* and now render, event or buffer. */
+  if (G_LIKELY (GST_IS_BUFFER (obj))) {
+    GstBuffer *buf;
+
     /* drop late buffers unconditionally, let's hope it's unlikely */
     if (G_UNLIKELY (late))
       goto dropped;
 
+    buf = GST_BUFFER_CAST (obj);
+
+    gst_base_sink_set_last_buffer (basesink, buf);
+
     bclass = GST_BASE_SINK_GET_CLASS (basesink);
 
-    if (G_LIKELY ((is_list && bclass->render_list) ||
-            (!is_list && bclass->render))) {
+    if (G_LIKELY (bclass->render)) {
       gint do_qos;
 
       /* read once, to get same value before and after */
       do_qos = g_atomic_int_get (&priv->qos_enabled);
 
-      GST_DEBUG_OBJECT (basesink, "rendering object %p", obj);
+      GST_DEBUG_OBJECT (basesink, "rendering buffer %p", obj);
 
       /* record rendering time for QoS and stats */
       if (do_qos)
         gst_base_sink_do_render_stats (basesink, TRUE);
 
-      if (!is_list) {
-        GstBuffer *buf;
-
-        /* For buffer lists do not set last buffer. Creating buffer
-         * with meaningful data can be done only with memcpy which will
-         * significantly affect performance */
-        buf = GST_BUFFER_CAST (obj);
-        gst_base_sink_set_last_buffer (basesink, buf);
-
-        ret = bclass->render (basesink, buf);
-      } else {
-        GstBufferList *buflist;
-
-        buflist = GST_BUFFER_LIST_CAST (obj);
-
-        ret = bclass->render_list (basesink, buflist);
-      }
+      ret = bclass->render (basesink, buf);
+
+      priv->rendered++;
 
       if (do_qos)
         gst_base_sink_do_render_stats (basesink, FALSE);
-
-      if (ret == GST_FLOW_STEP)
-        goto again;
-
-      if (G_UNLIKELY (basesink->flushing))
-        goto flushing;
-
-      priv->rendered++;
     }
   } else {
     GstEvent *event = GST_EVENT_CAST (obj);
@@ -2842,22 +2129,9 @@
     if (bclass->event)
       event_res = bclass->event (basesink, event);
 
-    /* when we get here we could be flushing again when the event handler calls
-     * _wait_eos(). We have to ignore this object in that case. */
-    if (G_UNLIKELY (basesink->flushing))
-      goto flushing;
-
     if (G_LIKELY (event_res)) {
-      guint32 seqnum;
-
-      seqnum = basesink->priv->seqnum = gst_event_get_seqnum (event);
-      GST_DEBUG_OBJECT (basesink, "Got seqnum #%" G_GUINT32_FORMAT, seqnum);
-
       switch (type) {
         case GST_EVENT_EOS:
-        {
-          GstMessage *message;
-
           /* the EOS event is completely handled so we mark
            * ourselves as being in the EOS state. eos is also 
            * protected by the object lock so we can read it when 
@@ -2865,15 +2139,11 @@
           GST_OBJECT_LOCK (basesink);
           basesink->eos = TRUE;
           GST_OBJECT_UNLOCK (basesink);
-
           /* ok, now we can post the message */
           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
-
-          message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
-          gst_message_set_seqnum (message, seqnum);
-          gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
+          gst_element_post_message (GST_ELEMENT_CAST (basesink),
+              gst_message_new_eos (GST_OBJECT_CAST (basesink)));
           break;
-        }
         case GST_EVENT_NEWSEGMENT:
           /* configure the segment */
           gst_base_sink_configure_segment (basesink, pad, event,
@@ -2886,18 +2156,11 @@
   }
 
 done:
-  if (step_end) {
-    /* the step ended, check if we need to activate a new step */
-    GST_DEBUG_OBJECT (basesink, "step ended");
-    stop_stepping (basesink, &basesink->segment, &priv->current_step,
-        priv->current_rstart, priv->current_rstop, basesink->eos);
-    goto again;
-  }
-
   gst_base_sink_perform_qos (basesink, late);
 
   GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
-  gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+  gst_mini_object_unref (obj);
+
   return ret;
 
   /* ERRORS */
@@ -2912,12 +2175,6 @@
     GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
     goto done;
   }
-flushing:
-  {
-    GST_DEBUG_OBJECT (basesink, "we are flushing, ignore object");
-    gst_mini_object_unref (obj);
-    return GST_FLOW_WRONG_STATE;
-  }
 }
 
 /* with STREAM_LOCK, PREROLL_LOCK
@@ -2929,46 +2186,31 @@
  * function does not take ownership of obj.
  */
 static GstFlowReturn
-gst_base_sink_preroll_object (GstBaseSink * basesink, gboolean is_list,
+gst_base_sink_preroll_object (GstBaseSink * basesink, GstPad * pad,
     GstMiniObject * obj)
 {
   GstFlowReturn ret;
 
-  GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
+  GST_DEBUG_OBJECT (basesink, "do preroll %p", obj);
 
   /* if it's a buffer, we need to call the preroll method */
-  if (G_LIKELY (is_list || GST_IS_BUFFER (obj)) && basesink->priv->call_preroll) {
+  if (G_LIKELY (GST_IS_BUFFER (obj))) {
     GstBaseSinkClass *bclass;
     GstBuffer *buf;
     GstClockTime timestamp;
 
-    if (is_list) {
-      buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
-      g_assert (NULL != buf);
-    } else {
-      buf = GST_BUFFER_CAST (obj);
-    }
-
+    buf = GST_BUFFER_CAST (obj);
     timestamp = GST_BUFFER_TIMESTAMP (buf);
 
     GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
         GST_TIME_ARGS (timestamp));
 
-    /*
-     * For buffer lists do not set last buffer. Creating buffer
-     * with meaningful data can be done only with memcpy which will
-     * significantly affect performance
-     */
-    if (!is_list) {
-      gst_base_sink_set_last_buffer (basesink, buf);
-    }
+    gst_base_sink_set_last_buffer (basesink, buf);
 
     bclass = GST_BASE_SINK_GET_CLASS (basesink);
     if (bclass->preroll)
       if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK)
         goto preroll_failed;
-
-    basesink->priv->call_preroll = FALSE;
   }
 
   /* commit state */
@@ -3003,7 +2245,7 @@
  */
 static GstFlowReturn
 gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
-    gboolean is_list, gpointer obj, gboolean prerollable)
+    GstMiniObject * obj, gboolean prerollable)
 {
   GstFlowReturn ret = GST_FLOW_OK;
   gint length;
@@ -3019,7 +2261,7 @@
 
     /* first prerollable item needs to finish the preroll */
     if (length == 1) {
-      ret = gst_base_sink_preroll_object (basesink, is_list, obj);
+      ret = gst_base_sink_preroll_object (basesink, pad, obj);
       if (G_UNLIKELY (ret != GST_FLOW_OK))
         goto preroll_failed;
     }
@@ -3032,6 +2274,7 @@
         goto more_preroll;
     }
   }
+
   /* we can start rendering (or blocking) the queued object
    * if any. */
   q = basesink->preroll_queue;
@@ -3042,13 +2285,13 @@
     GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o);
 
     /* do something with the return value */
-    ret = gst_base_sink_render_object (basesink, pad, FALSE, o);
+    ret = gst_base_sink_render_object (basesink, pad, o);
     if (ret != GST_FLOW_OK)
       goto dequeue_failed;
   }
 
   /* now render the object */
-  ret = gst_base_sink_render_object (basesink, pad, is_list, obj);
+  ret = gst_base_sink_render_object (basesink, pad, obj);
   basesink->preroll_queued = 0;
 
   return ret;
@@ -3058,7 +2301,7 @@
   {
     GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s",
         gst_flow_get_name (ret));
-    gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+    gst_mini_object_unref (obj);
     return ret;
   }
 more_preroll:
@@ -3073,7 +2316,7 @@
   {
     GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s",
         gst_flow_get_name (ret));
-    gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+    gst_mini_object_unref (obj);
     return ret;
   }
 }
@@ -3098,9 +2341,7 @@
   if (G_UNLIKELY (basesink->priv->received_eos))
     goto was_eos;
 
-  ret =
-      gst_base_sink_queue_object_unlocked (basesink, pad, FALSE, obj,
-      prerollable);
+  ret = gst_base_sink_queue_object_unlocked (basesink, pad, obj, prerollable);
   GST_PAD_PREROLL_UNLOCK (pad);
 
   return ret;
@@ -3123,55 +2364,6 @@
   }
 }
 
-static void
-gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
-{
-  /* make sure we are not blocked on the clock also clear any pending
-   * eos state. */
-  gst_base_sink_set_flushing (basesink, pad, TRUE);
-
-  /* we grab the stream lock but that is not needed since setting the
-   * sink to flushing would make sure no state commit is being done
-   * anymore */
-  GST_PAD_STREAM_LOCK (pad);
-  gst_base_sink_reset_qos (basesink);
-  if (basesink->priv->async_enabled) {
-    /* and we need to commit our state again on the next
-     * prerolled buffer */
-    basesink->playing_async = TRUE;
-    gst_element_lost_state (GST_ELEMENT_CAST (basesink));
-  } else {
-    basesink->priv->have_latency = TRUE;
-    basesink->need_preroll = FALSE;
-  }
-  gst_base_sink_set_last_buffer (basesink, NULL);
-  GST_PAD_STREAM_UNLOCK (pad);
-}
-
-static void
-gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
-{
-  /* unset flushing so we can accept new data, this also flushes out any EOS
-   * event. */
-  gst_base_sink_set_flushing (basesink, pad, FALSE);
-
-  /* for position reporting */
-  GST_OBJECT_LOCK (basesink);
-  basesink->priv->current_sstart = -1;
-  basesink->priv->current_sstop = -1;
-  basesink->priv->eos_rtime = -1;
-  basesink->priv->call_preroll = TRUE;
-  basesink->priv->current_step.valid = FALSE;
-  basesink->priv->pending_step.valid = FALSE;
-  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);
-  }
-  GST_OBJECT_UNLOCK (basesink);
-}
-
 static gboolean
 gst_base_sink_event (GstPad * pad, GstEvent * event)
 {
@@ -3201,13 +2393,13 @@
         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. */
+         * we are prerolled and to refure 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,
-            FALSE, GST_MINI_OBJECT_CAST (event), TRUE);
+            GST_MINI_OBJECT_CAST (event), TRUE);
         if (G_UNLIKELY (ret != GST_FLOW_OK))
           result = FALSE;
       }
@@ -3237,14 +2429,11 @@
 
         ret =
             gst_base_sink_queue_object_unlocked (basesink, pad,
-            FALSE, GST_MINI_OBJECT_CAST (event), FALSE);
+            GST_MINI_OBJECT_CAST (event), FALSE);
         if (G_UNLIKELY (ret != GST_FLOW_OK))
           result = FALSE;
-        else {
-          GST_OBJECT_LOCK (basesink);
+        else
           basesink->have_newsegment = TRUE;
-          GST_OBJECT_UNLOCK (basesink);
-        }
       }
       GST_PAD_PREROLL_UNLOCK (pad);
       break;
@@ -3255,7 +2444,26 @@
 
       GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
 
-      gst_base_sink_flush_start (basesink, pad);
+      /* make sure we are not blocked on the clock also clear any pending
+       * eos state. */
+      gst_base_sink_set_flushing (basesink, pad, TRUE);
+
+      /* we grab the stream lock but that is not needed since setting the
+       * sink to flushing would make sure no state commit is being done
+       * anymore */
+      GST_PAD_STREAM_LOCK (pad);
+      gst_base_sink_reset_qos (basesink);
+      if (basesink->priv->async_enabled) {
+        /* and we need to commit our state again on the next
+         * prerolled buffer */
+        basesink->playing_async = TRUE;
+        gst_element_lost_state (GST_ELEMENT_CAST (basesink));
+      } else {
+        basesink->priv->have_latency = TRUE;
+        basesink->need_preroll = FALSE;
+      }
+      gst_base_sink_set_last_buffer (basesink, NULL);
+      GST_PAD_STREAM_UNLOCK (pad);
 
       gst_event_unref (event);
       break;
@@ -3265,7 +2473,21 @@
 
       GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
 
-      gst_base_sink_flush_stop (basesink, pad);
+      /* unset flushing so we can accept new data, this also flushes out any EOS
+       * event. */
+      gst_base_sink_set_flushing (basesink, pad, FALSE);
+
+      /* we need new segment info after the flush. */
+      gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
+      gst_segment_init (basesink->abidata.ABI.clip_segment,
+          GST_FORMAT_UNDEFINED);
+      basesink->have_newsegment = FALSE;
+
+      /* for position reporting */
+      GST_OBJECT_LOCK (basesink);
+      basesink->priv->current_sstart = -1;
+      basesink->priv->current_sstop = -1;
+      GST_OBJECT_UNLOCK (basesink);
 
       gst_event_unref (event);
       break;
@@ -3330,8 +2552,7 @@
    *  2) we are syncing on the clock
    */
   is_prerolled = basesink->have_preroll || basesink->priv->received_eos;
-  res = !is_prerolled;
-
+  res = !is_prerolled && basesink->pad_mode != GST_ACTIVATE_PULL;
   GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d",
       basesink->have_preroll, basesink->priv->received_eos, res);
 
@@ -3348,13 +2569,11 @@
  */
 static GstFlowReturn
 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
-    gboolean is_list, gpointer obj)
+    GstBuffer * buf)
 {
-  GstBaseSinkClass *bclass;
   GstFlowReturn result;
   GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
   GstSegment *clip_segment;
-  GstBuffer *time_buf;
 
   if (G_UNLIKELY (basesink->flushing))
     goto flushing;
@@ -3362,13 +2581,6 @@
   if (G_UNLIKELY (basesink->priv->received_eos))
     goto was_eos;
 
-  if (is_list) {
-    time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
-    g_assert (NULL != time_buf);
-  } else {
-    time_buf = GST_BUFFER_CAST (obj);
-  }
-
   /* for code clarity */
   clip_segment = basesink->abidata.ABI.clip_segment;
 
@@ -3382,28 +2594,18 @@
           ("Received buffer without a new-segment. Assuming timestamps start from 0."));
     }
 
+    basesink->have_newsegment = TRUE;
     /* this means this sink will assume timestamps start from 0 */
-    GST_OBJECT_LOCK (basesink);
     clip_segment->start = 0;
     clip_segment->stop = -1;
     basesink->segment.start = 0;
     basesink->segment.stop = -1;
-    basesink->have_newsegment = TRUE;
-    GST_OBJECT_UNLOCK (basesink);
   }
 
-  bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
-  /* check if the buffer needs to be dropped, we first ask the subclass for the
-   * start and end */
-  if (bclass->get_times)
-    bclass->get_times (basesink, time_buf, &start, &end);
-
-  if (start == -1) {
-    /* if the subclass does not want sync, we use our own values so that we at
-     * least clip the buffer to the segment */
-    gst_base_sink_get_times (basesink, time_buf, &start, &end);
-  }
+  /* check if the buffer needs to be dropped */
+  /* we don't use the subclassed method as it may not return
+   * valid values for our purpose here */
+  gst_base_sink_get_times (basesink, buf, &start, &end);
 
   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
@@ -3419,27 +2621,28 @@
   /* now we can process the buffer in the queue, this function takes ownership
    * of the buffer */
   result = gst_base_sink_queue_object_unlocked (basesink, pad,
-      is_list, obj, TRUE);
+      GST_MINI_OBJECT_CAST (buf), TRUE);
+
   return result;
 
   /* ERRORS */
 flushing:
   {
     GST_DEBUG_OBJECT (basesink, "sink is flushing");
-    gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+    gst_buffer_unref (buf);
     return GST_FLOW_WRONG_STATE;
   }
 was_eos:
   {
     GST_DEBUG_OBJECT (basesink,
         "we are EOS, dropping object, return UNEXPECTED");
-    gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+    gst_buffer_unref (buf);
     return GST_FLOW_UNEXPECTED;
   }
 out_of_segment:
   {
     GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment");
-    gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+    gst_buffer_unref (buf);
     return GST_FLOW_OK;
   }
 }
@@ -3447,16 +2650,18 @@
 /* with STREAM_LOCK
  */
 static GstFlowReturn
-gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
-    gboolean is_list, gpointer obj)
+gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
 {
+  GstBaseSink *basesink;
   GstFlowReturn result;
 
+  basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
+
   if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
     goto wrong_mode;
 
   GST_PAD_PREROLL_LOCK (pad);
-  result = gst_base_sink_chain_unlocked (basesink, pad, is_list, obj);
+  result = gst_base_sink_chain_unlocked (basesink, pad, buf);
   GST_PAD_PREROLL_UNLOCK (pad);
 
 done:
@@ -3470,7 +2675,7 @@
         "Push on pad %s:%s, but it was not activated in push mode",
         GST_DEBUG_PAD_NAME (pad));
     GST_OBJECT_UNLOCK (pad);
-    gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+    gst_buffer_unref (buf);
     /* we don't post an error message this will signal to the peer
      * pushing that EOS is reached. */
     result = GST_FLOW_UNEXPECTED;
@@ -3478,360 +2683,6 @@
   }
 }
 
-static GstFlowReturn
-gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
-{
-  GstBaseSink *basesink;
-
-  basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
-
-  return gst_base_sink_chain_main (basesink, pad, FALSE, buf);
-}
-
-static GstFlowReturn
-gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
-{
-  GstBaseSink *basesink;
-  GstBaseSinkClass *bclass;
-  GstFlowReturn result;
-
-  basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
-  bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
-  if (G_LIKELY (bclass->render_list)) {
-    result = gst_base_sink_chain_main (basesink, pad, TRUE, list);
-  } else {
-    GstBufferListIterator *it;
-    GstBuffer *group;
-
-    GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
-
-    it = gst_buffer_list_iterate (list);
-
-    result = GST_FLOW_OK;
-    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, FALSE, 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, FALSE, gst_buffer_new ());
-    }
-    gst_buffer_list_iterator_free (it);
-    gst_buffer_list_unref (list);
-  }
-  return result;
-}
-
-
-static gboolean
-gst_base_sink_default_do_seek (GstBaseSink * sink, GstSegment * segment)
-{
-  gboolean res = TRUE;
-
-  /* update our offset if the start/stop position was updated */
-  if (segment->format == GST_FORMAT_BYTES) {
-    segment->time = segment->start;
-  } else if (segment->start == 0) {
-    /* seek to start, we can implement a default for this. */
-    segment->time = 0;
-  } else {
-    res = FALSE;
-    GST_INFO_OBJECT (sink, "Can't do a default seek");
-  }
-
-  return res;
-}
-
-#define SEEK_TYPE_IS_RELATIVE(t) (((t) != GST_SEEK_TYPE_NONE) && ((t) != GST_SEEK_TYPE_SET))
-
-static gboolean
-gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
-    GstEvent * event, GstSegment * segment)
-{
-  /* By default, we try one of 2 things:
-   *   - For absolute seek positions, convert the requested position to our 
-   *     configured processing format and place it in the output segment \
-   *   - For relative seek positions, convert our current (input) values to the
-   *     seek format, adjust by the relative seek offset and then convert back to
-   *     the processing format
-   */
-  GstSeekType cur_type, stop_type;
-  gint64 cur, stop;
-  GstSeekFlags flags;
-  GstFormat seek_format, dest_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,
-        cur_type, cur, stop_type, stop, &update);
-    return TRUE;
-  }
-
-  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,
-        &cur);
-    cur_type = GST_SEEK_TYPE_SET;
-  }
-
-  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);
-    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,
-      stop_type, stop, &update);
-
-  if (!res)
-    goto no_format;
-
-  return res;
-
-no_format:
-  {
-    GST_DEBUG_OBJECT (sink, "undefined format given, seek aborted.");
-    return FALSE;
-  }
-}
-
-/* perform a seek, only executed in pull mode */
-static gboolean
-gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
-{
-  gboolean flush;
-  gdouble rate;
-  GstFormat seek_format, dest_format;
-  GstSeekFlags flags;
-  GstSeekType cur_type, stop_type;
-  gboolean seekseg_configured = FALSE;
-  gint64 cur, stop;
-  gboolean update, res = TRUE;
-  GstSegment seeksegment;
-
-  dest_format = sink->segment.format;
-
-  if (event) {
-    GST_DEBUG_OBJECT (sink, "performing seek with event %p", event);
-    gst_event_parse_seek (event, &rate, &seek_format, &flags,
-        &cur_type, &cur, &stop_type, &stop);
-
-    flush = flags & GST_SEEK_FLAG_FLUSH;
-  } else {
-    GST_DEBUG_OBJECT (sink, "performing seek without event");
-    flush = FALSE;
-  }
-
-  if (flush) {
-    GST_DEBUG_OBJECT (sink, "flushing upstream");
-    gst_pad_push_event (pad, gst_event_new_flush_start ());
-    gst_base_sink_flush_start (sink, pad);
-  } else {
-    GST_DEBUG_OBJECT (sink, "pausing pulling thread");
-  }
-
-  GST_PAD_STREAM_LOCK (pad);
-
-  /* If we configured the seeksegment above, don't overwrite it now. Otherwise
-   * copy the current segment info into the temp segment that we can actually
-   * attempt the seek with. We only update the real segment if the seek suceeds. */
-  if (!seekseg_configured) {
-    memcpy (&seeksegment, &sink->segment, sizeof (GstSegment));
-
-    /* now configure the final seek segment */
-    if (event) {
-      if (sink->segment.format != seek_format) {
-        /* OK, here's where we give the subclass a chance to convert the relative
-         * seek into an absolute one in the processing format. We set up any
-         * absolute seek above, before taking the stream lock. */
-        if (!gst_base_sink_default_prepare_seek_segment (sink, event,
-                &seeksegment)) {
-          GST_DEBUG_OBJECT (sink,
-              "Preparing the seek failed after flushing. " "Aborting seek");
-          res = FALSE;
-        }
-      } 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,
-            cur_type, cur, stop_type, stop, &update);
-      }
-    }
-    /* Else, no seek event passed, so we're just (re)starting the 
-       current segment. */
-  }
-
-  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);
-
-    /* do the seek, segment.last_stop 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) {
-    /* we are running the current segment and doing a non-flushing seek, 
-     * close the segment first based on the last_stop. */
-    GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT
-        " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop);
-  }
-
-  /* The subclass must have converted the segment to the processing format 
-   * by now */
-  if (res && seeksegment.format != dest_format) {
-    GST_DEBUG_OBJECT (sink, "Subclass failed to prepare a seek segment "
-        "in the correct format. Aborting seek.");
-    res = FALSE;
-  }
-
-  /* if successfull seek, we update our real segment and push
-   * out the new segment. */
-  if (res) {
-    memcpy (&sink->segment, &seeksegment, sizeof (GstSegment));
-
-    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->priv->discont = TRUE;
-  sink->abidata.ABI.running = TRUE;
-
-  GST_PAD_STREAM_UNLOCK (pad);
-
-  return res;
-}
-
-static void
-set_step_info (GstBaseSink * sink, GstStepInfo * current, GstStepInfo * pending,
-    guint seqnum, GstFormat format, guint64 amount, gdouble rate,
-    gboolean flush, gboolean intermediate)
-{
-  GST_OBJECT_LOCK (sink);
-  pending->seqnum = seqnum;
-  pending->format = format;
-  pending->amount = amount;
-  pending->position = 0;
-  pending->rate = rate;
-  pending->flush = flush;
-  pending->intermediate = intermediate;
-  pending->valid = TRUE;
-  /* flush invalidates the current stepping segment */
-  if (flush)
-    current->valid = FALSE;
-  GST_OBJECT_UNLOCK (sink);
-}
-
-static gboolean
-gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
-{
-  GstBaseSinkPrivate *priv;
-  GstBaseSinkClass *bclass;
-  gboolean flush, intermediate;
-  gdouble rate;
-  GstFormat format;
-  guint64 amount;
-  guint seqnum;
-  GstStepInfo *pending, *current;
-  GstMessage *message;
-
-  bclass = GST_BASE_SINK_GET_CLASS (sink);
-  priv = sink->priv;
-
-  GST_DEBUG_OBJECT (sink, "performing step with event %p", event);
-
-  gst_event_parse_step (event, &format, &amount, &rate, &flush, &intermediate);
-  seqnum = gst_event_get_seqnum (event);
-
-  pending = &priv->pending_step;
-  current = &priv->current_step;
-
-  /* post message first */
-  message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format,
-      amount, rate, flush, intermediate);
-  gst_message_set_seqnum (message, seqnum);
-  gst_element_post_message (GST_ELEMENT (sink), message);
-
-  if (flush) {
-    /* we need to call ::unlock before locking PREROLL_LOCK
-     * since we lock it before going into ::render */
-    if (bclass->unlock)
-      bclass->unlock (sink);
-
-    GST_PAD_PREROLL_LOCK (sink->sinkpad);
-    /* now that we have the PREROLL lock, clear our unlock request */
-    if (bclass->unlock_stop)
-      bclass->unlock_stop (sink);
-
-    /* update the stepinfo and make it valid */
-    set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
-        intermediate);
-
-    if (sink->priv->async_enabled) {
-      /* and we need to commit our state again on the next
-       * prerolled buffer */
-      sink->playing_async = TRUE;
-      priv->pending_step.need_preroll = TRUE;
-      sink->need_preroll = FALSE;
-      gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE);
-    } else {
-      sink->priv->have_latency = TRUE;
-      sink->need_preroll = FALSE;
-    }
-    priv->current_sstart = -1;
-    priv->current_sstop = -1;
-    priv->eos_rtime = -1;
-    priv->call_preroll = TRUE;
-    gst_base_sink_set_last_buffer (sink, NULL);
-    gst_base_sink_reset_qos (sink);
-
-    if (sink->clock_id) {
-      gst_clock_id_unschedule (sink->clock_id);
-    }
-
-    if (sink->have_preroll) {
-      GST_DEBUG_OBJECT (sink, "signal waiter");
-      priv->step_unlock = TRUE;
-      GST_PAD_PREROLL_SIGNAL (sink->sinkpad);
-    }
-    GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
-  } else {
-    /* update the stepinfo and make it valid */
-    set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
-        intermediate);
-  }
-
-  return TRUE;
-}
-
 /* with STREAM_LOCK
  */
 static void
@@ -3840,34 +2691,25 @@
   GstBaseSink *basesink;
   GstBuffer *buf = NULL;
   GstFlowReturn result;
-  guint blocksize;
-  guint64 offset;
 
   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
 
   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
 
-  if ((blocksize = basesink->priv->blocksize) == 0)
-    blocksize = -1;
-
-  offset = basesink->segment.last_stop;
-
   GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
-      offset, blocksize);
-
-  result = gst_pad_pull_range (pad, offset, blocksize, &buf);
+      basesink->offset, (guint) DEFAULT_SIZE);
+
+  result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
   if (G_UNLIKELY (result != GST_FLOW_OK))
     goto paused;
 
   if (G_UNLIKELY (buf == NULL))
     goto no_buffer;
 
-  offset += GST_BUFFER_SIZE (buf);
-
-  gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset);
+  basesink->offset += GST_BUFFER_SIZE (buf);
 
   GST_PAD_PREROLL_LOCK (pad);
-  result = gst_base_sink_chain_unlocked (basesink, pad, FALSE, buf);
+  result = gst_base_sink_chain_unlocked (basesink, pad, buf);
   GST_PAD_PREROLL_UNLOCK (pad);
   if (G_UNLIKELY (result != GST_FLOW_OK))
     goto paused;
@@ -3882,22 +2724,13 @@
     gst_pad_pause_task (pad);
     /* fatal errors and NOT_LINKED cause EOS */
     if (GST_FLOW_IS_FATAL (result) || result == GST_FLOW_NOT_LINKED) {
-      if (result == GST_FLOW_UNEXPECTED) {
-        /* perform EOS logic */
-        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));
-        } else {
-          gst_base_sink_event (pad, gst_event_new_eos ());
-        }
-      } else {
-        /* for fatal errors we post an error message, post the error
-         * first so the app knows about the error first. */
+      /* FIXME, we shouldn't post EOS when we are operating in segment mode */
+      gst_base_sink_event (pad, gst_event_new_eos ());
+      /* EOS does not cause an ERROR message */
+      if (result != GST_FLOW_UNEXPECTED) {
         GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
             (_("Internal data stream error.")),
             ("stream stopped, reason %s", gst_flow_get_name (result)));
-        gst_base_sink_event (pad, gst_event_new_eos ());
       }
     }
     return;
@@ -3905,8 +2738,6 @@
 no_buffer:
   {
     GST_LOG_OBJECT (basesink, "no buffer, pausing");
-    GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
-        (_("Internal data flow error.")), ("element returned NULL buffer"));
     result = GST_FLOW_ERROR;
     goto paused;
   }
@@ -3943,8 +2774,7 @@
       gst_clock_id_unschedule (basesink->clock_id);
     }
 
-    /* flush out the data thread if it's locked in finish_preroll, this will
-     * also flush out the EOS state */
+    /* flush out the data thread if it's locked in finish_preroll */
     GST_DEBUG_OBJECT (basesink,
         "flushing out data thread, need preroll to TRUE");
     gst_base_sink_preroll_queue_flush (basesink, pad);
@@ -3983,52 +2813,18 @@
 
   gst_base_sink_set_flushing (basesink, pad, FALSE);
 
-  /* we need to have the pull mode enabled */
-  if (!basesink->can_activate_pull) {
-    GST_DEBUG_OBJECT (basesink, "pull mode disabled");
-    goto fallback;
-  }
-
-  /* check if downstreams supports pull mode at all */
-  if (!gst_pad_check_pull_range (pad)) {
-    GST_DEBUG_OBJECT (basesink, "pull mode not supported");
-    goto fallback;
-  }
-
-  /* set the pad mode before starting the task so that it's in the
-   * correct state for the new thread. also the sink set_caps and get_caps
-   * function checks this */
-  basesink->pad_mode = GST_ACTIVATE_PULL;
-
-  /* we first try to negotiate a format so that when we try to activate
-   * downstream, it knows about our format */
-  if (!gst_base_sink_negotiate_pull (basesink)) {
-    GST_DEBUG_OBJECT (basesink, "failed to negotiate in pull mode");
-    goto fallback;
+  if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
+      && gst_pad_activate_pull (pad, TRUE)) {
+    GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
+    result = TRUE;
+  } else {
+    GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
+    if (gst_pad_activate_push (pad, TRUE)) {
+      GST_DEBUG_OBJECT (basesink, "Success activating push mode");
+      result = TRUE;
+    }
   }
 
-  /* ok activate now */
-  if (!gst_pad_activate_pull (pad, TRUE)) {
-    /* clear any pending caps */
-    GST_OBJECT_LOCK (basesink);
-    gst_caps_replace (&basesink->priv->pull_caps, NULL);
-    GST_OBJECT_UNLOCK (basesink);
-    GST_DEBUG_OBJECT (basesink, "failed to activate in pull mode");
-    goto fallback;
-  }
-
-  GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
-  result = TRUE;
-  goto done;
-
-  /* push mode fallback */
-fallback:
-  GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
-  if ((result = gst_pad_activate_push (pad, TRUE))) {
-    GST_DEBUG_OBJECT (basesink, "Success activating push mode");
-  }
-
-done:
   if (!result) {
     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
     gst_base_sink_set_flushing (basesink, pad, TRUE);
@@ -4075,60 +2871,48 @@
 gst_base_sink_negotiate_pull (GstBaseSink * basesink)
 {
   GstCaps *caps;
-  gboolean result;
-
-  result = FALSE;
-
-  /* this returns the intersection between our caps and the peer caps. If there
-   * is no peer, it returns NULL and we can't operate in pull mode so we can
-   * fail the negotiation. */
-  caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (basesink));
-  if (caps == NULL || gst_caps_is_empty (caps))
+  GstPad *pad;
+
+  GST_OBJECT_LOCK (basesink);
+  pad = basesink->sinkpad;
+  gst_object_ref (pad);
+  GST_OBJECT_UNLOCK (basesink);
+
+  caps = gst_pad_get_allowed_caps (pad);
+  if (gst_caps_is_empty (caps))
     goto no_caps_possible;
 
-  GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps);
-
   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_pad_fixate_caps (pad, caps);
 
   if (gst_caps_is_any (caps)) {
     GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
         "allowing pull()");
     /* 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))
+  } else {
+    if (!gst_pad_set_caps (pad, caps))
       goto could_not_set_caps;
-
-    GST_OBJECT_LOCK (basesink);
-    gst_caps_replace (&basesink->priv->pull_caps, caps);
-    GST_OBJECT_UNLOCK (basesink);
-
-    result = TRUE;
   }
 
   gst_caps_unref (caps);
-
-  return result;
+  gst_object_unref (pad);
+
+  return TRUE;
 
 no_caps_possible:
   {
     GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps");
     GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY");
-    if (caps)
-      gst_caps_unref (caps);
+    gst_object_unref (pad);
     return FALSE;
   }
 could_not_set_caps:
   {
     GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps);
     gst_caps_unref (caps);
+    gst_object_unref (pad);
     return FALSE;
   }
 }
@@ -4145,40 +2929,47 @@
   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_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);
-    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);
+    if (!basesink->can_activate_pull) {
+      result = FALSE;
+      basesink->pad_mode = GST_ACTIVATE_NONE;
     } else {
-      GST_DEBUG_OBJECT (basesink, "unknown duration");
+      GstPad *peer = gst_pad_get_peer (pad);
+
+      if (G_UNLIKELY (peer == NULL)) {
+        g_warning ("Trying to activate pad in pull mode, but no peer");
+        result = FALSE;
+        basesink->pad_mode = GST_ACTIVATE_NONE;
+      } else {
+        if (gst_pad_activate_pull (peer, TRUE)) {
+          /* we mark we have a newsegment here because pull based
+           * mode works just fine without having a newsegment before the
+           * first buffer */
+          gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
+          gst_segment_init (basesink->abidata.ABI.clip_segment,
+              GST_FORMAT_UNDEFINED);
+          basesink->have_newsegment = TRUE;
+
+          /* set the pad mode before starting the task so that it's in the
+             correct state for the new thread. also the sink set_caps function
+             checks this */
+          basesink->pad_mode = GST_ACTIVATE_PULL;
+          if ((result = gst_base_sink_negotiate_pull (basesink))) {
+            if (bclass->activate_pull)
+              result = bclass->activate_pull (basesink, TRUE);
+            else
+              result = FALSE;
+          }
+          /* but if starting the thread fails, set it back */
+          if (!result)
+            basesink->pad_mode = GST_ACTIVATE_NONE;
+        } else {
+          GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
+          result = FALSE;
+          basesink->pad_mode = GST_ACTIVATE_NONE;
+        }
+        gst_object_unref (peer);
+      }
     }
-
-    if (bclass->activate_pull)
-      result = bclass->activate_pull (basesink, TRUE);
-    else
-      result = FALSE;
-
-    if (!result)
-      goto activate_failed;
-
   } else {
     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
       g_warning ("Internal GStreamer activation error!!!");
@@ -4188,25 +2979,12 @@
       if (bclass->activate_pull)
         result &= bclass->activate_pull (basesink, FALSE);
       basesink->pad_mode = GST_ACTIVATE_NONE;
-      /* clear any pending caps */
-      GST_OBJECT_LOCK (basesink);
-      gst_caps_replace (&basesink->priv->pull_caps, NULL);
-      GST_OBJECT_UNLOCK (basesink);
     }
   }
+
   gst_object_unref (basesink);
 
   return result;
-
-  /* ERRORS */
-activate_failed:
-  {
-    /* reset, as starting the thread failed */
-    basesink->pad_mode = GST_ACTIVATE_NONE;
-
-    GST_ERROR_OBJECT (basesink, "subclass failed to activate in pull mode");
-    return FALSE;
-  }
 }
 
 /* send an event to our sinkpad peer. */
@@ -4216,13 +2994,6 @@
   GstPad *pad;
   GstBaseSink *basesink = GST_BASE_SINK (element);
   gboolean forward, result = TRUE;
-  GstActivateMode mode;
-
-  GST_OBJECT_LOCK (element);
-  /* get the pad and the scheduling mode */
-  pad = gst_object_ref (basesink->sinkpad);
-  mode = basesink->pad_mode;
-  GST_OBJECT_UNLOCK (element);
 
   /* only push UPSTREAM events upstream */
   forward = GST_EVENT_IS_UPSTREAM (event);
@@ -4234,42 +3005,32 @@
 
       gst_event_parse_latency (event, &latency);
 
-      /* store the latency. We use this to adjust the running_time before syncing
-       * it to the clock. */
       GST_OBJECT_LOCK (element);
       basesink->priv->latency = latency;
-      if (!basesink->priv->have_latency)
-        forward = FALSE;
       GST_OBJECT_UNLOCK (element);
       GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT,
           GST_TIME_ARGS (latency));
 
-      /* We forward this event so that all elements know about the global pipeline
-       * latency. This is interesting for an element when it wants to figure out
-       * when a particular piece of data will be rendered. */
+      /* don't forward, yet */
+      forward = FALSE;
       break;
     }
-    case GST_EVENT_SEEK:
-      /* in pull mode we will execute the seek */
-      if (mode == GST_ACTIVATE_PULL)
-        result = gst_base_sink_perform_seek (basesink, pad, event);
-      break;
-    case GST_EVENT_STEP:
-      result = gst_base_sink_perform_step (basesink, pad, event);
-      forward = FALSE;
-      break;
     default:
       break;
   }
 
   if (forward) {
+    GST_OBJECT_LOCK (element);
+    pad = gst_object_ref (basesink->sinkpad);
+    GST_OBJECT_UNLOCK (element);
+
     result = gst_pad_push_event (pad, event);
+
+    gst_object_unref (pad);
   } else {
     /* not forwarded, unref the event */
     gst_event_unref (event);
   }
-
-  gst_object_unref (pad);
   return result;
 }
 
@@ -4288,74 +3049,29 @@
 
 /* get the end position of the last seen object, this is used
  * for EOS and for making sure that we don't report a position we
- * have not reached yet. With LOCK. */
+ * have not reached yet. */
 static gboolean
-gst_base_sink_get_position_last (GstBaseSink * basesink, GstFormat format,
-    gint64 * cur)
+gst_base_sink_get_position_last (GstBaseSink * basesink, gint64 * cur)
 {
-  GstFormat oformat;
-  GstSegment *segment;
-  gboolean ret = TRUE;
-
-  segment = &basesink->segment;
-  oformat = segment->format;
-
-  if (oformat == GST_FORMAT_TIME) {
-    /* return last observed stream time, we keep the stream time around in the
-     * time format. */
-    *cur = basesink->priv->current_sstop;
-  } else {
-    /* convert last stop to stream time */
-    *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
-  }
-
-  if (*cur != -1 && oformat != format) {
-    GST_OBJECT_UNLOCK (basesink);
-    /* convert to the target format if we need to, release lock first */
-    ret =
-        gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur);
-    if (!ret)
-      *cur = -1;
-    GST_OBJECT_LOCK (basesink);
-  }
-
+  /* return last observed stream time */
+  *cur = basesink->priv->current_sstop;
   GST_DEBUG_OBJECT (basesink, "POSITION: %" GST_TIME_FORMAT,
       GST_TIME_ARGS (*cur));
-
-  return ret;
+  return TRUE;
 }
 
 /* get the position when we are PAUSED, this is the stream time of the buffer
  * that prerolled. If no buffer is prerolled (we are still flushing), this
- * value will be -1. With LOCK. */
+ * value will be -1. */
 static gboolean
-gst_base_sink_get_position_paused (GstBaseSink * basesink, GstFormat format,
-    gint64 * cur)
+gst_base_sink_get_position_paused (GstBaseSink * basesink, gint64 * cur)
 {
   gboolean res;
   gint64 time;
   GstSegment *segment;
-  GstFormat oformat;
-
-  /* we don't use the clip segment in pull mode, when seeking we update the
-   * 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;
-  else
-    segment = &basesink->segment;
-  oformat = segment->format;
-
-  if (oformat == GST_FORMAT_TIME) {
-    *cur = basesink->priv->current_sstart;
-    if (segment->rate < 0.0 && basesink->priv->current_sstop != -1) {
-      /* for reverse playback we prefer the stream time stop position if we have
-       * one */
-      *cur = basesink->priv->current_sstop;
-    }
-  } else {
-    *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
-  }
+
+  *cur = basesink->priv->current_sstart;
+  segment = basesink->abidata.ABI.clip_segment;
 
   time = segment->time;
 
@@ -4373,142 +3089,118 @@
     } else {
       /* reverse, next expected timestamp is segment->stop. We use the function
        * to get things right for negative applied_rates. */
-      *cur = gst_segment_to_stream_time (segment, oformat, segment->stop);
+      *cur =
+          gst_segment_to_stream_time (segment, GST_FORMAT_TIME, segment->stop);
       GST_DEBUG_OBJECT (basesink, "reverse POSITION: %" GST_TIME_FORMAT,
           GST_TIME_ARGS (*cur));
     }
   }
-
   res = (*cur != -1);
-  if (res && oformat != format) {
-    GST_OBJECT_UNLOCK (basesink);
-    res =
-        gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur);
-    if (!res)
-      *cur = -1;
-    GST_OBJECT_LOCK (basesink);
-  }
 
   return res;
 }
 
 static gboolean
 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
-    gint64 * cur, gboolean * upstream)
+    gint64 * cur)
 {
   GstClock *clock;
   gboolean res = FALSE;
-  GstFormat oformat, tformat;
-  GstClockTime now, base, latency;
-  gint64 time, accum, duration;
-  gdouble rate;
-  gint64 last;
-
-  GST_OBJECT_LOCK (basesink);
-  /* our intermediate time format */
-  tformat = GST_FORMAT_TIME;
-  /* get the format in the segment */
-  oformat = basesink->segment.format;
-
-  /* can only give answer based on the clock if not EOS */
-  if (G_UNLIKELY (basesink->eos))
-    goto in_eos;
-
-  /* we can only get the segment when we are not NULL or READY */
-  if (!basesink->have_newsegment)
-    goto wrong_state;
-
-  /* when not in PLAYING or when we're busy with a state change, we
-   * cannot read from the clock so we report time based on the
-   * last seen timestamp. */
-  if (GST_STATE (basesink) != GST_STATE_PLAYING ||
-      GST_STATE_PENDING (basesink) != GST_STATE_VOID_PENDING)
-    goto in_pause;
-
-  /* we need to sync on the clock. */
-  if (basesink->sync == FALSE)
-    goto no_sync;
-
-  /* and we need a clock */
-  if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
-    goto no_sync;
-
-  /* collect all data we need holding the lock */
-  if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time))
-    time = basesink->segment.time;
-  else
-    time = 0;
-
-  if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop))
-    duration = basesink->segment.stop - basesink->segment.start;
-  else
-    duration = 0;
-
-  base = GST_ELEMENT_CAST (basesink)->base_time;
-  accum = basesink->segment.accum;
-  rate = basesink->segment.rate * basesink->segment.applied_rate;
-  latency = basesink->priv->latency;
-
-  gst_object_ref (clock);
-
-  /* this function might release the LOCK */
-  gst_base_sink_get_position_last (basesink, format, &last);
-
-  /* need to release the object lock before we can get the time, 
-   * a clock might take the LOCK of the provider, which could be
-   * a basesink subclass. */
-  GST_OBJECT_UNLOCK (basesink);
-
-  now = gst_clock_get_time (clock);
-
-  if (oformat != tformat) {
-    /* convert accum, time and duration to time */
-    if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat,
-            &accum))
-      goto convert_failed;
-    if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration, &tformat,
-            &duration))
-      goto convert_failed;
-    if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat,
-            &time))
-      goto convert_failed;
+
+  switch (format) {
+      /* we can answer time format */
+    case GST_FORMAT_TIME:
+    {
+      GstClockTime now, base, latency;
+      gint64 time, accum, duration;
+      gdouble rate;
+      gint64 last;
+
+      GST_OBJECT_LOCK (basesink);
+
+      /* can only give answer based on the clock if not EOS */
+      if (G_UNLIKELY (basesink->eos))
+        goto in_eos;
+
+      /* in PAUSE we cannot read from the clock so we
+       * report time based on the last seen timestamp. */
+      if (GST_STATE (basesink) == GST_STATE_PAUSED)
+        goto in_pause;
+
+      /* We get position from clock only in PLAYING, we checked
+       * the PAUSED case above, so this is check is to test 
+       * READY and NULL, where the position is always 0 */
+      if (GST_STATE (basesink) != GST_STATE_PLAYING)
+        goto wrong_state;
+
+      /* we need to sync on the clock. */
+      if (basesink->sync == FALSE)
+        goto no_sync;
+
+      /* and we need a clock */
+      if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
+        goto no_sync;
+
+      /* collect all data we need holding the lock */
+      if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time))
+        time = basesink->segment.time;
+      else
+        time = 0;
+
+      if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop))
+        duration = basesink->segment.stop - basesink->segment.start;
+      else
+        duration = 0;
+
+      base = GST_ELEMENT_CAST (basesink)->base_time;
+      accum = basesink->segment.accum;
+      rate = basesink->segment.rate * basesink->segment.applied_rate;
+      gst_base_sink_get_position_last (basesink, &last);
+      latency = basesink->priv->latency;
+
+      gst_object_ref (clock);
+      /* need to release the object lock before we can get the time, 
+       * a clock might take the LOCK of the provider, which could be
+       * a basesink subclass. */
+      GST_OBJECT_UNLOCK (basesink);
+
+      now = gst_clock_get_time (clock);
+
+      /* subtract base time and accumulated 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;
+      base = MIN (now, base);
+
+      /* for negative rates we need to count back from from the segment
+       * duration. */
+      if (rate < 0.0)
+        time += duration;
+      *cur = time + gst_guint64_to_gdouble (now - base) * rate;
+
+      /* never report more than last seen position */
+      if (last != -1)
+        *cur = MIN (last, *cur);
+
+      gst_object_unref (clock);
+
+      res = TRUE;
+
+      GST_DEBUG_OBJECT (basesink,
+          "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
+          GST_TIME_FORMAT " + time %" GST_TIME_FORMAT,
+          GST_TIME_ARGS (now), GST_TIME_ARGS (base),
+          GST_TIME_ARGS (accum), GST_TIME_ARGS (time));
+      break;
+    }
+    default:
+      /* cannot answer other than TIME, we return FALSE, which will
+       * send the query upstream. */
+      break;
   }
 
-  /* subtract base time and accumulated 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;
-  base = MIN (now, base);
-
-  /* for negative rates we need to count back from from the segment
-   * duration. */
-  if (rate < 0.0)
-    time += duration;
-
-  *cur = time + gst_guint64_to_gdouble (now - base) * rate;
-
-  /* never report more than last seen position */
-  if (last != -1)
-    *cur = MIN (last, *cur);
-
-  gst_object_unref (clock);
-
-  GST_DEBUG_OBJECT (basesink,
-      "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
-      GST_TIME_FORMAT " + time %" GST_TIME_FORMAT,
-      GST_TIME_ARGS (now), GST_TIME_ARGS (base),
-      GST_TIME_ARGS (accum), GST_TIME_ARGS (time));
-
-  if (oformat != format) {
-    /* convert time to final format */
-    if (!gst_pad_query_convert (basesink->sinkpad, tformat, *cur, &format, cur))
-      goto convert_failed;
-  }
-
-  res = TRUE;
-
 done:
   GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT,
       res, GST_TIME_ARGS (*cur));
@@ -4518,20 +3210,20 @@
 in_eos:
   {
     GST_DEBUG_OBJECT (basesink, "position in EOS");
-    res = gst_base_sink_get_position_last (basesink, format, cur);
+    res = gst_base_sink_get_position_last (basesink, cur);
     GST_OBJECT_UNLOCK (basesink);
     goto done;
   }
 in_pause:
   {
     GST_DEBUG_OBJECT (basesink, "position in PAUSED");
-    res = gst_base_sink_get_position_paused (basesink, format, cur);
+    res = gst_base_sink_get_position_paused (basesink, cur);
     GST_OBJECT_UNLOCK (basesink);
     goto done;
   }
 wrong_state:
   {
-    /* in NULL or READY we always return FALSE and -1 */
+    /* in NULL or READY we always return 0 */
     GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1");
     res = FALSE;
     *cur = -1;
@@ -4540,23 +3232,15 @@
   }
 no_sync:
   {
-    /* report last seen timestamp if any, else ask upstream to answer */
+    /* report last seen timestamp if any, else return FALSE so
+     * that upstream can answer */
     if ((*cur = basesink->priv->current_sstart) != -1)
       res = TRUE;
-    else
-      *upstream = TRUE;
-
     GST_DEBUG_OBJECT (basesink, "no sync, res %d, POSITION %" GST_TIME_FORMAT,
         res, GST_TIME_ARGS (*cur));
     GST_OBJECT_UNLOCK (basesink);
     return res;
   }
-convert_failed:
-  {
-    GST_DEBUG_OBJECT (basesink, "convert failed, try upstream");
-    *upstream = TRUE;
-    return FALSE;
-  }
 }
 
 static gboolean
@@ -4571,61 +3255,24 @@
     {
       gint64 cur = 0;
       GstFormat format;
-      gboolean upstream = FALSE;
 
       gst_query_parse_position (query, &format, NULL);
 
       GST_DEBUG_OBJECT (basesink, "position format %d", format);
 
       /* first try to get the position based on the clock */
-      if ((res =
-              gst_base_sink_get_position (basesink, format, &cur, &upstream))) {
+      if ((res = gst_base_sink_get_position (basesink, format, &cur))) {
         gst_query_set_position (query, format, cur);
-      } else if (upstream) {
+      } else {
         /* fallback to peer query */
         res = gst_base_sink_peer_query (basesink, query);
       }
       break;
     }
     case GST_QUERY_DURATION:
-    {
-      GstFormat format, uformat;
-      gint64 duration, uduration;
-
-      gst_query_parse_duration (query, &format, NULL);
-
-      GST_DEBUG_OBJECT (basesink, "duration query in format %s",
-          gst_format_get_name (format));
-
-      if (basesink->pad_mode == GST_ACTIVATE_PULL) {
-        uformat = GST_FORMAT_BYTES;
-
-        /* 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);
-        if (res) {
-          gst_segment_set_duration (&basesink->segment, uformat, uduration);
-          if (format != uformat) {
-            /* convert to the requested format */
-            res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration,
-                &format, &duration);
-          } else {
-            duration = uduration;
-          }
-          if (res) {
-            /* set the result */
-            gst_query_set_duration (query, format, duration);
-          }
-        }
-      } else {
-        /* in push mode we simply forward upstream */
-        res = gst_base_sink_peer_query (basesink, query);
-      }
+      GST_DEBUG_OBJECT (basesink, "duration query");
+      res = gst_base_sink_peer_query (basesink, query);
       break;
-    }
     case GST_QUERY_LATENCY:
     {
       gboolean live, us_live;
@@ -4683,13 +3330,12 @@
        * is no data flow in READY so we can safely assume we need to preroll. */
       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
       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);
+      basesink->have_newsegment = FALSE;
       basesink->offset = 0;
       basesink->have_preroll = FALSE;
-      priv->step_unlock = FALSE;
       basesink->need_preroll = TRUE;
       basesink->playing_async = TRUE;
       priv->current_sstart = -1;
@@ -4700,9 +3346,6 @@
       priv->received_eos = FALSE;
       gst_base_sink_reset_qos (basesink);
       priv->commited = FALSE;
-      priv->call_preroll = TRUE;
-      priv->current_step.valid = FALSE;
-      priv->pending_step.valid = FALSE;
       if (priv->async_enabled) {
         GST_DEBUG_OBJECT (basesink, "doing async state change");
         /* when async enabled, post async-start message and return ASYNC from
@@ -4723,13 +3366,10 @@
         basesink->playing_async = FALSE;
         basesink->need_preroll = FALSE;
         if (basesink->eos) {
-          GstMessage *message;
-
           /* need to post EOS message here */
           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
-          message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
-          gst_message_set_seqnum (message, basesink->priv->seqnum);
-          gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
+          gst_element_post_message (GST_ELEMENT_CAST (basesink),
+              gst_message_new_eos (GST_OBJECT_CAST (basesink)));
         } else {
           GST_DEBUG_OBJECT (basesink, "signal preroll");
           GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
@@ -4738,7 +3378,6 @@
         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
         basesink->need_preroll = TRUE;
         basesink->playing_async = TRUE;
-        priv->call_preroll = TRUE;
         priv->commited = FALSE;
         if (priv->async_enabled) {
           GST_DEBUG_OBJECT (basesink, "doing async state change");
@@ -4762,6 +3401,19 @@
   }
 
   switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      /* note that this is the upward case, which doesn't follow most
+         patterns */
+      if (basesink->pad_mode == GST_ACTIVATE_PULL) {
+        GST_DEBUG_OBJECT (basesink, "basesink activated in pull mode, "
+            "returning SUCCESS directly");
+        GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+        gst_element_post_message (GST_ELEMENT_CAST (basesink),
+            gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+        GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+        ret = GST_STATE_CHANGE_SUCCESS;
+      }
+      break;
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
       /* FIXME, make sure we cannot enter _render first */
@@ -4798,7 +3450,6 @@
               "PLAYING to PAUSED, we are not prerolled");
           basesink->playing_async = TRUE;
           priv->commited = FALSE;
-          priv->call_preroll = TRUE;
           if (priv->async_enabled) {
             GST_DEBUG_OBJECT (basesink, "doing async state change");
             ret = GST_STATE_CHANGE_ASYNC;
@@ -4816,19 +3467,6 @@
       break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
-      /* 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. */
-      GST_OBJECT_LOCK (basesink);
-      basesink->have_newsegment = FALSE;
-      priv->current_sstart = -1;
-      priv->current_sstop = -1;
-      priv->have_latency = FALSE;
-      GST_OBJECT_UNLOCK (basesink);
-
-      gst_base_sink_set_last_buffer (basesink, NULL);
-      priv->call_preroll = FALSE;
-
       if (!priv->commited) {
         if (priv->async_enabled) {
           GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done");
@@ -4844,6 +3482,10 @@
       } else {
         GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
       }
+      priv->current_sstart = -1;
+      priv->current_sstop = -1;
+      priv->have_latency = FALSE;
+      gst_base_sink_set_last_buffer (basesink, NULL);
       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -4853,7 +3495,6 @@
         }
       }
       gst_base_sink_set_last_buffer (basesink, NULL);
-      priv->call_preroll = FALSE;
       break;
     default:
       break;