summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp')
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp340
1 files changed, 176 insertions, 164 deletions
diff --git a/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
index 7dd894e28..9adaaa0bb 100644
--- a/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
+++ b/Source/WebCore/platform/graphics/gstreamer/VideoSinkGStreamer.cpp
@@ -1,7 +1,8 @@
/*
* Copyright (C) 2007 OpenedHand
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
- * Copyright (C) 2009, 2010, 2011, 2012 Igalia S.L
+ * Copyright (C) 2009, 2010, 2011, 2012, 2015, 2016 Igalia S.L
+ * Copyright (C) 2015, 2016 Metrological Group B.V.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -35,8 +36,8 @@
#include <glib.h>
#include <gst/gst.h>
#include <gst/video/gstvideometa.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/gobject/GMutexLocker.h>
+#include <wtf/Condition.h>
+#include <wtf/RunLoop.h>
using namespace WebCore;
@@ -46,13 +47,8 @@ using namespace WebCore;
#else
#define GST_CAPS_FORMAT "{ xRGB, ARGB }"
#endif
-#if GST_CHECK_VERSION(1, 1, 0)
-#define GST_FEATURED_CAPS GST_VIDEO_CAPS_MAKE_WITH_FEATURES(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, GST_CAPS_FORMAT) ";"
-#else
-#define GST_FEATURED_CAPS
-#endif
-#define WEBKIT_VIDEO_SINK_PAD_CAPS GST_FEATURED_CAPS GST_VIDEO_CAPS_MAKE(GST_CAPS_FORMAT)
+#define WEBKIT_VIDEO_SINK_PAD_CAPS GST_VIDEO_CAPS_MAKE_WITH_FEATURES(GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, GST_CAPS_FORMAT) ";" GST_VIDEO_CAPS_MAKE(GST_CAPS_FORMAT)
static GstStaticPadTemplate s_sinkTemplate = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS(WEBKIT_VIDEO_SINK_PAD_CAPS));
@@ -62,35 +58,123 @@ GST_DEBUG_CATEGORY_STATIC(webkitVideoSinkDebug);
enum {
REPAINT_REQUESTED,
+ REPAINT_CANCELLED,
LAST_SIGNAL
};
-enum {
- PROP_0,
- PROP_CAPS
-};
-
static guint webkitVideoSinkSignals[LAST_SIGNAL] = { 0, };
-struct _WebKitVideoSinkPrivate {
- GstBuffer* buffer;
- guint timeoutId;
- GMutex* bufferMutex;
- GCond* dataCondition;
+static void webkitVideoSinkRepaintRequested(WebKitVideoSink*, GstSample*);
+static GRefPtr<GstSample> webkitVideoSinkRequestRender(WebKitVideoSink*, GstBuffer*);
- GstVideoInfo info;
+class VideoRenderRequestScheduler {
+public:
+ VideoRenderRequestScheduler()
+#if !USE(COORDINATED_GRAPHICS_THREADED)
+ : m_timer(RunLoop::main(), this, &VideoRenderRequestScheduler::render)
+#endif
+ {
+#if PLATFORM(GTK) && !USE(COORDINATED_GRAPHICS_THREADED)
+ // Use a higher priority than WebCore timers (G_PRIORITY_HIGH_IDLE + 20).
+ m_timer.setPriority(G_PRIORITY_HIGH_IDLE + 19);
+#endif
+ }
- GstCaps* currentCaps;
+ void start()
+ {
+ LockHolder locker(m_sampleMutex);
+ m_unlocked = false;
+ }
+
+ void stop()
+ {
+ LockHolder locker(m_sampleMutex);
+ m_sample = nullptr;
+ m_unlocked = true;
+#if !USE(COORDINATED_GRAPHICS_THREADED)
+ m_timer.stop();
+ m_dataCondition.notifyOne();
+#endif
+ }
+
+ void drain()
+ {
+ LockHolder locker(m_sampleMutex);
+ m_sample = nullptr;
+ }
+
+ bool requestRender(WebKitVideoSink* sink, GstBuffer* buffer)
+ {
+ LockHolder locker(m_sampleMutex);
+ if (m_unlocked)
+ return true;
+
+ m_sample = webkitVideoSinkRequestRender(sink, buffer);
+ if (!m_sample)
+ return false;
+
+#if USE(COORDINATED_GRAPHICS_THREADED)
+ auto sample = WTFMove(m_sample);
+ locker.unlockEarly();
+ if (LIKELY(GST_IS_SAMPLE(sample.get())))
+ webkitVideoSinkRepaintRequested(sink, sample.get());
+#else
+ m_sink = sink;
+ m_timer.startOneShot(0);
+ m_dataCondition.wait(m_sampleMutex);
+#endif
+ return true;
+ }
- // If this is TRUE all processing should finish ASAP
+private:
+
+#if !USE(COORDINATED_GRAPHICS_THREADED)
+ void render()
+ {
+ LockHolder locker(m_sampleMutex);
+ GRefPtr<GstSample> sample = WTFMove(m_sample);
+ GRefPtr<WebKitVideoSink> sink = WTFMove(m_sink);
+ if (sample && !m_unlocked && LIKELY(GST_IS_SAMPLE(sample.get())))
+ webkitVideoSinkRepaintRequested(sink.get(), sample.get());
+ m_dataCondition.notifyOne();
+ }
+#endif
+
+ Lock m_sampleMutex;
+ GRefPtr<GstSample> m_sample;
+
+#if !USE(COORDINATED_GRAPHICS_THREADED)
+ RunLoop::Timer<VideoRenderRequestScheduler> m_timer;
+ Condition m_dataCondition;
+ GRefPtr<WebKitVideoSink> m_sink;
+#endif
+
+ // 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 buffer mutex
- bool unlocked;
+ // Protected by the sample mutex
+ 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
@@ -100,59 +184,29 @@ G_DEFINE_TYPE_WITH_CODE(WebKitVideoSink, webkit_video_sink, GST_TYPE_VIDEO_SINK,
static void webkit_video_sink_init(WebKitVideoSink* sink)
{
sink->priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
-#if GLIB_CHECK_VERSION(2, 31, 0)
- sink->priv->dataCondition = new GCond;
- g_cond_init(sink->priv->dataCondition);
- sink->priv->bufferMutex = new GMutex;
- g_mutex_init(sink->priv->bufferMutex);
-#else
- sink->priv->dataCondition = g_cond_new();
- sink->priv->bufferMutex = g_mutex_new();
-#endif
-
- gst_video_info_init(&sink->priv->info);
+ g_object_set(GST_BASE_SINK(sink), "enable-last-sample", FALSE, nullptr);
+ new (sink->priv) WebKitVideoSinkPrivate();
}
-static gboolean webkitVideoSinkTimeoutCallback(gpointer data)
+static void webkitVideoSinkRepaintRequested(WebKitVideoSink* sink, GstSample* sample)
{
- WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data);
- WebKitVideoSinkPrivate* priv = sink->priv;
-
- WTF::GMutexLocker lock(priv->bufferMutex);
- GstBuffer* buffer = priv->buffer;
- priv->buffer = 0;
- priv->timeoutId = 0;
-
- if (!buffer || priv->unlocked || UNLIKELY(!GST_IS_BUFFER(buffer))) {
- g_cond_signal(priv->dataCondition);
- return FALSE;
- }
-
- g_signal_emit(sink, webkitVideoSinkSignals[REPAINT_REQUESTED], 0, buffer);
- gst_buffer_unref(buffer);
- g_cond_signal(priv->dataCondition);
+ g_signal_emit(sink, webkitVideoSinkSignals[REPAINT_REQUESTED], 0, sample);
+}
- return FALSE;
+static void webkitVideoSinkRepaintCancelled(WebKitVideoSink* sink)
+{
+ g_signal_emit(sink, webkitVideoSinkSignals[REPAINT_CANCELLED], 0);
}
-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;
-
- WTF::GMutexLocker lock(priv->bufferMutex);
-
- if (priv->unlocked)
- return GST_FLOW_OK;
-
- priv->buffer = gst_buffer_ref(buffer);
+ GRefPtr<GstSample> sample = adoptGRef(gst_sample_new(buffer, priv->currentCaps, nullptr, nullptr));
// 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_buffer_unref(buffer);
- 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.
@@ -166,10 +220,8 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
GstBuffer* newBuffer = WebCore::createGstBuffer(buffer);
// Check if allocation failed.
- if (UNLIKELY(!newBuffer)) {
- gst_buffer_unref(buffer);
- return GST_FLOW_ERROR;
- }
+ if (UNLIKELY(!newBuffer))
+ return nullptr;
// We don't use Color::premultipliedARGBFromColor() here because
// one function call per video pixel is just too expensive:
@@ -179,15 +231,13 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
GstVideoFrame destinationFrame;
if (!gst_video_frame_map(&sourceFrame, &priv->info, buffer, GST_MAP_READ)) {
- gst_buffer_unref(buffer);
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(buffer);
gst_buffer_unref(newBuffer);
- return GST_FLOW_ERROR;
+ return nullptr;
}
const guint8* source = static_cast<guint8*>(GST_VIDEO_FRAME_PLANE_DATA(&sourceFrame, 0));
@@ -215,87 +265,32 @@ static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buf
gst_video_frame_unmap(&sourceFrame);
gst_video_frame_unmap(&destinationFrame);
- gst_buffer_unref(buffer);
- buffer = priv->buffer = newBuffer;
- }
-#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.
- priv->timeoutId = g_timeout_add_full(G_PRIORITY_DEFAULT, 0, webkitVideoSinkTimeoutCallback,
- gst_object_ref(sink), reinterpret_cast<GDestroyNotify>(gst_object_unref));
- g_source_set_name_by_id(priv->timeoutId, "[WebKit] webkitVideoSinkTimeoutCallback");
-
- g_cond_wait(priv->dataCondition, priv->bufferMutex);
- return GST_FLOW_OK;
-}
-
-static void webkitVideoSinkDispose(GObject* object)
-{
- WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
- WebKitVideoSinkPrivate* priv = sink->priv;
-
- if (priv->dataCondition) {
-#if GLIB_CHECK_VERSION(2, 31, 0)
- g_cond_clear(priv->dataCondition);
- delete priv->dataCondition;
-#else
- g_cond_free(priv->dataCondition);
-#endif
- priv->dataCondition = 0;
+ sample = adoptGRef(gst_sample_new(newBuffer, priv->currentCaps, nullptr, nullptr));
+ gst_buffer_unref(newBuffer);
}
-
- if (priv->bufferMutex) {
-#if GLIB_CHECK_VERSION(2, 31, 0)
- g_mutex_clear(priv->bufferMutex);
- delete priv->bufferMutex;
-#else
- g_mutex_free(priv->bufferMutex);
#endif
- priv->bufferMutex = 0;
- }
- G_OBJECT_CLASS(parent_class)->dispose(object);
+ return sample;
}
-static void webkitVideoSinkGetProperty(GObject* object, guint propertyId, GValue* value, GParamSpec* parameterSpec)
+static GstFlowReturn webkitVideoSinkRender(GstBaseSink* baseSink, GstBuffer* buffer)
{
- WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
- WebKitVideoSinkPrivate* priv = sink->priv;
-
- switch (propertyId) {
- case PROP_CAPS: {
- GstCaps* caps = priv->currentCaps;
- if (caps)
- gst_caps_ref(caps);
- g_value_take_boxed(value, caps);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyId, parameterSpec);
- }
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
+ return sink->priv->scheduler.requestRender(sink, buffer) ? GST_FLOW_OK : GST_FLOW_ERROR;
}
-static void unlockBufferMutex(WebKitVideoSinkPrivate* priv)
+static void webkitVideoSinkFinalize(GObject* object)
{
- WTF::GMutexLocker lock(priv->bufferMutex);
-
- if (priv->buffer) {
- gst_buffer_unref(priv->buffer);
- priv->buffer = 0;
- }
-
- priv->unlocked = true;
-
- g_cond_signal(priv->dataCondition);
+ WEBKIT_VIDEO_SINK(object)->priv->~WebKitVideoSinkPrivate();
+ G_OBJECT_CLASS(parent_class)->finalize(object);
}
static gboolean webkitVideoSinkUnlock(GstBaseSink* baseSink)
{
- WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
+ WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
- unlockBufferMutex(sink->priv);
+ priv->scheduler.stop();
+ webkitVideoSinkRepaintCancelled(WEBKIT_VIDEO_SINK(baseSink));
return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock, (baseSink), TRUE);
}
@@ -304,10 +299,7 @@ static gboolean webkitVideoSinkUnlockStop(GstBaseSink* baseSink)
{
WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
- {
- WTF::GMutexLocker lock(priv->bufferMutex);
- priv->unlocked = false;
- }
+ priv->scheduler.start();
return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop, (baseSink), TRUE);
}
@@ -316,11 +308,11 @@ static gboolean webkitVideoSinkStop(GstBaseSink* baseSink)
{
WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
- unlockBufferMutex(priv);
-
+ priv->scheduler.stop();
+ webkitVideoSinkRepaintCancelled(WEBKIT_VIDEO_SINK(baseSink));
if (priv->currentCaps) {
gst_caps_unref(priv->currentCaps);
- priv->currentCaps = 0;
+ priv->currentCaps = nullptr;
}
return TRUE;
@@ -330,8 +322,8 @@ static gboolean webkitVideoSinkStart(GstBaseSink* baseSink)
{
WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(baseSink)->priv;
- WTF::GMutexLocker lock(priv->bufferMutex);
- priv->unlocked = false;
+ priv->scheduler.start();
+
return TRUE;
}
@@ -357,7 +349,7 @@ static gboolean webkitVideoSinkSetCaps(GstBaseSink* baseSink, GstCaps* caps)
static gboolean webkitVideoSinkProposeAllocation(GstBaseSink* baseSink, GstQuery* query)
{
GstCaps* caps;
- gst_query_parse_allocation(query, &caps, 0);
+ gst_query_parse_allocation(query, &caps, nullptr);
if (!caps)
return FALSE;
@@ -365,14 +357,27 @@ static gboolean webkitVideoSinkProposeAllocation(GstBaseSink* baseSink, GstQuery
if (!gst_video_info_from_caps(&sink->priv->info, caps))
return FALSE;
- gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, 0);
- gst_query_add_allocation_meta(query, GST_VIDEO_CROP_META_API_TYPE, 0);
-#if GST_CHECK_VERSION(1, 1, 0)
- gst_query_add_allocation_meta(query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, 0);
-#endif
+ gst_query_add_allocation_meta(query, GST_VIDEO_META_API_TYPE, nullptr);
+ gst_query_add_allocation_meta(query, GST_VIDEO_CROP_META_API_TYPE, nullptr);
+ gst_query_add_allocation_meta(query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, nullptr);
return TRUE;
}
+static gboolean webkitVideoSinkEvent(GstBaseSink* baseSink, GstEvent* event)
+{
+ switch (GST_EVENT_TYPE(event)) {
+ case GST_EVENT_FLUSH_START: {
+ WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(baseSink);
+ sink->priv->scheduler.drain();
+
+ GST_DEBUG_OBJECT(sink, "Flush-start, releasing m_sample");
+ }
+ FALLTHROUGH;
+ default:
+ return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, event, (baseSink, event), TRUE);
+ }
+}
+
static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
{
GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
@@ -384,8 +389,7 @@ static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate));
- gobjectClass->dispose = webkitVideoSinkDispose;
- gobjectClass->get_property = webkitVideoSinkGetProperty;
+ gobjectClass->finalize = webkitVideoSinkFinalize;
baseSinkClass->unlock = webkitVideoSinkUnlock;
baseSinkClass->unlock_stop = webkitVideoSinkUnlockStop;
@@ -395,9 +399,7 @@ static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
baseSinkClass->start = webkitVideoSinkStart;
baseSinkClass->set_caps = webkitVideoSinkSetCaps;
baseSinkClass->propose_allocation = webkitVideoSinkProposeAllocation;
-
- g_object_class_install_property(gobjectClass, PROP_CAPS,
- g_param_spec_boxed("current-caps", "Current-Caps", "Current caps", GST_TYPE_CAPS, G_PARAM_READABLE));
+ baseSinkClass->event = webkitVideoSinkEvent;
webkitVideoSinkSignals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
G_TYPE_FROM_CLASS(klass),
@@ -408,13 +410,23 @@ static void webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
g_cclosure_marshal_generic,
G_TYPE_NONE, // Return type
1, // Only one parameter
- GST_TYPE_BUFFER);
+ GST_TYPE_SAMPLE);
+ webkitVideoSinkSignals[REPAINT_CANCELLED] = g_signal_new("repaint-cancelled",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ 0, // Class offset
+ nullptr, // Accumulator
+ nullptr, // Accumulator data
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, // Return type
+ 0, // No parameters
+ G_TYPE_NONE);
}
GstElement* webkitVideoSinkNew()
{
- return GST_ELEMENT(g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0));
+ return GST_ELEMENT(g_object_new(WEBKIT_TYPE_VIDEO_SINK, nullptr));
}
#endif // ENABLE(VIDEO) && USE(GSTREAMER)