Title: [192094] trunk/Source/WebCore
Revision
192094
Author
[email protected]
Date
2015-11-05 23:28:00 -0800 (Thu, 05 Nov 2015)

Log Message

[GStreamer] Use RunLoop::Timer instead of GMainLoopSource in video sink
https://bugs.webkit.org/show_bug.cgi?id=150807

Reviewed by Žan Doberšek.

Since we always wait until the sample is actually rendered we
don't really need either a thread safe main loop source, nor
cancelling if already requested and other things GMainLoopSource does.
This adds a helper class VideoRenderRequestScheduler to use the
RunLoop::Timer. All the logic to syncronize between threads has
been moved to this helper class too.

* platform/graphics/gstreamer/VideoSinkGStreamer.cpp:
(VideoRenderRequestScheduler::VideoRenderRequestScheduler):
(VideoRenderRequestScheduler::start):
(VideoRenderRequestScheduler::stop):
(VideoRenderRequestScheduler::requestRender):
(VideoRenderRequestScheduler::isUnlocked):
(VideoRenderRequestScheduler::render):
(_WebKitVideoSinkPrivate::_WebKitVideoSinkPrivate):
(webkitVideoSinkRepaintRequested):
(webkitVideoSinkRender):
(webkitVideoSinkUnlock):
(webkitVideoSinkUnlockStop):
(webkitVideoSinkStop):
(webkitVideoSinkStart):
(_WebKitVideoSinkPrivate::~_WebKitVideoSinkPrivate): Deleted.
(webkitVideoSinkTimeoutCallback): Deleted.
(unlockSampleMutex): Deleted.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (192093 => 192094)


--- trunk/Source/WebCore/ChangeLog	2015-11-06 05:58:52 UTC (rev 192093)
+++ trunk/Source/WebCore/ChangeLog	2015-11-06 07:28:00 UTC (rev 192094)
@@ -1,3 +1,35 @@
+2015-11-05  Carlos Garcia Campos  <[email protected]>
+
+        [GStreamer] Use RunLoop::Timer instead of GMainLoopSource in video sink
+        https://bugs.webkit.org/show_bug.cgi?id=150807
+
+        Reviewed by Žan Doberšek.
+
+        Since we always wait until the sample is actually rendered we
+        don't really need either a thread safe main loop source, nor
+        cancelling if already requested and other things GMainLoopSource does.
+        This adds a helper class VideoRenderRequestScheduler to use the
+        RunLoop::Timer. All the logic to syncronize between threads has
+        been moved to this helper class too.
+
+        * platform/graphics/gstreamer/VideoSinkGStreamer.cpp:
+        (VideoRenderRequestScheduler::VideoRenderRequestScheduler):
+        (VideoRenderRequestScheduler::start):
+        (VideoRenderRequestScheduler::stop):
+        (VideoRenderRequestScheduler::requestRender):
+        (VideoRenderRequestScheduler::isUnlocked):
+        (VideoRenderRequestScheduler::render):
+        (_WebKitVideoSinkPrivate::_WebKitVideoSinkPrivate):
+        (webkitVideoSinkRepaintRequested):
+        (webkitVideoSinkRender):
+        (webkitVideoSinkUnlock):
+        (webkitVideoSinkUnlockStop):
+        (webkitVideoSinkStop):
+        (webkitVideoSinkStart):
+        (_WebKitVideoSinkPrivate::~_WebKitVideoSinkPrivate): Deleted.
+        (webkitVideoSinkTimeoutCallback): Deleted.
+        (unlockSampleMutex): Deleted.
+
 2015-11-05  Nikos Andronikos  <[email protected]>
 
         Add runtime and compile time flags for enabling Web Animations API and model.

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp (192093 => 192094)


--- trunk/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp	2015-11-06 05:58:52 UTC (rev 192093)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp	2015-11-06 07:28:00 UTC (rev 192094)
@@ -35,8 +35,8 @@
 #include <glib.h>
 #include <gst/gst.h>
 #include <gst/video/gstvideometa.h>
-#include <wtf/glib/GMutexLocker.h>
-#include <wtf/glib/GThreadSafeMainLoopSource.h>
+#include <wtf/Condition.h>
+#include <wtf/RunLoop.h>
 
 using namespace WebCore;
 
@@ -67,40 +67,97 @@
 
 static guint webkitVideoSinkSignals[LAST_SIGNAL] = { 0, };
 
-struct _WebKitVideoSinkPrivate {
-    _WebKitVideoSinkPrivate()
+static void webkitVideoSinkRepaintRequested(WebKitVideoSink*, GstSample*);
+static GRefPtr<GstSample> webkitVideoSinkRequestRender(WebKitVideoSink*, GstBuffer*);
+
+class VideoRenderRequestScheduler {
+public:
+    VideoRenderRequestScheduler()
+        : m_timer(RunLoop::main(), this, &VideoRenderRequestScheduler::render)
     {
-        g_mutex_init(&sampleMutex);
-        g_cond_init(&dataCondition);
-        gst_video_info_init(&info);
+#if PLATFORM(GTK)
+        // Use a higher priority than WebCore timers (G_PRIORITY_HIGH_IDLE + 20).
+        m_timer.setPriority(G_PRIORITY_HIGH_IDLE + 19);
+#endif
     }
 
-    ~_WebKitVideoSinkPrivate()
+    void start()
     {
-        g_mutex_clear(&sampleMutex);
-        g_cond_clear(&dataCondition);
+        LockHolder locker(m_sampleMutex);
+        m_unlocked = false;
     }
 
-    GstSample* sample;
-    GThreadSafeMainLoopSource timeoutSource;
-    GMutex sampleMutex;
-    GCond dataCondition;
+    void stop()
+    {
+        LockHolder locker(m_sampleMutex);
+        m_timer.stop();
+        m_sample = nullptr;
+        m_unlocked = true;
+        m_dataCondition.notifyOne();
+    }
 
-    GstVideoInfo info;
+    bool requestRender(WebKitVideoSink* sink, GstBuffer* buffer)
+    {
+        LockHolder locker(m_sampleMutex);
+        if (m_unlocked)
+            return true;
 
-    GstCaps* currentCaps;
+        m_sample = webkitVideoSinkRequestRender(sink, buffer);
+        if (!m_sample)
+            return false;
 
-    // If this is TRUE all processing should finish ASAP
+        m_sink = sink;
+        m_timer.startOneShot(0);
+        m_dataCondition.wait(m_sampleMutex);
+        return true;
+    }
+
+private:
+
+    void render()
+    {
+        LockHolder locker(m_sampleMutex);
+        GRefPtr<GstSample> sample = WTF::move(m_sample);
+        GRefPtr<WebKitVideoSink> sink = WTF::move(m_sink);
+        if (sample && !m_unlocked && LIKELY(GST_IS_SAMPLE(sample.get())))
+            webkitVideoSinkRepaintRequested(sink.get(), sample.get());
+        m_dataCondition.notifyOne();
+    }
+
+    RunLoop::Timer<VideoRenderRequestScheduler> m_timer;
+    Lock m_sampleMutex;
+    Condition m_dataCondition;
+    GRefPtr<GstSample> m_sample;
+    GRefPtr<WebKitVideoSink> m_sink;
+
+    // If this is true all processing should finish ASAP
     // This is necessary because there could be a race between
     // unlock() and render(), where unlock() wins, signals the
-    // GCond, then render() tries to render a frame although
+    // Condition, then render() tries to render a frame although
     // everything else isn't running anymore. This will lead
     // to deadlocks because render() holds the stream lock.
     //
     // Protected by the sample mutex
-    bool unlocked;
+    bool m_unlocked { false };
 };
 
+struct _WebKitVideoSinkPrivate {
+    _WebKitVideoSinkPrivate()
+    {
+        gst_video_info_init(&info);
+    }
+
+    ~_WebKitVideoSinkPrivate()
+    {
+        if (currentCaps)
+            gst_caps_unref(currentCaps);
+    }
+
+    VideoRenderRequestScheduler scheduler;
+    GstVideoInfo info;
+    GstCaps* currentCaps;
+};
+
 #define webkit_video_sink_parent_class parent_class
 G_DEFINE_TYPE_WITH_CODE(WebKitVideoSink, webkit_video_sink, GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT(webkitVideoSinkDebug, "webkitsink", 0, "webkit video sink"));
 
@@ -112,42 +169,20 @@
     new (sink->priv) WebKitVideoSinkPrivate();
 }
 
-static void webkitVideoSinkTimeoutCallback(WebKitVideoSink* sink)
+static void webkitVideoSinkRepaintRequested(WebKitVideoSink* sink, GstSample* sample)
 {
-    WebKitVideoSinkPrivate* priv = sink->priv;
-
-    WTF::GMutexLocker<GMutex> lock(priv->sampleMutex);
-    GstSample* sample = priv->sample;
-    priv->sample = 0;
-
-    if (!sample || priv->unlocked || UNLIKELY(!GST_IS_SAMPLE(sample))) {
-        g_cond_signal(&priv->dataCondition);
-        return;
-    }
-
     g_signal_emit(sink, webkitVideoSinkSignals[REPAINT_REQUESTED], 0, sample);
-    gst_sample_unref(sample);
-    g_cond_signal(&priv->dataCondition);
 }
 
-static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buffer)
+static GRefPtr<GstSample> webkitVideoSinkRequestRender(WebKitVideoSink* sink, GstBuffer* buffer)
 {
-    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
     WebKitVideoSinkPrivate* priv = sink->priv;
+    GRefPtr<GstSample> sample = adoptGRef(gst_sample_new(buffer, priv->currentCaps, nullptr, nullptr));
 
-    WTF::GMutexLocker<GMutex> lock(priv->sampleMutex);
-
-    if (priv->unlocked)
-        return GST_FLOW_OK;
-
-    priv->sample = gst_sample_new(buffer, priv->currentCaps, 0, 0);
-
     // The video info structure is valid only if the sink handled an allocation query.
     GstVideoFormat format = GST_VIDEO_INFO_FORMAT(&priv->info);
-    if (format == GST_VIDEO_FORMAT_UNKNOWN) {
-        gst_sample_unref(priv->sample);
-        return GST_FLOW_ERROR;
-    }
+    if (format == GST_VIDEO_FORMAT_UNKNOWN)
+        return nullptr;
 
 #if !(USE(TEXTURE_MAPPER_GL) && !USE(COORDINATED_GRAPHICS))
     // Cairo's ARGB has pre-multiplied alpha while GStreamer's doesn't.
@@ -163,7 +198,7 @@
         // Check if allocation failed.
         if (UNLIKELY(!newBuffer)) {
             gst_buffer_unref(buffer);
-            return GST_FLOW_ERROR;
+            return nullptr;
         }
 
         // We don't use Color::premultipliedARGBFromColor() here because
@@ -174,14 +209,13 @@
         GstVideoFrame destinationFrame;
 
         if (!gst_video_frame_map(&sourceFrame, &priv->info, buffer, GST_MAP_READ)) {
-            gst_sample_unref(priv->sample);
             gst_buffer_unref(newBuffer);
-            return GST_FLOW_ERROR;
+            return nullptr;
         }
         if (!gst_video_frame_map(&destinationFrame, &priv->info, newBuffer, GST_MAP_WRITE)) {
             gst_video_frame_unmap(&sourceFrame);
             gst_buffer_unref(newBuffer);
-            return GST_FLOW_ERROR;
+            return nullptr;
         }
 
         const guint8* source = static_cast<guint8*>(GST_VIDEO_FRAME_PLANE_DATA(&sourceFrame, 0));
@@ -209,20 +243,17 @@
 
         gst_video_frame_unmap(&sourceFrame);
         gst_video_frame_unmap(&destinationFrame);
-        gst_sample_unref(priv->sample);
-        priv->sample = gst_sample_new(newBuffer, priv->currentCaps, 0, 0);
+        sample = adoptGRef(gst_sample_new(newBuffer, priv->currentCaps, nullptr, nullptr));
     }
 #endif
 
-    // This should likely use a lower priority, but glib currently starves
-    // lower priority sources.
-    // See: https://bugzilla.gnome.org/show_bug.cgi?id=610830.
-    GRefPtr<WebKitVideoSink> protector(sink);
-    priv->timeoutSource.schedule("[WebKit] webkitVideoSinkTimeoutCallback",
-        std::function<void()>([protector] { webkitVideoSinkTimeoutCallback(protector.get()); }));
+    return sample;
+}
 
-    g_cond_wait(&priv->dataCondition, &priv->sampleMutex);
-    return GST_FLOW_OK;
+static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buffer)
+{
+    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
+    return sink->priv->scheduler.requestRender(sink, buffer) ? GST_FLOW_OK : GST_FLOW_ERROR;
 }
 
 static void webkitVideoSinkFinalize(GObject* object)
@@ -231,25 +262,11 @@
     G_OBJECT_CLASS(parent_class)->finalize(object);
 }
 
-static void unlockSampleMutex(WebKitVideoSinkPrivate* priv)
-{
-    WTF::GMutexLocker<GMutex> lock(priv->sampleMutex);
-
-    if (priv->sample) {
-        gst_sample_unref(priv->sample);
-        priv->sample = 0;
-    }
-
-    priv->unlocked = true;
-
-    g_cond_signal(&priv->dataCondition);
-}
-
 static gboolean webkitVideoSinkUnlock(GstBaseSink* baseSink)
 {
-    WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
+    WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
-    unlockSampleMutex(sink->priv);
+    priv->scheduler.stop();
 
     return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock, (baseSink), TRUE);
 }
@@ -258,10 +275,7 @@
 {
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
-    {
-        WTF::GMutexLocker<GMutex> lock(priv->sampleMutex);
-        priv->unlocked = false;
-    }
+    priv->scheduler.start();
 
     return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop, (baseSink), TRUE);
 }
@@ -270,11 +284,10 @@
 {
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
-    unlockSampleMutex(priv);
-
+    priv->scheduler.stop();
     if (priv->currentCaps) {
         gst_caps_unref(priv->currentCaps);
-        priv->currentCaps = 0;
+        priv->currentCaps = nullptr;
     }
 
     return TRUE;
@@ -284,8 +297,8 @@
 {
     WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
 
-    WTF::GMutexLocker<GMutex> lock(priv->sampleMutex);
-    priv->unlocked = false;
+    priv->scheduler.start();
+
     return TRUE;
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to