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;
}