Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / libs / gst / base / gstbasesink.c
index fd9f949..e94a1e2 100644 (file)
@@ -227,6 +227,8 @@ struct _GstBaseSinkPrivate
 
   /* if we already commited the state */
   gboolean commited;
+  /* state change to playing ongoing */
+  gboolean to_playing;
 
   /* when we received EOS */
   gboolean received_eos;
@@ -262,6 +264,8 @@ struct _GstBaseSinkPrivate
   /* for throttling and QoS */
   GstClockTime earliest_in_time;
   GstClockTime throttle_time;
+
+  gboolean reset_time;
 };
 
 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
@@ -360,7 +364,7 @@ static void gst_base_sink_get_property (GObject * object, guint prop_id,
 
 static gboolean gst_base_sink_send_event (GstElement * element,
     GstEvent * event);
-static gboolean gst_base_sink_query (GstElement * element, GstQuery * query);
+static gboolean default_element_query (GstElement * element, GstQuery * query);
 static const GstQueryType *gst_base_sink_get_query_types (GstElement * element);
 
 static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink, GstCaps * caps);
@@ -379,6 +383,7 @@ static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
     GstStateChange transition);
 
+static gboolean gst_base_sink_sink_query (GstPad * pad, GstQuery * query);
 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
 static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
     GstBufferList * list);
@@ -389,6 +394,8 @@ static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active);
 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
 
+static gboolean default_sink_query (GstBaseSink * sink, GstQuery * query);
+
 static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
 static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad, GstCaps * filter);
 static void gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps);
@@ -540,7 +547,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
-  gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query);
+  gstelement_class->query = GST_DEBUG_FUNCPTR (default_element_query);
   gstelement_class->get_query_types =
       GST_DEBUG_FUNCPTR (gst_base_sink_get_query_types);
 
@@ -549,6 +556,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
   klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
   klass->activate_pull =
       GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull);
+  klass->query = GST_DEBUG_FUNCPTR (default_sink_query);
 
   /* Registering debug symbols for function pointers */
   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_getcaps);
@@ -640,6 +648,7 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
       gst_base_sink_pad_activate_push);
   gst_pad_set_activatepull_function (basesink->sinkpad,
       gst_base_sink_pad_activate_pull);
+  gst_pad_set_query_function (basesink->sinkpad, gst_base_sink_sink_query);
   gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event);
   gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain);
   gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list);
@@ -649,7 +658,6 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
   basesink->preroll_lock = g_mutex_new ();
   basesink->preroll_cond = g_cond_new ();
   basesink->preroll_queue = g_queue_new ();
-  basesink->clip_segment = gst_segment_new ();
   priv->have_latency = FALSE;
 
   basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
@@ -679,7 +687,6 @@ gst_base_sink_finalize (GObject * object)
   g_mutex_free (basesink->preroll_lock);
   g_cond_free (basesink->preroll_cond);
   g_queue_free (basesink->preroll_queue);
-  gst_segment_free (basesink->clip_segment);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -1469,6 +1476,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
   gboolean post_paused = FALSE;
   gboolean post_async_done = FALSE;
   gboolean post_playing = FALSE;
+  gboolean reset_time;
 
   /* we are certainly not playing async anymore now */
   basesink->playing_async = FALSE;
@@ -1478,14 +1486,12 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
   next = GST_STATE_NEXT (basesink);
   pending = GST_STATE_PENDING (basesink);
   post_pending = pending;
+  reset_time = basesink->priv->reset_time;
+  basesink->priv->reset_time = FALSE;
 
   switch (pending) {
     case GST_STATE_PLAYING:
     {
-      GstBaseSinkClass *bclass;
-
-      bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
       GST_DEBUG_OBJECT (basesink, "commiting state to PLAYING");
 
       basesink->need_preroll = FALSE;
@@ -1532,7 +1538,7 @@ gst_base_sink_commit_state (GstBaseSink * basesink)
   if (post_async_done) {
     GST_DEBUG_OBJECT (basesink, "posting async-done message");
     gst_element_post_message (GST_ELEMENT_CAST (basesink),
-        gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+        gst_message_new_async_done (GST_OBJECT_CAST (basesink), reset_time));
   }
   if (post_playing) {
     GST_DEBUG_OBJECT (basesink, "posting PLAYING state change message");
@@ -1696,7 +1702,7 @@ stop_stepping (GstBaseSink * sink, GstSegment * segment,
     segment->start = current->start_start;
 
   /* the clip segment is used for position report in paused... */
-  gst_segment_copy_into (segment, sink->clip_segment);
+  gst_segment_copy_into (segment, &sink->clip_segment);
 
   /* post the step done when we know the stepped duration in TIME */
   message =
@@ -2067,8 +2073,8 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
   /* FIXME: Casting to GstClockEntry only works because the types
    * are the same */
   if (G_LIKELY (sink->priv->cached_clock_id != NULL
-          && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->
-              priv->cached_clock_id) == clock)) {
+          && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv->
+              cached_clock_id) == clock)) {
     if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id,
             time)) {
       gst_clock_id_unref (sink->priv->cached_clock_id);
@@ -2959,7 +2965,19 @@ again:
           gst_base_sink_configure_segment (basesink, pad, event,
               &basesink->segment);
           break;
-        case GST_EVENT_SINK_MESSAGE:{
+        case GST_EVENT_TAG:
+        {
+          GstTagList *taglist;
+
+          gst_event_parse_tag (event, &taglist);
+
+          gst_element_post_message (GST_ELEMENT_CAST (basesink),
+              gst_message_new_tag (GST_OBJECT_CAST (basesink),
+                  gst_tag_list_copy (taglist)));
+          break;
+        }
+        case GST_EVENT_SINK_MESSAGE:
+        {
           GstMessage *msg = NULL;
 
           gst_event_parse_sink_message (event, &msg);
@@ -3114,7 +3132,7 @@ stopping:
  *
  * Queue an object for rendering.
  * The first prerollable object queued will complete the preroll. If the
- * preroll queue if filled, we render all the objects in the queue.
+ * preroll queue is filled, we render all the objects in the queue.
  *
  * This function takes ownership of the object.
  */
@@ -3261,8 +3279,11 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
    * prerolled buffer */
   basesink->playing_async = TRUE;
   if (basesink->priv->async_enabled) {
-    gst_element_lost_state (GST_ELEMENT_CAST (basesink), TRUE);
+    gst_element_lost_state (GST_ELEMENT_CAST (basesink));
   } else {
+    /* start time reset in above case as well;
+     * arranges for a.o. proper position reporting when flushing in PAUSED */
+    gst_element_set_start_time (GST_ELEMENT_CAST (basesink), 0);
     basesink->priv->have_latency = TRUE;
   }
   gst_base_sink_set_last_buffer (basesink, NULL);
@@ -3270,7 +3291,8 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
 }
 
 static void
-gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
+gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad,
+    gboolean reset_time)
 {
   /* unset flushing so we can accept new data, this also flushes out any EOS
    * event. */
@@ -3287,9 +3309,12 @@ gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
   if (basesink->pad_mode == GST_ACTIVATE_PUSH) {
     /* we need new segment info after the flush. */
     basesink->have_newsegment = FALSE;
-    gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
-    gst_segment_init (basesink->clip_segment, GST_FORMAT_UNDEFINED);
+    if (reset_time) {
+      gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
+      gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED);
+    }
   }
+  basesink->priv->reset_time = reset_time;
   GST_OBJECT_UNLOCK (basesink);
 }
 
@@ -3320,22 +3345,20 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
       if (G_UNLIKELY (basesink->flushing))
         goto flushing;
 
-      if (G_UNLIKELY (basesink->priv->received_eos)) {
-        /* we can't accept anything when we are EOS */
+      if (G_UNLIKELY (basesink->priv->received_eos))
+        goto after_eos;
+
+      /* we set the received EOS flag here so that we can use it when testing if
+       * we are prerolled and to refuse more buffers. */
+      basesink->priv->received_eos = TRUE;
+
+      /* EOS is a prerollable object, we call the unlocked version because it
+       * does not check the received_eos flag. */
+      ret = gst_base_sink_queue_object_unlocked (basesink, pad,
+          _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE);
+      if (G_UNLIKELY (ret != GST_FLOW_OK))
         result = FALSE;
-        gst_event_unref (event);
-      } else {
-        /* we set the received EOS flag here so that we can use it when testing if
-         * we are prerolled and to refuse more buffers. */
-        basesink->priv->received_eos = TRUE;
-
-        /* EOS is a prerollable object, we call the unlocked version because it
-         * does not check the received_eos flag. */
-        ret = gst_base_sink_queue_object_unlocked (basesink, pad,
-            _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE);
-        if (G_UNLIKELY (ret != GST_FLOW_OK))
-          result = FALSE;
-      }
+
       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
       break;
     }
@@ -3362,11 +3385,14 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
       if (G_UNLIKELY (basesink->flushing))
         goto flushing;
 
+      if (G_UNLIKELY (basesink->priv->received_eos))
+        goto after_eos;
+
       /* the new segment is a non prerollable item and does not block anything,
        * we need to configure the current clipping segment and insert the event
        * in the queue to serialize it with the buffers for rendering. */
       gst_base_sink_configure_segment (basesink, pad, event,
-          basesink->clip_segment);
+          &basesink->clip_segment);
 
       ret =
           gst_base_sink_queue_object_unlocked (basesink, pad,
@@ -3392,15 +3418,21 @@ gst_base_sink_event (GstPad * pad, GstEvent * event)
       gst_event_unref (event);
       break;
     case GST_EVENT_FLUSH_STOP:
+    {
+      gboolean reset_time;
+
       if (bclass->event)
         bclass->event (basesink, event);
 
-      GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
+      gst_event_parse_flush_stop (event, &reset_time);
+      GST_DEBUG_OBJECT (basesink, "flush-stop %p, reset_time: %d", event,
+          reset_time);
 
-      gst_base_sink_flush_stop (basesink, pad);
+      gst_base_sink_flush_stop (basesink, pad, reset_time);
 
       gst_event_unref (event);
       break;
+    }
     default:
       /* other events are sent to queue or subclass depending on if they
        * are serialized. */
@@ -3428,6 +3460,15 @@ flushing:
     gst_event_unref (event);
     goto done;
   }
+
+after_eos:
+  {
+    GST_DEBUG_OBJECT (basesink, "Event received after EOS, dropping");
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
+    result = FALSE;
+    gst_event_unref (event);
+    goto done;
+  }
 }
 
 /* default implementation to calculate the start and end
@@ -3502,7 +3543,7 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
   }
 
   /* for code clarity */
-  clip_segment = basesink->clip_segment;
+  clip_segment = &basesink->clip_segment;
 
   if (G_UNLIKELY (!basesink->have_newsegment)) {
     gboolean sync;
@@ -3689,16 +3730,15 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
   GstSeekType cur_type, stop_type;
   gint64 cur, stop;
   GstSeekFlags flags;
-  GstFormat seek_format, dest_format;
+  GstFormat seek_format;
   gdouble rate;
   gboolean update;
   gboolean res = TRUE;
 
   gst_event_parse_seek (event, &rate, &seek_format, &flags,
       &cur_type, &cur, &stop_type, &stop);
-  dest_format = segment->format;
 
-  if (seek_format == dest_format) {
+  if (seek_format == segment->format) {
     gst_segment_do_seek (segment, rate, seek_format, flags,
         cur_type, cur, stop_type, stop, &update);
     return TRUE;
@@ -3707,7 +3747,7 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
   if (cur_type != GST_SEEK_TYPE_NONE) {
     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
     res =
-        gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format,
+        gst_pad_query_convert (sink->sinkpad, seek_format, cur, segment->format,
         &cur);
     cur_type = GST_SEEK_TYPE_SET;
   }
@@ -3715,13 +3755,13 @@ gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
   if (res && stop_type != GST_SEEK_TYPE_NONE) {
     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
     res =
-        gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format,
-        &stop);
+        gst_pad_query_convert (sink->sinkpad, seek_format, stop,
+        segment->format, &stop);
     stop_type = GST_SEEK_TYPE_SET;
   }
 
   /* And finally, configure our output segment in the desired format */
-  gst_segment_do_seek (segment, rate, dest_format, flags, cur_type, cur,
+  gst_segment_do_seek (segment, rate, segment->format, flags, cur_type, cur,
       stop_type, stop, &update);
 
   if (!res)
@@ -3814,8 +3854,8 @@ gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
 
   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);
+    gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
+    gst_base_sink_flush_stop (sink, pad, TRUE);
   } else if (res && sink->running) {
     /* we are running the current segment and doing a non-flushing seek,
      * close the segment first based on the position. */
@@ -3922,7 +3962,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
       sink->playing_async = TRUE;
       priv->pending_step.need_preroll = TRUE;
       sink->need_preroll = FALSE;
-      gst_element_lost_state (GST_ELEMENT_CAST (sink), FALSE);
+      gst_element_lost_state (GST_ELEMENT_CAST (sink));
     } else {
       sink->priv->have_latency = TRUE;
       sink->need_preroll = FALSE;
@@ -4098,6 +4138,8 @@ gst_base_sink_pad_activate (GstPad * pad)
 {
   gboolean result = FALSE;
   GstBaseSink *basesink;
+  GstQuery *query;
+  gboolean pull_mode;
 
   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
 
@@ -4112,7 +4154,19 @@ gst_base_sink_pad_activate (GstPad * pad)
   }
 
   /* check if downstreams supports pull mode at all */
-  if (!gst_pad_check_pull_range (pad)) {
+  query = gst_query_new_scheduling ();
+
+  if (!gst_pad_peer_query (pad, query)) {
+    gst_query_unref (query);
+    GST_DEBUG_OBJECT (basesink, "peer query faild, no pull mode");
+    goto fallback;
+  }
+
+  /* parse result of the query */
+  gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
+  gst_query_unref (query);
+
+  if (!pull_mode) {
     GST_DEBUG_OBJECT (basesink, "pull mode not supported");
     goto fallback;
   }
@@ -4228,7 +4282,8 @@ gst_base_sink_negotiate_pull (GstBaseSink * basesink)
     GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
 
     if (gst_caps_is_fixed (caps)) {
-      if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps))
+      if (!gst_pad_send_event (GST_BASE_SINK_PAD (basesink),
+              gst_event_new_caps (caps)))
         goto could_not_set_caps;
 
       GST_OBJECT_LOCK (basesink);
@@ -4271,26 +4326,23 @@ gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active)
   bclass = GST_BASE_SINK_GET_CLASS (basesink);
 
   if (active) {
-    GstFormat format;
     gint64 duration;
 
     /* we mark we have a newsegment here because pull based
      * mode works just fine without having a newsegment before the
      * first buffer */
-    format = GST_FORMAT_BYTES;
-
-    gst_segment_init (&basesink->segment, format);
-    gst_segment_init (basesink->clip_segment, format);
+    gst_segment_init (&basesink->segment, GST_FORMAT_BYTES);
+    gst_segment_init (&basesink->clip_segment, GST_FORMAT_BYTES);
     GST_OBJECT_LOCK (basesink);
     basesink->have_newsegment = TRUE;
     GST_OBJECT_UNLOCK (basesink);
 
     /* get the peer duration in bytes */
-    result = gst_pad_query_peer_duration (pad, &format, &duration);
+    result = gst_pad_query_peer_duration (pad, GST_FORMAT_BYTES, &duration);
     if (result) {
       GST_DEBUG_OBJECT (basesink,
           "setting duration in bytes to %" G_GINT64_FORMAT, duration);
-      basesink->clip_segment->duration = duration;
+      basesink->clip_segment.duration = duration;
       basesink->segment.duration = duration;
     } else {
       GST_DEBUG_OBJECT (basesink, "unknown duration");
@@ -4407,7 +4459,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
 {
   GstClock *clock = NULL;
   gboolean res = FALSE;
-  GstFormat oformat, tformat;
+  GstFormat oformat;
   GstSegment *segment;
   GstClockTime now, latency;
   GstClockTimeDiff base_time;
@@ -4434,12 +4486,10 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
    * main segment directly with the new segment values without it having to be
    * activated by the rendering after preroll */
   if (basesink->pad_mode == GST_ACTIVATE_PUSH)
-    segment = basesink->clip_segment;
+    segment = &basesink->clip_segment;
   else
     segment = &basesink->segment;
 
-  /* our intermediate time format */
-  tformat = GST_FORMAT_TIME;
   /* get the format in the segment */
   oformat = segment->format;
 
@@ -4457,6 +4507,14 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
   else
     gst_object_ref (clock);
 
+  /* mainloop might be querying position when going to playing async,
+   * while (audio) rendering might be quickly advancing stream position,
+   * so use clock asap rather than last reported position */
+  if (in_paused && with_clock && g_atomic_int_get (&basesink->priv->to_playing)) {
+    GST_DEBUG_OBJECT (basesink, "going to PLAYING, so not PAUSED");
+    in_paused = FALSE;
+  }
+
   /* collect all data we need holding the lock */
   if (GST_CLOCK_TIME_IS_VALID (segment->time))
     time = segment->time;
@@ -4536,23 +4594,23 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
         GST_TIME_ARGS (last));
     *cur = last;
   } else {
-    if (oformat != tformat) {
+    if (oformat != GST_FORMAT_TIME) {
       /* convert base, time and duration to time */
-      if (!gst_pad_query_convert (basesink->sinkpad, oformat, base, &tformat,
-              &base))
+      if (!gst_pad_query_convert (basesink->sinkpad, oformat, base,
+              GST_FORMAT_TIME, &base))
         goto convert_failed;
       if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration,
-              &tformat, &duration))
+              GST_FORMAT_TIME, &duration))
         goto convert_failed;
-      if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat,
-              &time))
+      if (!gst_pad_query_convert (basesink->sinkpad, oformat, time,
+              GST_FORMAT_TIME, &time))
         goto convert_failed;
-      if (!gst_pad_query_convert (basesink->sinkpad, oformat, last, &tformat,
-              &last))
+      if (!gst_pad_query_convert (basesink->sinkpad, oformat, last,
+              GST_FORMAT_TIME, &last))
         goto convert_failed;
 
       /* assume time format from now on */
-      oformat = tformat;
+      oformat = GST_FORMAT_TIME;
     }
 
     if (!in_paused && with_clock) {
@@ -4597,7 +4655,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
 
   if (oformat != format) {
     /* convert to final format */
-    if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur))
+    if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, format, cur))
       goto convert_failed;
   }
 
@@ -4638,20 +4696,22 @@ gst_base_sink_get_duration (GstBaseSink * basesink, GstFormat format,
   gboolean res = FALSE;
 
   if (basesink->pad_mode == GST_ACTIVATE_PULL) {
-    GstFormat uformat = GST_FORMAT_BYTES;
     gint64 uduration;
 
     /* get the duration in bytes, in pull mode that's all we are sure to
      * know. We have to explicitly get this value from upstream instead of
      * using our cached value because it might change. Duration caching
      * should be done at a higher level. */
-    res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, &uduration);
+    res =
+        gst_pad_query_peer_duration (basesink->sinkpad, GST_FORMAT_BYTES,
+        &uduration);
     if (res) {
       basesink->segment.duration = uduration;
-      if (format != uformat) {
+      if (format != GST_FORMAT_BYTES) {
         /* convert to the requested format */
-        res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration,
-            &format, dur);
+        res =
+            gst_pad_query_convert (basesink->sinkpad, GST_FORMAT_BYTES,
+            uduration, format, dur);
       } else {
         *dur = uduration;
       }
@@ -4679,7 +4739,7 @@ gst_base_sink_get_query_types (GstElement * element)
 }
 
 static gboolean
-gst_base_sink_query (GstElement * element, GstQuery * query)
+default_element_query (GstElement * element, GstQuery * query)
 {
   gboolean res = FALSE;
 
@@ -4709,20 +4769,21 @@ gst_base_sink_query (GstElement * element, GstQuery * query)
         /* we can handle a few things if upstream failed */
         if (format == GST_FORMAT_PERCENT) {
           gint64 dur = 0;
-          GstFormat uformat = GST_FORMAT_TIME;
 
           res = gst_base_sink_get_position (basesink, GST_FORMAT_TIME, &cur,
               &upstream);
           if (!res && upstream) {
-            res = gst_pad_query_peer_position (basesink->sinkpad, &uformat,
+            res =
+                gst_pad_query_peer_position (basesink->sinkpad, GST_FORMAT_TIME,
                 &cur);
           }
           if (res) {
             res = gst_base_sink_get_duration (basesink, GST_FORMAT_TIME, &dur,
                 &upstream);
             if (!res && upstream) {
-              res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat,
-                  &dur);
+              res =
+                  gst_pad_query_peer_duration (basesink->sinkpad,
+                  GST_FORMAT_TIME, &dur);
             }
           }
           if (res) {
@@ -4804,6 +4865,56 @@ gst_base_sink_query (GstElement * element, GstQuery * query)
   return res;
 }
 
+
+static gboolean
+default_sink_query (GstBaseSink * basesink, GstQuery * query)
+{
+  gboolean res;
+  GstBaseSinkClass *bclass;
+
+  bclass = GST_BASE_SINK_GET_CLASS (basesink);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_ALLOCATION:
+    {
+      if (bclass->setup_allocation)
+        res = bclass->setup_allocation (basesink, query);
+      else
+        res = FALSE;
+      break;
+    }
+    default:
+      res = gst_pad_query_default (basesink->sinkpad, query);
+      break;
+  }
+  return res;
+}
+
+static gboolean
+gst_base_sink_sink_query (GstPad * pad, GstQuery * query)
+{
+  GstBaseSink *basesink;
+  GstBaseSinkClass *bclass;
+  gboolean res;
+
+  basesink = GST_BASE_SINK_CAST (gst_pad_get_parent (pad));
+  if (G_UNLIKELY (basesink == NULL)) {
+    gst_query_unref (query);
+    return FALSE;
+  }
+
+  bclass = GST_BASE_SINK_GET_CLASS (basesink);
+
+  if (bclass->query)
+    res = bclass->query (basesink, query);
+  else
+    res = FALSE;
+
+  gst_object_unref (basesink);
+
+  return res;
+}
+
 static GstStateChangeReturn
 gst_base_sink_change_state (GstElement * element, GstStateChange transition)
 {
@@ -4829,12 +4940,13 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
       GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
       basesink->have_newsegment = FALSE;
       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
-      gst_segment_init (basesink->clip_segment, GST_FORMAT_UNDEFINED);
+      gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED);
       basesink->offset = 0;
       basesink->have_preroll = FALSE;
       priv->step_unlock = FALSE;
       basesink->need_preroll = TRUE;
       basesink->playing_async = TRUE;
+      basesink->priv->reset_time = FALSE;
       priv->current_sstart = GST_CLOCK_TIME_NONE;
       priv->current_sstop = GST_CLOCK_TIME_NONE;
       priv->eos_rtime = GST_CLOCK_TIME_NONE;
@@ -4852,7 +4964,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
          * the state change function */
         ret = GST_STATE_CHANGE_ASYNC;
         gst_element_post_message (GST_ELEMENT_CAST (basesink),
-            gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
+            gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
       } else {
         priv->have_latency = TRUE;
       }
@@ -4860,6 +4972,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       GST_BASE_SINK_PREROLL_LOCK (basesink);
+      g_atomic_int_set (&basesink->priv->to_playing, TRUE);
       if (!gst_base_sink_needs_preroll (basesink)) {
         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
         /* no preroll needed anymore now. */
@@ -4887,7 +5000,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
           GST_DEBUG_OBJECT (basesink, "doing async state change");
           ret = GST_STATE_CHANGE_ASYNC;
           gst_element_post_message (GST_ELEMENT_CAST (basesink),
-              gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
+              gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
         }
       }
       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
@@ -4905,7 +5018,14 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
   }
 
   switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      /* completed transition, so need not be marked any longer
+       * And it should be unmarked, since e.g. losing our position upon flush
+       * does not really change state to PAUSED ... */
+      g_atomic_int_set (&basesink->priv->to_playing, FALSE);
+      break;
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      g_atomic_int_set (&basesink->priv->to_playing, FALSE);
       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
       /* FIXME, make sure we cannot enter _render first */
 
@@ -4949,8 +5069,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
             GST_DEBUG_OBJECT (basesink, "doing async state change");
             ret = GST_STATE_CHANGE_ASYNC;
             gst_element_post_message (GST_ELEMENT_CAST (basesink),
-                gst_message_new_async_start (GST_OBJECT_CAST (basesink),
-                    FALSE));
+                gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
           }
         }
       }
@@ -4988,7 +5107,7 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
                   GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY));
 
           gst_element_post_message (GST_ELEMENT_CAST (basesink),
-              gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+              gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE));
         }
         priv->commited = TRUE;
       } else {