All pastes #1594958 Raw Edit

Something

public text v1 · immutable
#1594958 ·published 2009-10-05 17:00 UTC
rendered paste body
From 8d00890ce59b5ddbea5ee5e2ec91b5e4b37e4149 Mon Sep 17 00:00:00 2001
From: Philippe Normand <pnormand@igalia.com>
Date: Fri, 2 Oct 2009 11:09:12 +0200
Subject: [PATCH] sink: replace the idle with a timeout

---
 WebCore/ChangeLog                                  |   19 ++++
 .../graphics/gtk/MediaPlayerPrivateGStreamer.cpp   |   11 ---
 .../platform/graphics/gtk/VideoSinkGStreamer.cpp   |   91 +++++++++++++------
 3 files changed, 81 insertions(+), 40 deletions(-)

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 8b07193..1dae1c8 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -8,6 +8,25 @@
         * platform/qt/PlatformKeyboardEventQt.cpp:
         (WebCore::windowsKeyCodeForKeyEvent):
 
+2009-10-05  Philippe Normand  <pnormand@igalia.com>
+
+        Reviewed by NOBODY (OOPS!).
+
+        https://bugs.webkit.org/show_bug.cgi?id=29959
+        [GTK] QoS support in the video sink
+
+        Replace the idle with a timeout function in the sink. Allows
+        smoother video playback. This patch also adds basic QoS support
+        but we will improve things on that front progressively.
+
+        * platform/graphics/gtk/VideoSinkGStreamer.cpp:
+        (webkit_video_sink_init):
+        (webkit_video_sink_timeout_func):
+        (destroy_timeout_data):
+        (webkit_video_sink_render):
+        (webkit_video_sink_dispose):
+        (webkit_video_sink_stop):
+
 2009-10-05  Fumitoshi Ukai  <ukai@chromium.org>
 
         Unreviewed build fix for ENABLE(WEB_SOCKETS) and v8.
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 65c64b4..bf89376 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -174,17 +174,6 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
         gst_object_unref(GST_OBJECT(m_playBin));
     }
 
-    // FIXME: We should find a better way to handle the lifetime of this object; this is
-    // needed because the object is sometimes being destroyed inbetween a call to
-    // webkit_video_sink_render, and the idle it schedules. Adding a ref in
-    // webkit_video_sink_render that would be balanced by the idle is not an option,
-    // because in some cases the destruction of the sink may happen in time for the idle
-    // to be removed from the queue, so it may not run. It would also cause lots of ref
-    // counting churn (render/idle are called many times). This is an ugly race.
-    if (m_videoSink) {
-        g_idle_add(idleUnref, m_videoSink);
-        m_videoSink = 0;
-    }
 }
 
 void MediaPlayerPrivate::load(const String& url)
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
index bb269cd..ddf890a 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -65,7 +65,6 @@ static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, };
 
 struct _WebKitVideoSinkPrivate {
     cairo_surface_t* surface;
-    GAsyncQueue* async_queue;
     gboolean rgb_ordering;
     int width;
     int height;
@@ -73,6 +72,10 @@ struct _WebKitVideoSinkPrivate {
     int fps_d;
     int par_n;
     int par_d;
+    GstBuffer* buffer;
+    guint timeout_id;
+    GMutex* buffer_mutex;
+    GCond* data_cond;
 };
 
 #define _do_init(bla) \
@@ -102,32 +105,39 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
     WebKitVideoSinkPrivate* priv;
 
     sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
-    priv->async_queue = g_async_queue_new();
+    priv->data_cond = g_cond_new();
+    priv->buffer_mutex = g_mutex_new();
 }
 
 static gboolean
-webkit_video_sink_idle_func(gpointer data)
+webkit_video_sink_timeout_func(gpointer data)
 {
     WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data);
     WebKitVideoSinkPrivate* priv = sink->priv;
     GstBuffer* buffer;
     GstCaps* caps;
     GstVideoFormat* format;
+    guint timeout_id;
     gint par_n, par_d;
     gfloat par;
     gint bwidth, bheight;
 
-    if (!priv->async_queue)
-        return FALSE;
+    g_mutex_lock(priv->buffer_mutex);
+    buffer = priv->buffer;
+    timeout_id = priv->timeout_id;
 
-    buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue);
-    if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer)))
+    if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer))) {
+        g_cond_signal(priv->data_cond);
+        g_mutex_unlock(priv->buffer_mutex);
         return FALSE;
+    }
 
     caps = GST_BUFFER_CAPS(buffer);
     if (!gst_video_format_parse_caps(caps, format, &bwidth, &bheight)) {
         GST_ERROR_OBJECT(sink, "Unknown video format in buffer caps '%s'",
                          gst_caps_to_string(caps));
+        g_cond_signal(priv->data_cond);
+        g_mutex_unlock(priv->buffer_mutex);
         return FALSE;
     }
 
@@ -136,7 +146,6 @@ webkit_video_sink_idle_func(gpointer data)
 
     par = (gfloat) par_n / (gfloat) par_d;
 
-    // TODO: consider priv->rgb_ordering?
     cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer),
                                                                CAIRO_FORMAT_RGB24,
                                                                bwidth, bheight,
@@ -151,10 +160,13 @@ webkit_video_sink_idle_func(gpointer data)
     cairo_rectangle(cr, 0, 0, priv->width, priv->height);
     cairo_fill(cr);
     cairo_destroy(cr);
+
     gst_buffer_unref(buffer);
-    g_async_queue_unref(priv->async_queue);
+    priv->buffer = 0;
 
     g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0);
+    g_cond_signal(priv->data_cond);
+    g_mutex_unlock(priv->buffer_mutex);
 
     return FALSE;
 }
@@ -165,10 +177,17 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
     WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
     WebKitVideoSinkPrivate* priv = sink->priv;
 
-    g_async_queue_ref(priv->async_queue);
-    g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
-    g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, 0);
+    g_mutex_lock(priv->buffer_mutex);
+    priv->buffer = gst_buffer_ref(buffer);
+
+    // use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations
+    priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0,
+                                          webkit_video_sink_timeout_func,
+                                          gst_object_ref(sink),
+                                          (GDestroyNotify) gst_object_unref);
 
+    g_cond_wait(priv->data_cond, priv->buffer_mutex);
+    g_mutex_unlock(priv->buffer_mutex);
     return GST_FLOW_OK;
 }
 
@@ -225,18 +244,42 @@ webkit_video_sink_dispose(GObject* object)
         priv->surface = 0;
     }
 
-    if (priv->async_queue) {
-        g_async_queue_unref(priv->async_queue);
-        priv->async_queue = 0;
+    if (priv->data_cond) {
+        g_cond_free(priv->data_cond);
+        priv->data_cond = 0;
+    }
+
+    if (priv->buffer_mutex) {
+        g_mutex_free(priv->buffer_mutex);
+        priv->buffer_mutex = 0;
     }
 
     G_OBJECT_CLASS(parent_class)->dispose(object);
 }
 
 static void
-webkit_video_sink_finalize(GObject* object)
+_unlock_buffer_mutex(WebKitVideoSinkPrivate* priv)
+{
+
+    g_mutex_lock(priv->buffer_mutex);
+
+    if (priv->buffer) {
+        gst_buffer_unref(priv->buffer);
+        priv->buffer = 0;
+    }
+
+    g_cond_signal(priv->data_cond);
+    g_mutex_unlock(priv->buffer_mutex);
+
+}
+
+static gboolean
+webkit_video_sink_unlock(GstBaseSink* object)
 {
-    G_OBJECT_CLASS(parent_class)->finalize(object);
+    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+    _unlock_buffer_mutex(sink->priv);
+    GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock,
+                                 (object), TRUE);
 }
 
 static void
@@ -276,17 +319,7 @@ static gboolean
 webkit_video_sink_stop(GstBaseSink* base_sink)
 {
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
-
-    g_async_queue_lock(priv->async_queue);
-
-    /* Remove all remaining objects from the queue */
-    while (GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue))
-        gst_buffer_unref(buffer);
-
-    g_async_queue_unlock(priv->async_queue);
-
-    g_idle_remove_by_data(base_sink);
-
+    _unlock_buffer_mutex(priv);
     return TRUE;
 }
 
@@ -302,7 +335,7 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
     gobject_class->get_property = webkit_video_sink_get_property;
 
     gobject_class->dispose = webkit_video_sink_dispose;
-    gobject_class->finalize = webkit_video_sink_finalize;
+    gstbase_sink_class->unlock = webkit_video_sink_unlock;
 
     gstbase_sink_class->render = webkit_video_sink_render;
     gstbase_sink_class->preroll = webkit_video_sink_render;
-- 
1.6.0.4