summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp')
-rw-r--r--Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp226
1 files changed, 226 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp b/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
new file mode 100644
index 0000000..d179601
--- /dev/null
+++ b/Source/WebCore/platform/graphics/gstreamer/GStreamerGWorld.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2010 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "GStreamerGWorld.h"
+#if USE(GSTREAMER)
+
+#include "GOwnPtrGStreamer.h"
+#include <gst/gst.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/pbutils/pbutils.h>
+
+#if PLATFORM(GTK)
+#include <gtk/gtk.h>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h> // for GDK_WINDOW_XID
+#endif
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+gboolean gstGWorldSyncMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
+{
+ ASSERT(GST_MESSAGE_TYPE(message) == GST_MESSAGE_ELEMENT);
+
+ GStreamerGWorld* gstGWorld = static_cast<GStreamerGWorld*>(data);
+
+ if (gst_structure_has_name(message->structure, "prepare-xwindow-id"))
+ gstGWorld->setWindowOverlay(message);
+ return TRUE;
+}
+
+PassRefPtr<GStreamerGWorld> GStreamerGWorld::createGWorld(GstElement* pipeline)
+{
+ return adoptRef(new GStreamerGWorld(pipeline));
+}
+
+GStreamerGWorld::GStreamerGWorld(GstElement* pipeline)
+ : m_pipeline(pipeline)
+ , m_dynamicPadName(0)
+{
+ // XOverlay messages need to be handled synchronously.
+ GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
+ gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, this);
+ g_signal_connect(bus, "sync-message::element", G_CALLBACK(gstGWorldSyncMessageCallback), this);
+ gst_object_unref(bus);
+}
+
+GStreamerGWorld::~GStreamerGWorld()
+{
+ exitFullscreen();
+
+ m_pipeline = 0;
+}
+
+bool GStreamerGWorld::enterFullscreen()
+{
+ if (m_dynamicPadName)
+ return false;
+
+ if (!m_videoWindow)
+ m_videoWindow = PlatformVideoWindow::createWindow();
+
+ GstElement* platformVideoSink = gst_element_factory_make("autovideosink", "platformVideoSink");
+ GstElement* colorspace = gst_element_factory_make("ffmpegcolorspace", "colorspace");
+ GstElement* queue = gst_element_factory_make("queue", "queue");
+ GstElement* videoScale = gst_element_factory_make("videoscale", "videoScale");
+
+ // Get video sink bin and the tee inside.
+ GOwnPtr<GstElement> videoSink;
+ g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL);
+ GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee");
+ GstElement* valve = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoValve");
+
+ g_object_set(valve, "drop-probability", 1.0, NULL);
+
+ // Add and link a queue, ffmpegcolorspace, videoscale and sink in the bin.
+ gst_bin_add_many(GST_BIN(videoSink.get()), platformVideoSink, videoScale, colorspace, queue, NULL);
+#if GST_CHECK_VERSION(0, 10, 30)
+ // Faster elements linking, if possible.
+ gst_element_link_pads_full(queue, "src", colorspace, "sink", GST_PAD_LINK_CHECK_NOTHING);
+ gst_element_link_pads_full(colorspace, "src", videoScale, "sink", GST_PAD_LINK_CHECK_NOTHING);
+ gst_element_link_pads_full(videoScale, "src", platformVideoSink, "sink", GST_PAD_LINK_CHECK_NOTHING);
+#else
+ gst_element_link_many(queue, colorspace, videoScale, platformVideoSink, NULL);
+#endif
+
+ // Link a new src pad from tee to queue.
+ GstPad* srcPad = gst_element_get_request_pad(tee, "src%d");
+ GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
+ gst_pad_link(srcPad, sinkPad);
+ gst_object_unref(GST_OBJECT(sinkPad));
+
+ m_dynamicPadName = gst_pad_get_name(srcPad);
+
+ // Roll new elements to pipeline state.
+ gst_element_sync_state_with_parent(queue);
+ gst_element_sync_state_with_parent(colorspace);
+ gst_element_sync_state_with_parent(videoScale);
+ gst_element_sync_state_with_parent(platformVideoSink);
+
+ gst_object_unref(tee);
+
+ // Query the current media segment informations and send them towards
+ // the new tee branch downstream.
+
+ GstQuery* query = gst_query_new_segment(GST_FORMAT_TIME);
+ gboolean queryResult = gst_element_query(m_pipeline, query);
+
+#if GST_CHECK_VERSION(0, 10, 30)
+ if (!queryResult) {
+ gst_query_unref(query);
+ gst_object_unref(GST_OBJECT(srcPad));
+ return true;
+ }
+#else
+ // GStreamer < 0.10.30 doesn't set the query result correctly, so
+ // just ignore it to avoid a compilation warning.
+ // See https://bugzilla.gnome.org/show_bug.cgi?id=620490.
+ (void) queryResult;
+#endif
+
+ GstFormat format;
+ gint64 position;
+ if (!gst_element_query_position(m_pipeline, &format, &position))
+ position = 0;
+
+ gdouble rate;
+ gint64 startValue, stopValue;
+ gst_query_parse_segment(query, &rate, &format, &startValue, &stopValue);
+
+ GstEvent* event = gst_event_new_new_segment(FALSE, rate, format, startValue, stopValue, position);
+ gst_pad_push_event(srcPad, event);
+
+ gst_query_unref(query);
+ gst_object_unref(GST_OBJECT(srcPad));
+ return true;
+}
+
+void GStreamerGWorld::exitFullscreen()
+{
+ if (!m_dynamicPadName)
+ return;
+
+ // Get video sink bin and the elements to remove.
+ GOwnPtr<GstElement> videoSink;
+ g_object_get(m_pipeline, "video-sink", &videoSink.outPtr(), NULL);
+ GstElement* tee = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoTee");
+ GstElement* platformVideoSink = gst_bin_get_by_name(GST_BIN(videoSink.get()), "platformVideoSink");
+ GstElement* queue = gst_bin_get_by_name(GST_BIN(videoSink.get()), "queue");
+ GstElement* colorspace = gst_bin_get_by_name(GST_BIN(videoSink.get()), "colorspace");
+ GstElement* videoScale = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoScale");
+
+ GstElement* valve = gst_bin_get_by_name(GST_BIN(videoSink.get()), "videoValve");
+
+ g_object_set(valve, "drop-probability", 0.0, NULL);
+
+ // Get pads to unlink and remove.
+ GstPad* srcPad = gst_element_get_static_pad(tee, m_dynamicPadName);
+ GstPad* sinkPad = gst_element_get_static_pad(queue, "sink");
+
+ // Unlink and release request pad.
+ gst_pad_unlink(srcPad, sinkPad);
+ gst_element_release_request_pad(tee, srcPad);
+ gst_object_unref(GST_OBJECT(srcPad));
+ gst_object_unref(GST_OBJECT(sinkPad));
+
+ // Unlink, remove and cleanup queue, ffmpegcolorspace, videoScale and sink.
+ gst_element_unlink_many(queue, colorspace, videoScale, platformVideoSink, NULL);
+ gst_bin_remove_many(GST_BIN(videoSink.get()), queue, colorspace, videoScale, platformVideoSink, NULL);
+ gst_element_set_state(queue, GST_STATE_NULL);
+ gst_element_set_state(colorspace, GST_STATE_NULL);
+ gst_element_set_state(videoScale, GST_STATE_NULL);
+ gst_element_set_state(platformVideoSink, GST_STATE_NULL);
+ gst_object_unref(queue);
+ gst_object_unref(colorspace);
+ gst_object_unref(videoScale);
+ gst_object_unref(platformVideoSink);
+
+ gst_object_unref(tee);
+ m_dynamicPadName = 0;
+}
+
+void GStreamerGWorld::setWindowOverlay(GstMessage* message)
+{
+ GstObject* sink = GST_MESSAGE_SRC(message);
+
+ if (!GST_IS_X_OVERLAY(sink))
+ return;
+
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(sink), "force-aspect-ratio"))
+ g_object_set(sink, "force-aspect-ratio", TRUE, NULL);
+
+ if (m_videoWindow) {
+ m_videoWindow->prepareForOverlay(message);
+
+// gst_x_overlay_set_window_handle was introduced in -plugins-base
+// 0.10.31, just like the macro for checking the version.
+#ifdef GST_CHECK_PLUGINS_BASE_VERSION
+ gst_x_overlay_set_window_handle(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId());
+#else
+ gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), m_videoWindow->videoWindowId());
+#endif
+ }
+}
+
+}
+#endif // USE(GSTREAMER)