playbin2: make playsink go ASYNC to PAUSED
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 7 May 2009 12:28:30 +0000 (14:28 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Thu, 7 May 2009 12:28:30 +0000 (14:28 +0200)
Make playsink go async to the PAUSED state instead of relying on uridecodebin
for async behaviour in playbin. This solves some problems (mainly with DVD)
where the pipeline would go to PLAYING before preroll completed, failing to
select the audiosink clock.
Fixes #581727

gst/playback/gstplaysink.c

index b7f8c85..51faf78 100644 (file)
@@ -122,6 +122,8 @@ struct _GstPlaySink
 
   GMutex *lock;
 
+  gboolean async_pending;
+
   GstPlayFlags flags;
 
   /* chains */
@@ -794,6 +796,32 @@ gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj,
   return result;
 }
 
+static void
+do_async_start (GstPlaySink * playsink)
+{
+  GstMessage *message;
+
+  playsink->async_pending = TRUE;
+
+  message = gst_message_new_async_start (GST_OBJECT_CAST (playsink), FALSE);
+  GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
+      (playsink), message);
+}
+
+static void
+do_async_done (GstPlaySink * playsink)
+{
+  GstMessage *message;
+
+  if (playsink->async_pending) {
+    message = gst_message_new_async_done (GST_OBJECT_CAST (playsink));
+    GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
+        (playsink), message);
+
+    playsink->async_pending = FALSE;
+  }
+}
+
 /* try to change the state of an element. This function returns the element when
  * the state change could be performed. When this function returns NULL an error
  * occured and the element is unreffed if @unref is TRUE. */
@@ -1974,6 +2002,7 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
       activate_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
     }
   }
+  do_async_done (playsink);
   GST_PLAY_SINK_UNLOCK (playsink);
 
   return TRUE;
@@ -2318,22 +2347,30 @@ static GstStateChangeReturn
 gst_play_sink_change_state (GstElement * element, GstStateChange transition)
 {
   GstStateChangeReturn ret;
+  GstStateChangeReturn bret;
+
   GstPlaySink *playsink;
 
   playsink = GST_PLAY_SINK (element);
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
+      do_async_start (playsink);
+      ret = GST_STATE_CHANGE_ASYNC;
       break;
     default:
       break;
   }
 
-  ret =
+  bret =
       GST_ELEMENT_CLASS (gst_play_sink_parent_class)->change_state (element,
       transition);
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    return ret;
+  if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE))
+    goto activate_failed;
+  else if (G_UNLIKELY (bret == GST_STATE_CHANGE_NO_PREROLL)) {
+    do_async_done (playsink);
+    ret = bret;
+  }
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
@@ -2359,10 +2396,19 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
         activate_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
         add_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
       }
+      do_async_done (playsink);
       break;
     default:
       break;
   }
 
   return ret;
+
+  /* ERRORS */
+activate_failed:
+  {
+    GST_DEBUG_OBJECT (element,
+        "element failed to change states -- activation problem?");
+    return GST_STATE_CHANGE_FAILURE;
+  }
 }