[totem] Don't block main thread in _seek()



commit 9f355c1721553c3ca4f34c9b62c44bb58015a4e7
Author: Bastien Nocera <hadess hadess net>
Date:   Fri Mar 19 12:49:17 2010 +0000

    Don't block main thread in _seek()
    
    Instead keep hold of the last seek request and apply it
    when we've been told that the previous one finished, or
    apply it straight away if the previous seek took longer than
    1/10th of a second.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=588377

 src/backend/bacon-video-widget-gst-0.10.c |   89 ++++++++++++++++++++++++++---
 1 files changed, 80 insertions(+), 9 deletions(-)
---
diff --git a/src/backend/bacon-video-widget-gst-0.10.c b/src/backend/bacon-video-widget-gst-0.10.c
index d429a24..6ee45aa 100644
--- a/src/backend/bacon-video-widget-gst-0.10.c
+++ b/src/backend/bacon-video-widget-gst-0.10.c
@@ -93,6 +93,8 @@
 #define SMALL_STREAM_HEIGHT 120
 /* Maximum size of the logo */
 #define LOGO_SIZE 256
+#define NANOSECS_IN_SEC 1000000000
+#define SEEK_TIMEOUT NANOSECS_IN_SEC / 10
 
 #define is_error(e, d, c) \
   (e->domain == GST_##d##_ERROR && \
@@ -243,6 +245,12 @@ struct BaconVideoWidgetPrivate
 
   gint                         eos_id;
 
+  /* When seeking, queue up the seeks if they happen before
+   * the previous one finished */
+  GMutex                      *seek_mutex;
+  GstClock                    *clock;
+  GstClockTime                 seek_req_time;
+  gint64                       seek_time;
   /* state we want to be in, as opposed to actual pipeline state
    * which may change asynchronously or during buffering */
   GstState                     target_state;
@@ -297,6 +305,7 @@ static GError* bvw_error_from_gst_error (BaconVideoWidget *bvw, GstMessage *m);
 static gboolean bvw_check_for_cover_pixbuf (BaconVideoWidget * bvw);
 static const GdkPixbuf * bvw_get_logo_pixbuf (BaconVideoWidget * bvw);
 static gboolean bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward);
+static gboolean bacon_video_widget_seek_time_no_lock (BaconVideoWidget *bvw, gint64 _time, GError **error);
 
 static GtkWidgetClass *parent_class = NULL;
 
@@ -1300,6 +1309,11 @@ bacon_video_widget_init (BaconVideoWidget * bvw)
 
   priv->lock = g_mutex_new ();
 
+  priv->seek_mutex = g_mutex_new ();
+  priv->clock = gst_system_clock_obtain ();
+  priv->seek_req_time = GST_CLOCK_TIME_NONE;
+  priv->seek_time = -1;
+
   bvw->priv->missing_plugins = NULL;
   bvw->priv->plugin_install_in_progress = FALSE;
 
@@ -2178,6 +2192,24 @@ bvw_bus_message_cb (GstBus * bus, GstMessage * message, gpointer data)
       break;
     }
 
+    case GST_MESSAGE_ASYNC_DONE: {
+	gint64 _time;
+	/* When a seek has finished, set the playing state again */
+	g_mutex_lock (bvw->priv->seek_mutex);
+
+	bvw->priv->seek_req_time = gst_clock_get_internal_time (bvw->priv->clock);
+	_time = bvw->priv->seek_time;
+	bvw->priv->seek_time = -1;
+
+	g_mutex_unlock (bvw->priv->seek_mutex);
+
+	if (_time >= 0) {
+	  GST_DEBUG ("Have an old seek to schedule, doing it now");
+	  bacon_video_widget_seek_time_no_lock (bvw, _time, NULL);
+	}
+      break;
+    }
+
     /* FIXME: at some point we might want to handle CLOCK_LOST and set the
      * pipeline back to PAUSED and then PLAYING again to select a different
      * clock (this seems to trip up rtspsrc though so has to wait until
@@ -2649,6 +2681,11 @@ bacon_video_widget_finalize (GObject * object)
   g_free (bvw->priv->vis_element_name);
   bvw->priv->vis_element_name = NULL;
 
+  if (bvw->priv->clock) {
+    g_object_unref (bvw->priv->clock);
+    bvw->priv->clock = NULL;
+  }
+
   if (bvw->priv->vis_plugins_list) {
     g_list_free (bvw->priv->vis_plugins_list);
     bvw->priv->vis_plugins_list = NULL;
@@ -2708,6 +2745,7 @@ bacon_video_widget_finalize (GObject * object)
   }
 
   g_mutex_free (bvw->priv->lock);
+  g_mutex_free (bvw->priv->seek_mutex);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -3882,6 +3920,23 @@ bacon_video_widget_can_direct_seek (BaconVideoWidget *bvw)
   return FALSE;
 }
 
+static gboolean
+bacon_video_widget_seek_time_no_lock (BaconVideoWidget *bvw, gint64 _time, GError **error)
+{
+  if (bvw_set_playback_direction (bvw, TRUE) == FALSE)
+    return FALSE;
+
+  bvw->priv->seek_time = -1;
+  bvw->priv->rate = FORWARD_RATE;
+
+  gst_element_seek (bvw->priv->play, FORWARD_RATE,
+      GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT,
+      GST_SEEK_TYPE_SET, _time * GST_MSECOND,
+      GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
+  return TRUE;
+}
+
 /**
  * bacon_video_widget_seek_time:
  * @bvw: a #BaconVideoWidget
@@ -3896,6 +3951,7 @@ bacon_video_widget_can_direct_seek (BaconVideoWidget *bvw)
 gboolean
 bacon_video_widget_seek_time (BaconVideoWidget *bvw, gint64 _time, gboolean accurate, GError **error)
 {
+  GstClockTime cur_time;
   GstSeekFlags  flag;
 
   g_return_val_if_fail (bvw != NULL, FALSE);
@@ -3916,18 +3972,30 @@ bacon_video_widget_seek_time (BaconVideoWidget *bvw, gint64 _time, gboolean accu
   /* Emit a time tick of where we are going, we are paused */
   got_time_tick (bvw->priv->play, _time * GST_MSECOND, bvw);
 
+  /* Is there a pending seek? */
+  g_mutex_lock (bvw->priv->seek_mutex);
+  /* If there's no pending seek, or
+   * it's been too long since the seek,
+   * or we don't have an accurate seek requested */
+  cur_time = gst_clock_get_internal_time (bvw->priv->clock);
+  if (bvw->priv->seek_req_time == GST_CLOCK_TIME_NONE ||
+      cur_time > bvw->priv->seek_req_time + SEEK_TIMEOUT ||
+      accurate) {
+    bvw->priv->seek_time = -1;
+    bvw->priv->seek_req_time = cur_time;
+    g_mutex_unlock (bvw->priv->seek_mutex);
+  } else {
+    GST_LOG ("Not long enough since last seek, queuing it");
+    bvw->priv->seek_time = _time;
+    g_mutex_unlock (bvw->priv->seek_mutex);
+    return TRUE;
+  }
+
   if (bvw_set_playback_direction (bvw, TRUE) == FALSE)
     return FALSE;
 
   flag = (accurate ? GST_SEEK_FLAG_ACCURATE : GST_SEEK_FLAG_KEY_UNIT);
-  gst_element_seek (bvw->priv->play, FORWARD_RATE,
-      GST_FORMAT_TIME,
-      GST_SEEK_FLAG_FLUSH | flag,
-      GST_SEEK_TYPE_SET, _time * GST_MSECOND,
-      GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
-  bvw->priv->rate = FORWARD_RATE;
-
-  gst_element_get_state (bvw->priv->play, NULL, NULL, 100 * GST_MSECOND);
+  bacon_video_widget_seek_time_no_lock (bvw, _time, flag, error);
 
   return TRUE;
 }
@@ -4105,6 +4173,9 @@ bacon_video_widget_close (BaconVideoWidget * bvw)
   bvw->priv->window_resized = FALSE;
   bvw->priv->rate = FORWARD_RATE;
 
+  bvw->priv->seek_req_time = GST_CLOCK_TIME_NONE;
+  bvw->priv->seek_time = -1;
+
   if (bvw->priv->tagcache) {
     gst_tag_list_free (bvw->priv->tagcache);
     bvw->priv->tagcache = NULL;
@@ -4390,8 +4461,8 @@ bacon_video_widget_pause (BaconVideoWidget * bvw)
   }
 
   GST_LOG ("Pausing");
-  gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_PAUSED);
   bvw->priv->target_state = GST_STATE_PAUSED;
+  gst_element_set_state (GST_ELEMENT (bvw->priv->play), GST_STATE_PAUSED);
 }
 
 /**



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]