WebKit Bugzilla
Attachment 356491 Details for
Bug 192359
: [WPE] GStreamer/WPE Source element
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-192359-20181204142228.patch (text/plain), 51.02 KB, created by
Philippe Normand
on 2018-12-04 06:22:30 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Philippe Normand
Created:
2018-12-04 06:22:30 PST
Size:
51.02 KB
patch
obsolete
>Subversion Revision: 238850 >diff --git a/Source/ThirdParty/ChangeLog b/Source/ThirdParty/ChangeLog >index 224f979fab305cd860b4ab8a639ef2867a4deda2..0f29c7478def7258d6557e3e010acfabc6ec39b1 100644 >--- a/Source/ThirdParty/ChangeLog >+++ b/Source/ThirdParty/ChangeLog >@@ -1,3 +1,22 @@ >+2018-12-04 Philippe Normand <pnormand@igalia.com> >+ >+ [WPE] GStreamer/WPE Source element >+ https://bugs.webkit.org/show_bug.cgi?id=192359 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The wpesrc GStreamer element is used to produce a video texture >+ representing a web page rendered off-screen by WPE. This can be >+ useful to overlay HTML on top of a standalone GStreamer >+ media-player. >+ >+ * WPE/GstWPE/CMakeLists.txt: Added. >+ * WPE/GstWPE/WPEThreadedView.cpp: Added. >+ * WPE/GstWPE/WPEThreadedView.h: Added. >+ * WPE/GstWPE/gstwpesrc.cpp: Added. >+ * WPE/GstWPE/gstwpesrc.h: Added. >+ * WPE/GstWPE/meson.build: Added. >+ > 2018-10-30 Don Olmstead <don.olmstead@sony.com> > > [PlayStation] Enable JavaScriptCore >diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt >index 54fe4a2d2bc583c39f64851dff7541ee5c74665c..29292618d22a58e7f10e96486d5af9fa3e3b9e5a 100644 >--- a/Source/CMakeLists.txt >+++ b/Source/CMakeLists.txt >@@ -52,4 +52,8 @@ if (ENABLE_WEBDRIVER) > add_subdirectory(WebDriver) > endif () > >+if ("${PORT}" STREQUAL "WPE") >+ add_subdirectory(ThirdParty/WPE/GstWPE/) >+endif () >+ > WEBKIT_INCLUDE_CONFIG_FILES_IF_EXISTS() >diff --git a/Source/ThirdParty/WPE/GstWPE/CMakeLists.txt b/Source/ThirdParty/WPE/GstWPE/CMakeLists.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..dab8ffe0b53f8bcbacae401700b1539bd54c24b6 >--- /dev/null >+++ b/Source/ThirdParty/WPE/GstWPE/CMakeLists.txt >@@ -0,0 +1,49 @@ >+# NOTE: This CMake file should only be used within WebKit's build system. To >+# build GstWPE as a standalone project please use the Meson build definitions. >+ >+include(GNUInstallDirs) >+ >+set(gstwpe_SOURCES >+ WPEThreadedView.cpp >+ gstwpesrc.cpp >+) >+ >+set(gstwpe_HEADERS >+ WPEThreadedView.h >+ gstwpesrc.h >+) >+ >+find_package(PkgConfig) >+pkg_check_modules(WPE_FDO_DEP REQUIRED wpebackend-fdo-0.1) >+ >+set(gstwpe_LIBRARIES >+ WebKit >+ ${GSTREAMER_BASE_LIBRARIES} >+ ${GSTREAMER_VIDEO_LIBRARIES} >+ ${GSTREAMER_GL_LIBRARIES} >+ ${LIBXKBCOMMON_LIBRARIES} >+ ${EGL_LIBRARIES} >+ ${WPE_FDO_DEP_LIBRARIES} >+) >+ >+set(gstwpe_INCLUDE_DIRECTORIES >+ ${GSTREAMER_BASE_INCLUDE_DIRS} >+ ${GSTREAMER_VIDEO_INCLUDE_DIRS} >+ ${GSTREAMER_GL_INCLUDE_DIRS} >+ ${LIBXKBCOMMON_INCLUDE_DIRS} >+ ${EGL_INCLUDE_DIRS} >+ ${WPE_FDO_DEP_INCLUDE_DIRS} >+) >+ >+ >+if (DEVELOPER_MODE) >+ add_definitions(-DWEBKIT_INJECTED_BUNDLE_PATH="${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") >+endif () >+ >+add_library(gstwpe SHARED ${gstwpe_SOURCES} ${gstwpe_HEADERS}) >+WEBKIT_ADD_TARGET_C_FLAGS(gstwpe -Wno-unused-parameter -Wno-missing-field-initializers) >+set_property(TARGET gstwpe PROPERTY OUTPUT_NAME gstwpe) >+target_link_libraries(gstwpe ${gstwpe_LIBRARIES}) >+target_include_directories(gstwpe SYSTEM PRIVATE ${gstwpe_INCLUDE_DIRECTORIES}) >+install(TARGETS gstwpe DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/gstreamer-1.0/") >+ >diff --git a/Source/ThirdParty/WPE/GstWPE/WPEThreadedView.cpp b/Source/ThirdParty/WPE/GstWPE/WPEThreadedView.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..7b69544253288755609a499ff72a08e0127b25e9 >--- /dev/null >+++ b/Source/ThirdParty/WPE/GstWPE/WPEThreadedView.cpp >@@ -0,0 +1,409 @@ >+/* Copyright (C) <2018> Philippe Normand <philn@igalia.com> >+ * Copyright (C) <2018> Žan Doberšek <zdobersek@igalia.com> >+ * >+ * 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; if not, write to the >+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#include "WPEThreadedView.h" >+ >+#include <cstdio> >+#include <mutex> >+ >+GST_DEBUG_CATEGORY_EXTERN(wpe_src_debug); >+ >+WPEThreadedView::WPEThreadedView() >+{ >+ g_mutex_init(&threading.mutex); >+ g_cond_init(&threading.cond); >+ g_mutex_init(&threading.ready_mutex); >+ g_cond_init(&threading.ready_cond); >+ >+ g_mutex_init(&images.mutex); >+ >+ g_mutex_lock(&threading.mutex); >+ threading.thread = g_thread_new("WPEThreadedView", >+ s_viewThread, this); >+ g_cond_wait(&threading.cond, &threading.mutex); >+ g_mutex_unlock(&threading.mutex); >+ GST_DEBUG("thread spawned"); >+} >+ >+WPEThreadedView::~WPEThreadedView() >+{ >+ g_mutex_lock(&images.mutex); >+ if (images.pending) { >+ gst_egl_image_unref(images.pending); >+ images.pending = nullptr; >+ } >+ if (images.committed) { >+ gst_egl_image_unref(images.committed); >+ images.committed = nullptr; >+ } >+ g_mutex_unlock(&images.mutex); >+ >+ if (gst.display) { >+ gst_object_unref(gst.display); >+ gst.display = nullptr; >+ } >+ >+ if (gst.context) { >+ gst_object_unref(gst.context); >+ gst.context = nullptr; >+ } >+ >+ if (threading.thread) { >+ g_thread_unref(threading.thread); >+ threading.thread = nullptr; >+ } >+} >+ >+gpointer WPEThreadedView::s_viewThread(gpointer data) >+{ >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ >+ view.glib.context = g_main_context_new(); >+ view.glib.loop = g_main_loop_new(view.glib.context, FALSE); >+ >+ g_main_context_push_thread_default(view.glib.context); >+ >+ { >+ GSource* source = g_idle_source_new(); >+ g_source_set_callback(source, >+ [](gpointer data) -> gboolean { >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ g_mutex_lock(&view.threading.mutex); >+ g_cond_signal(&view.threading.cond); >+ g_mutex_unlock(&view.threading.mutex); >+ return G_SOURCE_REMOVE; >+ }, >+ &view, nullptr); >+ g_source_attach(source, view.glib.context); >+ g_source_unref(source); >+ } >+ >+ g_main_loop_run(view.glib.loop); >+ >+ g_main_loop_unref(view.glib.loop); >+ view.glib.loop = nullptr; >+ >+ if (view.webkit.view) { >+ g_object_unref(view.webkit.view); >+ view.webkit.view = nullptr; >+ } >+ if (view.webkit.uri) { >+ g_free(view.webkit.uri); >+ view.webkit.uri = nullptr; >+ } >+ >+ g_main_context_pop_thread_default(view.glib.context); >+ g_main_context_unref(view.glib.context); >+ view.glib.context = nullptr; >+ return nullptr; >+} >+ >+struct wpe_view_backend* WPEThreadedView::backend() const >+{ >+ return wpe.exportable ? wpe_view_backend_exportable_fdo_get_view_backend(wpe.exportable) : nullptr; >+} >+ >+void WPEThreadedView::s_loadEvent(WebKitWebView*, WebKitLoadEvent event, gpointer data) >+{ >+ if (event == WEBKIT_LOAD_COMMITTED) { >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ g_mutex_lock(&view.threading.ready_mutex); >+ g_cond_signal(&view.threading.ready_cond); >+ g_mutex_unlock(&view.threading.ready_mutex); >+ } >+} >+ >+void WPEThreadedView::initialize(GstWpeSrc* src, GstGLContext* context, GstGLDisplay* display, int width, int height) >+{ >+ GST_DEBUG("context %p display %p, size (%d,%d)", context, display, width, height); >+ >+ static std::once_flag s_loaderFlag; >+ std::call_once(s_loaderFlag, >+ [] { >+#if defined(WPE_BACKEND_CHECK_VERSION) && WPE_BACKEND_CHECK_VERSION(0, 2, 0) >+ wpe_loader_init("libWPEBackend-fdo-0.1.so"); >+#endif >+ }); >+ >+ struct InitializeContext { >+ GstWpeSrc* src; >+ WPEThreadedView& view; >+ GstGLContext* context; >+ GstGLDisplay* display; >+ int width; >+ int height; >+ } initializeContext { src, *this, context, display, width, height }; >+ >+ GSource* source = g_idle_source_new(); >+ g_source_set_callback(source, >+ [](gpointer data) -> gboolean { >+ GST_DEBUG("on view thread"); >+ auto& initializeContext = *static_cast<InitializeContext*>(data); >+ auto& view = initializeContext.view; >+ >+ g_mutex_lock(&view.threading.mutex); >+ >+ view.gst.context = GST_GL_CONTEXT(gst_object_ref(initializeContext.context)); >+ view.gst.display = GST_GL_DISPLAY(gst_object_ref(initializeContext.display)); >+ >+ view.wpe.width = initializeContext.width; >+ view.wpe.height = initializeContext.height; >+ >+ EGLDisplay eglDisplay = gst_gl_display_egl_get_from_native( >+ GST_GL_DISPLAY_TYPE_WAYLAND, >+ gst_gl_display_get_handle(initializeContext.display)); >+ GST_DEBUG("eglDisplay %p", eglDisplay); >+ wpe_fdo_initialize_for_egl_display(eglDisplay); >+ >+ view.wpe.exportable = wpe_view_backend_exportable_fdo_egl_create(&s_exportableClient, >+ &view, view.wpe.width, view.wpe.height); >+ auto* viewBackend = webkit_web_view_backend_new( >+ wpe_view_backend_exportable_fdo_get_view_backend(view.wpe.exportable), nullptr, nullptr); >+ >+ view.webkit.view = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, >+ "backend", viewBackend, nullptr)); >+ >+ gst_wpe_src_configure_web_view(initializeContext.src, view.webkit.view); >+ >+ g_signal_connect(view.webkit.view, "load-changed", G_CALLBACK(s_loadEvent), &view); >+ >+ const gchar* location; >+ gboolean drawBackground = TRUE; >+ g_object_get(initializeContext.src, "location", &location, "draw-background", &drawBackground, nullptr); >+ if (!location) >+ g_warning("Invalid location"); >+ else { >+ view.setDrawBackground(drawBackground); >+ view.loadUriUnlocked(location); >+ } >+ g_cond_signal(&view.threading.cond); >+ g_mutex_unlock(&view.threading.mutex); >+ return G_SOURCE_REMOVE; >+ }, >+ &initializeContext, nullptr); >+ g_source_set_priority(source, -70); >+ >+ g_mutex_lock(&threading.mutex); >+ g_source_attach(source, glib.context); >+ g_cond_wait(&threading.cond, &threading.mutex); >+ g_mutex_unlock(&threading.mutex); >+ >+ g_source_unref(source); >+ >+ GST_DEBUG("waiting load to finish"); >+ g_mutex_lock(&threading.ready_mutex); >+ g_cond_wait(&threading.ready_cond, &threading.ready_mutex); >+ g_mutex_unlock(&threading.ready_mutex); >+ GST_DEBUG("done"); >+} >+ >+GstEGLImage* WPEThreadedView::image() >+{ >+ GstEGLImage* ret = nullptr; >+ >+ g_mutex_lock(&images.mutex); >+ GST_DEBUG("pending %p committed %p", images.pending, images.committed); >+ >+ if (images.pending) { >+ auto* previousImage = images.committed; >+ images.committed = images.pending; >+ images.pending = nullptr; >+ >+ frameComplete(); >+ >+ if (previousImage) >+ gst_egl_image_unref(previousImage); >+ } >+ >+ if (images.committed) >+ ret = images.committed; >+ >+ g_mutex_unlock(&images.mutex); >+ return ret; >+} >+ >+void WPEThreadedView::resize(int width, int height) >+{ >+ GST_DEBUG("resize"); >+ >+ GSource* source = g_idle_source_new(); >+ g_source_set_callback(source, >+ [](gpointer data) -> gboolean { >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ >+ g_mutex_lock(&view.threading.mutex); >+ >+ GST_DEBUG("dispatching"); >+ if (view.wpe.exportable && wpe_view_backend_exportable_fdo_get_view_backend(view.wpe.exportable)) >+ wpe_view_backend_dispatch_set_size(wpe_view_backend_exportable_fdo_get_view_backend(view.wpe.exportable), view.wpe.width, view.wpe.height); >+ >+ g_cond_signal(&view.threading.cond); >+ g_mutex_unlock(&view.threading.mutex); >+ return G_SOURCE_REMOVE; >+ }, >+ this, nullptr); >+ g_source_set_priority(source, -70); >+ >+ g_mutex_lock(&threading.mutex); >+ g_source_attach(source, glib.context); >+ g_cond_wait(&threading.cond, &threading.mutex); >+ g_mutex_unlock(&threading.mutex); >+ >+ g_source_unref(source); >+} >+ >+void WPEThreadedView::frameComplete() >+{ >+ GST_DEBUG("frame complete"); >+ >+ GSource* source = g_idle_source_new(); >+ g_source_set_callback(source, >+ [](gpointer data) -> gboolean { >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ >+ g_mutex_lock(&view.threading.mutex); >+ >+ GST_DEBUG("dispatching"); >+ wpe_view_backend_exportable_fdo_dispatch_frame_complete(view.wpe.exportable); >+ >+ g_cond_signal(&view.threading.cond); >+ g_mutex_unlock(&view.threading.mutex); >+ return G_SOURCE_REMOVE; >+ }, >+ this, nullptr); >+ g_source_set_priority(source, -70); >+ >+ g_mutex_lock(&threading.mutex); >+ g_source_attach(source, glib.context); >+ g_cond_wait(&threading.cond, &threading.mutex); >+ g_mutex_unlock(&threading.mutex); >+ >+ g_source_unref(source); >+} >+ >+void WPEThreadedView::loadUriUnlocked(const gchar* uri) >+{ >+ if (webkit.uri) >+ g_free(webkit.uri); >+ webkit.uri = g_strdup(uri); >+ webkit_web_view_load_uri(webkit.view, webkit.uri); >+} >+ >+void WPEThreadedView::loadUri(const gchar* uri) >+{ >+ GST_DEBUG("loading %s", uri); >+ >+ struct UriContext { >+ WPEThreadedView& view; >+ const gchar* uri; >+ } uriContext { *this, uri }; >+ >+ GSource* source = g_idle_source_new(); >+ g_source_set_callback(source, >+ [](gpointer data) -> gboolean { >+ GST_DEBUG("on view thread"); >+ auto& uriContext = *static_cast<UriContext*>(data); >+ auto& view = uriContext.view; >+ >+ g_mutex_lock(&view.threading.mutex); >+ >+ view.loadUriUnlocked(uriContext.uri); >+ >+ g_cond_signal(&view.threading.cond); >+ g_mutex_unlock(&view.threading.mutex); >+ return G_SOURCE_REMOVE; >+ }, >+ &uriContext, nullptr); >+ g_source_set_priority(source, -70); >+ >+ g_mutex_lock(&threading.mutex); >+ g_source_attach(source, glib.context); >+ g_cond_wait(&threading.cond, &threading.mutex); >+ g_mutex_unlock(&threading.mutex); >+ >+ GST_DEBUG("done"); >+ g_source_unref(source); >+} >+ >+void WPEThreadedView::setDrawBackground(gboolean drawsBackground) >+{ >+#if 1 >+ // See https://bugs.webkit.org/show_bug.cgi?id=192305 >+ g_warning("set_draws_background API not upstream yet"); >+#else >+ webkit_web_view_set_draws_background(webkit.view, drawsBackground); >+#endif >+} >+ >+void WPEThreadedView::releaseImage(EGLImageKHR image) >+{ >+ struct ReleaseImageContext { >+ WPEThreadedView& view; >+ EGLImageKHR image; >+ } releaseImageContext { *this, image }; >+ >+ GSource* source = g_idle_source_new(); >+ g_source_set_callback(source, >+ [](gpointer data) -> gboolean { >+ auto& releaseImageContext = *static_cast<ReleaseImageContext*>(data); >+ auto& view = releaseImageContext.view; >+ >+ g_mutex_lock(&view.threading.mutex); >+ >+ wpe_view_backend_exportable_fdo_egl_dispatch_release_image( >+ releaseImageContext.view.wpe.exportable, releaseImageContext.image); >+ >+ g_cond_signal(&view.threading.cond); >+ g_mutex_unlock(&view.threading.mutex); >+ return G_SOURCE_REMOVE; >+ }, >+ &releaseImageContext, nullptr); >+ g_source_set_priority(source, -70); >+ >+ g_mutex_lock(&threading.mutex); >+ g_source_attach(source, glib.context); >+ g_cond_wait(&threading.cond, &threading.mutex); >+ g_mutex_unlock(&threading.mutex); >+ >+ g_source_unref(source); >+} >+ >+struct wpe_view_backend_exportable_fdo_egl_client WPEThreadedView::s_exportableClient = { >+ // export_buffer_resource >+ [](void* data, EGLImageKHR image) { >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ auto* gstImage = gst_egl_image_new_wrapped(view.gst.context, image, >+ GST_GL_RGBA, &view, s_releaseImage); >+ >+ GST_DEBUG("image %p, gstImage %" GST_PTR_FORMAT, image, gstImage); >+ >+ g_mutex_lock(&view.images.mutex); >+ view.images.pending = gstImage; >+ g_mutex_unlock(&view.images.mutex); >+ }, >+ // padding >+ nullptr, nullptr, nullptr, nullptr >+}; >+ >+void WPEThreadedView::s_releaseImage(GstEGLImage* image, gpointer data) >+{ >+ auto& view = *static_cast<WPEThreadedView*>(data); >+ GST_DEBUG("view %p image %" GST_PTR_FORMAT, &view, image); >+ view.releaseImage(gst_egl_image_get_image(image)); >+} >diff --git a/Source/ThirdParty/WPE/GstWPE/WPEThreadedView.h b/Source/ThirdParty/WPE/GstWPE/WPEThreadedView.h >new file mode 100644 >index 0000000000000000000000000000000000000000..7a20ff0147557460aa2306d669545d505e54068d >--- /dev/null >+++ b/Source/ThirdParty/WPE/GstWPE/WPEThreadedView.h >@@ -0,0 +1,92 @@ >+/* Copyright (C) <2018> Philippe Normand <philn@igalia.com> >+ * Copyright (C) <2018> Žan Doberšek <zdobersek@igalia.com> >+ * >+ * 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; if not, write to the >+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#pragma once >+ >+#include <EGL/egl.h> >+#include <glib.h> >+#include <gst/gl/gl.h> >+#include <gst/gl/gstglfuncs.h> >+#include <gst/gl/egl/gsteglimage.h> >+#include <gst/gl/egl/gstgldisplay_egl.h> >+#include <wpe/fdo.h> >+#include <wpe/fdo-egl.h> >+#include <wpe/webkit.h> >+#include "gstwpesrc.h" >+ >+class WPEThreadedView { >+public: >+ WPEThreadedView(); >+ ~WPEThreadedView(); >+ >+ void initialize(GstWpeSrc*, GstGLContext*, GstGLDisplay*, int width, int height); >+ >+ void resize(int width, int height); >+ void loadUri(const gchar*); >+ void setDrawBackground(gboolean); >+ >+ GstEGLImage* image(); >+ >+ struct wpe_view_backend* backend() const; >+ >+private: >+ void frameComplete(); >+ void releaseImage(EGLImageKHR); >+ void loadUriUnlocked(const gchar*); >+ >+ static void s_loadEvent(WebKitWebView*, WebKitLoadEvent, gpointer); >+ >+ static gpointer s_viewThread(gpointer); >+ struct { >+ GMutex mutex; >+ GCond cond; >+ GMutex ready_mutex; >+ GCond ready_cond; >+ GThread* thread; >+ } threading; >+ >+ struct { >+ GMainContext* context; >+ GMainLoop* loop; >+ } glib; >+ >+ struct { >+ GstGLContext* context; >+ GstGLDisplay* display; >+ } gst; >+ >+ static struct wpe_view_backend_exportable_fdo_egl_client s_exportableClient; >+ static void s_releaseImage(GstEGLImage*, gpointer); >+ struct { >+ struct wpe_view_backend_exportable_fdo* exportable; >+ int width; >+ int height; >+ } wpe { nullptr, 0, 0 }; >+ >+ struct { >+ gchar* uri; >+ WebKitWebView* view; >+ } webkit = { nullptr, nullptr }; >+ >+ struct { >+ GMutex mutex; >+ GstEGLImage* pending { nullptr }; >+ GstEGLImage* committed { nullptr }; >+ } images; >+}; >diff --git a/Source/ThirdParty/WPE/GstWPE/gstwpesrc.cpp b/Source/ThirdParty/WPE/GstWPE/gstwpesrc.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..1d055a653f1c2af11f95354df7fe71558b46cbb8 >--- /dev/null >+++ b/Source/ThirdParty/WPE/GstWPE/gstwpesrc.cpp >@@ -0,0 +1,835 @@ >+/* Copyright (C) <2018> Philippe Normand <philn@igalia.com> >+ * Copyright (C) <2018> Žan Doberšek <zdobersek@igalia.com> >+ * >+ * 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; if not, write to the >+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+/** >+ * SECTION:element-wpesrc >+ * @title: wpesrc >+ * >+ * The wpe element is used to produce a video texture representing a web page >+ * rendered off-screen by WPE. >+ * >+ * ## Example launch line >+ * >+ * |[ >+ * gst-launch-1.0 -v wpesrc location="https://gstreamer.freedesktop.org" ! glimagesink >+ * ]| >+ * Shows the GStreamer website homepage >+ * >+ * |[ >+ * gst-play-1.0 --videosink gtkglsink wpe://https://gstreamer.freedesktop.org >+ * ]| >+ * Shows the GStreamer website homepage as played with GstPlayer in a GTK+ window. >+ * >+ * |[ >+ * gst-launch-1.0 glvideomixer name=m sink_1::zorder=0 ! glimagesink wpesrc location="file:///home/phil/Downloads/plunk/index.html" draws-background=0 ! m. videotestsrc ! queue ! glupload ! glcolorconvert ! m. >+ * ]| >+ * Composite WPE with a video stream in a single OpenGL scene. >+ * >+ * |[ >+ * gst-launch-1.0 glvideomixer name=m sink_1::zorder=0 sink_0::height=818 sink_0::width=1920 ! gtkglsink wpesrc location="file:///home/phil/Downloads/plunk/index.html" draws-background=0 ! m. uridecodebin uri="http://192.168.1.44/Sintel.2010.1080p.mkv" name=d d. ! queue ! glupload ! glcolorconvert ! m. >+ * ]| >+ * Composite WPE with a video stream, sink_0 pad properties have to match the video dimensions. >+ */ >+ >+/* >+ * TODO: >+ * - Audio support (requires an AudioSession implementation in WebKit and a WPEBackend-fdo API for it) >+ * - DMABuf support (requires changes in WPEBackend-fdo to expose DMABuf planes and fds) >+ * - Custom EGLMemory allocator >+ * - Better navigation events handling (would require a new GstNavigation API) >+ */ >+ >+#include "gstwpesrc.h" >+#include <gst/video/video.h> >+#include <gst/gl/gl.h> >+#include <gst/gl/egl/gstglmemoryegl.h> >+#include <xkbcommon/xkbcommon.h> >+ >+#include "WPEThreadedView.h" >+ >+GST_DEBUG_CATEGORY_STATIC (wpe_src_debug); >+#define GST_CAT_DEFAULT wpe_src_debug >+ >+#define DEFAULT_WIDTH 1920 >+#define DEFAULT_HEIGHT 1080 >+#define DEFAULT_FPS_N 30 >+#define DEFAULT_FPS_D 1 >+ >+#define SUPPORTED_GL_APIS static_cast<GstGLAPI>(GST_GL_API_OPENGL | GST_GL_API_OPENGL3 | GST_GL_API_GLES2) >+ >+enum >+{ >+ PROP_0, >+ PROP_LOCATION, >+ PROP_DRAW_BACKGROUND >+}; >+ >+enum >+{ >+ SIGNAL_CONFIGURE_WEB_VIEW, >+ LAST_SIGNAL >+}; >+static guint gst_wpe_src_signals[LAST_SIGNAL] = { 0 }; >+ >+struct _GstWpeSrc >+{ >+ GstPushSrc parent; >+ GstGLDisplay *display; >+ GstGLContext *context, *other_context; >+ GstVideoInfo out_info; >+ GstCaps *out_caps; >+ GstGLVideoAllocationParams *gl_alloc_params; >+ GstClockTime running_time; /* total running time */ >+ guint64 n_frames; >+ gchar *location; >+ gboolean draw_background; >+ gboolean negotiated; >+ WPEThreadedView *view; >+}; >+ >+static void gst_wpe_src_uri_handler_init (gpointer iface, gpointer data); >+ >+#define gst_wpe_src_parent_class parent_class >+G_DEFINE_TYPE_WITH_CODE (GstWpeSrc, gst_wpe_src, GST_TYPE_PUSH_SRC, >+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_wpe_src_uri_handler_init)); >+ >+/* *INDENT-OFF* */ >+static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", >+ GST_PAD_SRC, >+ GST_PAD_ALWAYS, >+ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, "RGBA")) >+ ); >+/* *INDENT-ON* */ >+ >+static GstFlowReturn >+gst_wpe_src_fill (GstPushSrc * psrc, GstBuffer * buffer) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (psrc); >+ GstClockTime next_time; >+ GstGLSyncMeta *sync_meta; >+ GstEGLImage *img; >+ // FIXME: Implement a WPE GstGLMemory allocator. >+ GstGLVideoAllocationParams *params = src->gl_alloc_params; >+ GstGLMemoryAllocator *allocator; >+ GstGLMemory *gl_mem; >+ GstGLBaseMemoryAllocator *base_allocator; >+ >+ if (G_UNLIKELY (!src->negotiated || !src->context)) >+ goto not_negotiated; >+ >+ img = src->view->image (); >+ g_return_val_if_fail (img != NULL, GST_FLOW_ERROR); >+ >+ allocator = GST_GL_MEMORY_ALLOCATOR (gst_allocator_find >+ (GST_GL_MEMORY_EGL_ALLOCATOR_NAME)); >+ base_allocator = GST_GL_BASE_MEMORY_ALLOCATOR (allocator); >+ >+ params->parent.gl_handle = img; >+ params->plane = 0; >+ gl_mem = >+ (GstGLMemory *) gst_gl_base_memory_alloc (base_allocator, >+ (GstGLAllocationParams *) params); >+ gst_buffer_replace_memory (buffer, 0, (GstMemory *) gl_mem); >+ gst_buffer_add_video_meta_full (buffer, (GstVideoFrameFlags) 0, >+ GST_VIDEO_INFO_FORMAT (params->v_info), >+ GST_VIDEO_INFO_WIDTH (params->v_info), >+ GST_VIDEO_INFO_HEIGHT (params->v_info), 1, params->v_info->offset, >+ params->v_info->stride); >+ gst_object_unref (allocator); >+ >+ sync_meta = gst_buffer_get_gl_sync_meta (buffer); >+ if (sync_meta) >+ gst_gl_sync_meta_set_sync_point (sync_meta, src->context); >+ >+ GST_BUFFER_PTS (buffer) = src->running_time; >+ GST_BUFFER_OFFSET (buffer) = src->n_frames; >+ src->n_frames++; >+ GST_BUFFER_OFFSET_END (buffer) = src->n_frames; >+ if (src->out_info.fps_n) { >+ next_time = gst_util_uint64_scale_int (src->n_frames * GST_SECOND, >+ src->out_info.fps_d, src->out_info.fps_n); >+ GST_BUFFER_DURATION (buffer) = next_time - src->running_time; >+ src->running_time = next_time; >+ } else { >+ GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; >+ } >+ >+ return GST_FLOW_OK; >+ >+not_negotiated: >+ { >+ GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), >+ ("format wasn't negotiated before get function")); >+ return GST_FLOW_NOT_NEGOTIATED; >+ } >+} >+ >+static gboolean >+gst_wpe_src_start (GstBaseSrc * base_src) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (base_src); >+ >+ GST_INFO_OBJECT (src, "Starting up"); >+ GST_OBJECT_LOCK (src); >+ >+ src->running_time = 0; >+ src->n_frames = 0; >+ src->negotiated = FALSE; >+ src->gl_alloc_params = NULL; >+ src->view = new WPEThreadedView; >+ >+ GST_OBJECT_UNLOCK (src); >+ return TRUE; >+} >+ >+static gboolean >+gst_wpe_src_stop (GstBaseSrc * base_src) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (base_src); >+ >+ GST_INFO_OBJECT (src, "Stopping"); >+ GST_OBJECT_LOCK (src); >+ >+ if (src->gl_alloc_params) { >+ gst_gl_allocation_params_free ((GstGLAllocationParams *) >+ src->gl_alloc_params); >+ src->gl_alloc_params = NULL; >+ } >+ >+ gst_caps_replace (&src->out_caps, NULL); >+ >+ if (src->context) >+ g_clear_object (&src->context); >+ src->context = NULL; >+ >+ delete src->view; >+ src->view = NULL; >+ >+ GST_OBJECT_UNLOCK (src); >+ return TRUE; >+} >+ >+static void >+gst_wpe_src_get_times (GstBaseSrc * base_src, GstBuffer * buffer, >+ GstClockTime * start, GstClockTime * end) >+{ >+ GstClockTime timestamp = GST_BUFFER_PTS (buffer); >+ GstClockTime duration = GST_BUFFER_DURATION (buffer); >+ >+ *end = timestamp + duration; >+ *start = timestamp; >+ >+ GST_LOG_OBJECT (base_src, >+ "Got times start: %" GST_TIME_FORMAT " end: %" GST_TIME_FORMAT, >+ GST_TIME_ARGS (*start), GST_TIME_ARGS (*end)); >+} >+ >+static gboolean >+gst_wpe_src_query (GstBaseSrc * base_src, GstQuery * query) >+{ >+ gboolean res = FALSE; >+ GstWpeSrc *src = GST_WPE_SRC (base_src); >+ >+ switch (GST_QUERY_TYPE (query)) { >+ case GST_QUERY_LATENCY: >+ { >+ GstClockTime latency; >+ >+ if (src->out_info.fps_n) { >+ latency = >+ gst_util_uint64_scale (GST_SECOND, src->out_info.fps_d, >+ src->out_info.fps_n); >+ GST_DEBUG_OBJECT (src, "Reporting latency: %" GST_TIME_FORMAT, >+ GST_TIME_ARGS (latency)); >+ gst_query_set_latency (query, TRUE, latency, GST_CLOCK_TIME_NONE); >+ } >+ res = TRUE; >+ break; >+ } >+ case GST_QUERY_CONTEXT: >+ { >+ if (gst_gl_handle_context_query ((GstElement *) src, query, >+ src->display, src->context, src->other_context)) { >+ >+ return TRUE; >+ } >+ break; >+ } >+ case GST_QUERY_CONVERT: >+ { >+ GstFormat src_fmt, dest_fmt; >+ gint64 src_val, dest_val; >+ >+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val); >+ res = >+ gst_video_info_convert (&src->out_info, src_fmt, src_val, dest_fmt, >+ &dest_val); >+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val); >+ >+ return res; >+ } >+ >+ default: >+ res = GST_BASE_SRC_CLASS (parent_class)->query (base_src, query); >+ break; >+ } >+ >+ return res; >+} >+ >+static GstCaps * >+gst_wpe_src_fixate (GstBaseSrc * base_src, GstCaps * caps) >+{ >+ GstStructure *structure; >+ >+ caps = gst_caps_make_writable (caps); >+ structure = gst_caps_get_structure (caps, 0); >+ >+ gst_structure_fixate_field_nearest_int (structure, "width", DEFAULT_WIDTH); >+ gst_structure_fixate_field_nearest_int (structure, "height", DEFAULT_HEIGHT); >+ >+ if (gst_structure_has_field (structure, "framerate")) >+ gst_structure_fixate_field_nearest_fraction (structure, "framerate", >+ DEFAULT_FPS_N, DEFAULT_FPS_D); >+ else >+ gst_structure_set (structure, "framerate", GST_TYPE_FRACTION, DEFAULT_FPS_N, >+ DEFAULT_FPS_D, NULL); >+ >+ caps = GST_BASE_SRC_CLASS (parent_class)->fixate (base_src, caps); >+ GST_INFO_OBJECT (base_src, "Fixated caps to %" GST_PTR_FORMAT, caps); >+ return caps; >+} >+ >+static gboolean >+gst_wpe_src_set_caps (GstBaseSrc * base_src, GstCaps * caps) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (base_src); >+ >+ GST_INFO_OBJECT (base_src, "Caps set to %" GST_PTR_FORMAT, caps); >+ if (!gst_video_info_from_caps (&src->out_info, caps)) >+ goto wrong_caps; >+ >+ if (src->view) { >+ src->view->resize (GST_VIDEO_INFO_WIDTH (&src->out_info), >+ GST_VIDEO_INFO_HEIGHT (&src->out_info)); >+ } >+ >+ src->negotiated = TRUE; >+ gst_caps_replace (&src->out_caps, caps); >+ return TRUE; >+ >+wrong_caps: >+ { >+ GST_WARNING ("wrong caps"); >+ return FALSE; >+ } >+} >+ >+static void >+gst_wpe_src_set_context (GstElement * element, GstContext * context) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (element); >+ >+ gst_gl_handle_set_context (element, context, &src->display, >+ &src->other_context); >+ >+ if (src->display) >+ gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); >+ >+ GST_ELEMENT_CLASS (parent_class)->set_context (element, context); >+} >+ >+static gboolean >+_find_local_gl_context (GstWpeSrc * src) >+{ >+ if (gst_gl_query_local_gl_context (GST_ELEMENT (src), GST_PAD_SRC, >+ &src->context)) >+ return TRUE; >+ return FALSE; >+} >+ >+static void >+_src_initialize_wpe_view (GstGLContext * context, GstWpeSrc * src) >+{ >+ src->view->initialize (src, context, src->display, >+ GST_VIDEO_INFO_WIDTH (&src->out_info), >+ GST_VIDEO_INFO_HEIGHT (&src->out_info)); >+} >+ >+void >+gst_wpe_src_configure_web_view (GstWpeSrc * src, WebKitWebView * webview) >+{ >+ GValue args[2] = { {0}, {0} }; >+ >+ g_value_init (&args[0], GST_TYPE_ELEMENT); >+ g_value_set_object (&args[0], src); >+ g_value_init (&args[1], G_TYPE_OBJECT); >+ g_value_set_object (&args[1], webview); >+ >+ g_signal_emitv (args, gst_wpe_src_signals[SIGNAL_CONFIGURE_WEB_VIEW], 0, >+ NULL); >+ >+ g_value_unset (&args[0]); >+ g_value_unset (&args[1]); >+} >+ >+static gboolean >+gst_wpe_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (basesrc); >+ GstBufferPool *pool = NULL; >+ GstStructure *config; >+ GstCaps *caps; >+ guint min, max, size; >+ gboolean update_pool; >+ GError *error = NULL; >+ GstGLMemoryAllocator *allocator; >+ GstAllocationParams *alloc_params = NULL; >+ guint plane = 1; >+ GstVideoAlignment *valign = NULL; >+ GstGLTextureTarget target = GST_GL_TEXTURE_TARGET_2D; >+ GstGLFormat tex_format = GST_GL_RGBA; >+ >+ if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context)) >+ return FALSE; >+ >+ gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); >+ >+ _find_local_gl_context (src); >+ >+ if (!src->context) { >+ GST_OBJECT_LOCK (src->display); >+ do { >+ if (src->context) { >+ gst_object_unref (src->context); >+ src->context = NULL; >+ } >+ >+ src->context = >+ gst_gl_display_get_gl_context_for_thread (src->display, NULL); >+ if (!src->context) { >+ if (!gst_gl_display_create_context (src->display, src->other_context, >+ &src->context, &error)) { >+ GST_OBJECT_UNLOCK (src->display); >+ goto context_error; >+ } >+ } >+ } while (!gst_gl_display_add_context (src->display, src->context)); >+ GST_OBJECT_UNLOCK (src->display); >+ } >+ >+ if ((gst_gl_context_get_gl_api (src->context) & SUPPORTED_GL_APIS) == 0) >+ goto unsupported_gl_api; >+ >+ gst_gl_context_thread_add (src->context, >+ (GstGLContextThreadFunc) _src_initialize_wpe_view, src); >+ >+ gst_query_parse_allocation (query, &caps, NULL); >+ >+ if (gst_query_get_n_allocation_pools (query) > 0) { >+ gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); >+ update_pool = TRUE; >+ } else { >+ GstVideoInfo vinfo; >+ >+ gst_video_info_init (&vinfo); >+ gst_video_info_from_caps (&vinfo, caps); >+ size = vinfo.size; >+ min = max = 1; >+ update_pool = FALSE; >+ } >+ >+ if (!pool || !GST_IS_GL_BUFFER_POOL (pool)) { >+ /* can't use this pool */ >+ if (pool) >+ gst_object_unref (pool); >+ pool = gst_gl_buffer_pool_new (src->context); >+ } >+ config = gst_buffer_pool_get_config (pool); >+ >+ gst_buffer_pool_config_set_params (config, caps, size, min, max); >+ gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); >+ if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL)) >+ gst_buffer_pool_config_add_option (config, >+ GST_BUFFER_POOL_OPTION_GL_SYNC_META); >+ >+ allocator = >+ GST_GL_MEMORY_ALLOCATOR (gst_allocator_find >+ (GST_GL_MEMORY_EGL_ALLOCATOR_NAME)); >+ gst_buffer_pool_config_set_allocator (config, GST_ALLOCATOR_CAST (allocator), >+ NULL); >+ gst_object_unref (allocator); >+ >+ gst_buffer_pool_set_config (pool, config); >+ >+ src->gl_alloc_params = gst_gl_video_allocation_params_new_wrapped_gl_handle >+ (src->context, >+ alloc_params, >+ &src->out_info, plane, valign, target, tex_format, NULL, NULL, NULL); >+ >+ if (update_pool) >+ gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); >+ else >+ gst_query_add_allocation_pool (query, pool, size, min, max); >+ >+ gst_object_unref (pool); >+ >+ return TRUE; >+ >+unsupported_gl_api: >+ { >+ GstGLAPI gl_api = gst_gl_context_get_gl_api (src->context); >+ gchar *gl_api_str = gst_gl_api_to_string (gl_api); >+ gchar *supported_gl_api_str = gst_gl_api_to_string (SUPPORTED_GL_APIS); >+ GST_ELEMENT_ERROR (src, RESOURCE, BUSY, >+ ("GL API's not compatible context: %s supported: %s", gl_api_str, >+ supported_gl_api_str), (NULL)); >+ >+ g_free (supported_gl_api_str); >+ g_free (gl_api_str); >+ return FALSE; >+ } >+context_error: >+ { >+ if (error) { >+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message), >+ (NULL)); >+ g_clear_error (&error); >+ } else { >+ GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL)); >+ } >+ if (src->context) >+ gst_object_unref (src->context); >+ src->context = NULL; >+ return FALSE; >+ } >+} >+ >+static GstStateChangeReturn >+gst_wpe_src_change_state (GstElement * element, GstStateChange transition) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (element); >+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; >+ >+ GST_DEBUG_OBJECT (src, "changing state: %s => %s", >+ gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), >+ gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); >+ >+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); >+ if (ret == GST_STATE_CHANGE_FAILURE) >+ return ret; >+ >+ switch (transition) { >+ case GST_STATE_CHANGE_READY_TO_NULL: >+ if (src->other_context) { >+ g_clear_object (&src->other_context); >+ src->other_context = NULL; >+ } >+ >+ if (src->display) { >+ g_clear_object (&src->display); >+ src->display = NULL; >+ } >+ break; >+ default: >+ break; >+ } >+ >+ return ret; >+} >+ >+static gboolean >+gst_wpe_src_set_location (GstWpeSrc * src, const gchar * location, >+ GError ** error) >+{ >+ g_free (src->location); >+ src->location = g_strdup (location); >+ if (src->view) >+ src->view->loadUri (src->location); >+ >+ return TRUE; >+} >+ >+static void >+gst_wpe_src_set_draw_background (GstWpeSrc * src, gboolean draw_background) >+{ >+ if (src->view) >+ src->view->setDrawBackground (draw_background); >+ src->draw_background = draw_background; >+} >+ >+static void >+gst_wpe_src_set_property (GObject * object, guint prop_id, const GValue * value, >+ GParamSpec * pspec) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (object); >+ >+ switch (prop_id) { >+ case PROP_LOCATION: >+ { >+ const gchar *location; >+ >+ location = g_value_get_string (value); >+ if (location == NULL) { >+ GST_WARNING_OBJECT (src, "location property cannot be NULL"); >+ return; >+ } >+ >+ if (!gst_wpe_src_set_location (src, location, NULL)) { >+ GST_WARNING_OBJECT (src, "badly formatted location"); >+ return; >+ } >+ break; >+ } >+ case PROP_DRAW_BACKGROUND: >+ gst_wpe_src_set_draw_background (src, g_value_get_boolean (value)); >+ break; >+ default: >+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); >+ break; >+ } >+} >+ >+static void >+gst_wpe_src_get_property (GObject * object, guint prop_id, GValue * value, >+ GParamSpec * pspec) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (object); >+ >+ switch (prop_id) { >+ case PROP_LOCATION: >+ g_value_set_string (value, src->location); >+ break; >+ case PROP_DRAW_BACKGROUND: >+ g_value_set_boolean (value, src->draw_background); >+ break; >+ default: >+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); >+ break; >+ } >+} >+ >+static gboolean >+gst_wpe_src_event (GstPad * pad, GstObject * parent, GstEvent * event) >+{ >+ gboolean ret = FALSE; >+ GstWpeSrc *src = GST_WPE_SRC (parent); >+ >+ if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION) { >+ const gchar *key; >+ gint button; >+ gdouble x, y; >+ >+ GST_DEBUG_OBJECT (src, "Processing event %" GST_PTR_FORMAT, event); >+ switch (gst_navigation_event_get_type (event)) { >+ case GST_NAVIGATION_EVENT_KEY_PRESS: >+ case GST_NAVIGATION_EVENT_KEY_RELEASE: >+ if (gst_navigation_event_parse_key_event (event, &key)) { >+ /* FIXME: This is wrong... The GstNavigation API should pass >+ hardware-level informations, not high-level keysym strings */ >+ uint32_t keysym = >+ (uint32_t) xkb_keysym_from_name (key, XKB_KEYSYM_NO_FLAGS); >+ struct wpe_input_keyboard_event wpe_event; >+ wpe_event.key_code = keysym; >+ wpe_event.pressed = >+ gst_navigation_event_get_type (event) == >+ GST_NAVIGATION_EVENT_KEY_PRESS; >+ wpe_view_backend_dispatch_keyboard_event (src->view->backend (), >+ &wpe_event); >+ ret = TRUE; >+ } >+ break; >+ case GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS: >+ case GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE: >+ if (gst_navigation_event_parse_mouse_button_event (event, &button, &x, >+ &y)) { >+ struct wpe_input_pointer_event wpe_event; >+ wpe_event.type = wpe_input_pointer_event_type_button; >+ wpe_event.x = (int) x; >+ wpe_event.y = (int) y; >+ if (button == 1) { >+ wpe_event.modifiers = wpe_input_pointer_modifier_button1; >+ } else if (button == 2) { >+ wpe_event.modifiers = wpe_input_pointer_modifier_button2; >+ } else if (button == 3) { >+ wpe_event.modifiers = wpe_input_pointer_modifier_button3; >+ } else if (button == 4) { >+ wpe_event.modifiers = wpe_input_pointer_modifier_button4; >+ } else if (button == 5) { >+ wpe_event.modifiers = wpe_input_pointer_modifier_button5; >+ } >+ wpe_event.button = button; >+ wpe_event.state = 1; >+ wpe_event.state = >+ gst_navigation_event_get_type (event) == >+ GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS; >+ wpe_view_backend_dispatch_pointer_event (src->view->backend (), >+ &wpe_event); >+ ret = TRUE; >+ } >+ break; >+ case GST_NAVIGATION_EVENT_MOUSE_MOVE: >+ if (gst_navigation_event_parse_mouse_move_event (event, &x, &y)) { >+ struct wpe_input_pointer_event wpe_event; >+ wpe_event.type = wpe_input_pointer_event_type_motion; >+ wpe_event.x = (int) x; >+ wpe_event.y = (int) y; >+ wpe_view_backend_dispatch_pointer_event (src->view->backend (), >+ &wpe_event); >+ ret = TRUE; >+ } >+ break; >+ default: >+ break; >+ } >+ /* FIXME: No touch events handling support in GstNavigation */ >+ } >+ >+ if (!ret) { >+ ret = gst_pad_event_default (pad, parent, event); >+ } >+ return ret; >+} >+ >+static void >+gst_wpe_src_init (GstWpeSrc * src) >+{ >+ GstBaseSrc *base_src = GST_BASE_SRC (src); >+ GstPad *pad = gst_element_get_static_pad (GST_ELEMENT_CAST (src), "src"); >+ >+ gst_pad_set_event_function (pad, gst_wpe_src_event); >+ gst_object_unref (pad); >+ >+ src->n_frames = 0; >+ src->draw_background = TRUE; >+ >+ gst_base_src_set_format (base_src, GST_FORMAT_TIME); >+ gst_base_src_set_live (base_src, TRUE); >+} >+ >+static GstURIType >+gst_wpe_src_uri_get_type (GType) >+{ >+ return GST_URI_SRC; >+} >+ >+const gchar *const * >+gst_wpe_src_get_protocols (GType) >+{ >+ static const char *protocols[] = { "wpe", NULL }; >+ return protocols; >+} >+ >+static gchar * >+gst_wpe_src_get_uri (GstURIHandler * handler) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (handler); >+ return g_strdup_printf ("wpe://%s", src->location); >+} >+ >+static gboolean >+gst_wpe_src_set_uri (GstURIHandler * handler, const gchar * uri, >+ GError ** error) >+{ >+ GstWpeSrc *src = GST_WPE_SRC (handler); >+ >+ return gst_wpe_src_set_location (src, uri + 6, error); >+} >+ >+static void >+gst_wpe_src_uri_handler_init (gpointer iface_ptr, gpointer data) >+{ >+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) iface_ptr; >+ >+ iface->get_type = gst_wpe_src_uri_get_type; >+ iface->get_protocols = gst_wpe_src_get_protocols; >+ iface->get_uri = gst_wpe_src_get_uri; >+ iface->set_uri = gst_wpe_src_set_uri; >+} >+ >+static void >+gst_wpe_src_class_init (GstWpeSrcClass * klass) >+{ >+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); >+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); >+ GstPushSrcClass *push_src_class = GST_PUSH_SRC_CLASS (klass); >+ GstBaseSrcClass *base_src_class = GST_BASE_SRC_CLASS (klass); >+ >+ gobject_class->set_property = gst_wpe_src_set_property; >+ gobject_class->get_property = gst_wpe_src_get_property; >+ >+ g_object_class_install_property (gobject_class, PROP_LOCATION, >+ g_param_spec_string ("location", "location", >+ "The URL to display", >+ "", (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); >+ g_object_class_install_property (gobject_class, PROP_DRAW_BACKGROUND, >+ g_param_spec_boolean ("draw-background", "Draws the background", >+ "Whether to draw the WebView background", TRUE, >+ (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS))); >+ >+ gst_element_class_set_static_metadata (gstelement_class, >+ "WPE source", "Source/Video", >+ "Creates a video stream from a WPE browser", >+ "Philippe Normand <philn@igalia.com>, Žan Doberšek <zdobersek@igalia.com>"); >+ >+ gst_element_class_add_static_pad_template (gstelement_class, &src_factory); >+ >+ gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_wpe_src_set_context); >+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_wpe_src_change_state); >+ >+ base_src_class->fixate = GST_DEBUG_FUNCPTR (gst_wpe_src_fixate); >+ base_src_class->set_caps = GST_DEBUG_FUNCPTR (gst_wpe_src_set_caps); >+ base_src_class->start = GST_DEBUG_FUNCPTR (gst_wpe_src_start); >+ base_src_class->stop = GST_DEBUG_FUNCPTR (gst_wpe_src_stop); >+ base_src_class->get_times = GST_DEBUG_FUNCPTR (gst_wpe_src_get_times); >+ base_src_class->query = GST_DEBUG_FUNCPTR (gst_wpe_src_query); >+ base_src_class->decide_allocation = >+ GST_DEBUG_FUNCPTR (gst_wpe_src_decide_allocation); >+ >+ push_src_class->fill = GST_DEBUG_FUNCPTR (gst_wpe_src_fill); >+ >+ /** >+ * GstWpeSrc::configure-web-view: >+ * @src: the object which received the signal >+ * @webview: the webView >+ * >+ * Allow application to configure the webView settings. >+ */ >+ gst_wpe_src_signals[SIGNAL_CONFIGURE_WEB_VIEW] = >+ g_signal_new ("configure-web-view", G_TYPE_FROM_CLASS (klass), >+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, >+ G_TYPE_NONE, 1, G_TYPE_OBJECT); >+ >+} >+ >+static gboolean >+plugin_init (GstPlugin * plugin) >+{ >+ GST_DEBUG_CATEGORY_INIT (wpe_src_debug, "wpesrc", 0, "WPE Source"); >+ >+ return gst_element_register (plugin, "wpesrc", GST_RANK_NONE, >+ GST_TYPE_WPE_SRC); >+} >+ >+#define PACKAGE "gstwpe" >+ >+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, >+ GST_VERSION_MINOR, >+ wpe, >+ "WPE src plugin", plugin_init, "1.0", "LGPL", PACKAGE, "https://igalia.com") >diff --git a/Source/ThirdParty/WPE/GstWPE/gstwpesrc.h b/Source/ThirdParty/WPE/GstWPE/gstwpesrc.h >new file mode 100644 >index 0000000000000000000000000000000000000000..8c93e297abd48e431188c87e5c2c373c1468b0c7 >--- /dev/null >+++ b/Source/ThirdParty/WPE/GstWPE/gstwpesrc.h >@@ -0,0 +1,51 @@ >+/* Copyright (C) <2018> Philippe Normand <philn@igalia.com> >+ * Copyright (C) <2018> Žan Doberšek <zdobersek@igalia.com> >+ * >+ * 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; if not, write to the >+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#pragma once >+ >+#include <gst/gst.h> >+#include <gst/base/gstpushsrc.h> >+#include <wpe/webkit.h> >+ >+G_BEGIN_DECLS >+ >+#define GST_TYPE_WPE_SRC \ >+ (gst_wpe_src_get_type()) >+#define GST_WPE_SRC(obj) \ >+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WPE_SRC,GstWpeSrc)) >+#define GST_WPE_SRC_CLASS(klass) \ >+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WPE_SRC,GstWpeSrcClass)) >+#define GST_IS_WPE_SRC(obj) \ >+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WPE_SRC)) >+#define GST_IS_WPE_SRC_CLASS(klass) \ >+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WPE_SRC)) >+ >+typedef struct _GstWpeSrc GstWpeSrc; >+typedef struct _GstWpeSrcClass GstWpeSrcClass; >+ >+struct _GstWpeSrcClass >+{ >+ GstPushSrcClass parent_class; >+}; >+ >+GType gst_wpe_src_get_type (void); >+ >+void gst_wpe_src_configure_web_view(GstWpeSrc*, WebKitWebView* webview); >+ >+G_END_DECLS >diff --git a/Source/ThirdParty/WPE/GstWPE/meson.build b/Source/ThirdParty/WPE/GstWPE/meson.build >new file mode 100644 >index 0000000000000000000000000000000000000000..1e36a89e05a0bd64f178e6f0a95514073124a824 >--- /dev/null >+++ b/Source/ThirdParty/WPE/GstWPE/meson.build >@@ -0,0 +1,23 @@ >+project('gstwpe', 'cpp', >+ license: 'LGPL', >+ version: '1.0') >+ >+gstbase_dep = dependency('gstreamer-base-1.0', version : '>=1.0', required : true) >+gstgl_dep = dependency('gstreamer-gl-1.0', version : '>=1.0', required : true) >+gstvideo_dep = dependency('gstreamer-video-1.0', version : '>=1.0', required : true) >+ >+wpe_dep = dependency('wpe-webkit-0.1', required : true) >+wpe_fdo_dep = dependency('wpebackend-fdo-0.1', required : true) >+ >+egl_dep = dependency('egl', required : true) >+xkbcommon_dep = dependency('xkbcommon', version : '>= 0.8', required : true) >+ >+gstwpe_sources = [ >+ 'WPEThreadedView.cpp', >+ 'gstwpesrc.cpp'] >+ >+gstwpe = shared_library('gstwpe', >+ gstwpe_sources, >+ dependencies : [egl_dep, wpe_dep, wpe_fdo_dep, gstvideo_dep, gstbase_dep, gstgl_dep, xkbcommon_dep], >+ install : true, >+ install_dir : '@0@/gstreamer-1.0'.format(get_option('libdir'))) >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 54da3351102b6fa2fd27e71d7cd5c13402deeda7..ac80d685e3a8e05396a878d5c969b53a15245d0c 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,14 @@ >+2018-12-04 Philippe Normand <pnormand@igalia.com> >+ >+ [WPE] GStreamer/WPE Source element >+ https://bugs.webkit.org/show_bug.cgi?id=192359 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Scripts/webkitpy/style/checker.py: Register ThirdParty/WPE to the style checker. >+ * jhbuild/jhbuildrc_common.py: >+ (init): Support a new WEBKIT_UNINSTALLED_PATH environment variable >+ > 2018-12-03 Carlos Garcia Campos <cgarcia@igalia.com> > > [GTK] Bump freetype, fontconfig, harfbuzz, cairo and icu in jhbuild >diff --git a/Tools/Scripts/webkitpy/style/checker.py b/Tools/Scripts/webkitpy/style/checker.py >index 17424934e187fd7dc3118bf2c41d6df6cf2f960a..60e4703980b58125fa92801224d7d6ac6b104ef9 100644 >--- a/Tools/Scripts/webkitpy/style/checker.py >+++ b/Tools/Scripts/webkitpy/style/checker.py >@@ -225,6 +225,7 @@ _PATH_RULES_SPECIFIER = [ > os.path.join('Source', 'ThirdParty', 'libwebrtc'), > os.path.join('Source', 'ThirdParty', 'openvr'), > os.path.join('Source', 'ThirdParty', 'xdgmime'), >+ os.path.join('Source', 'ThirdParty', 'WPE'), > os.path.join('Tools', 'WebGPUAPIStructure')], > ["-", > "+pep8/W191", # Tabs >diff --git a/Tools/jhbuild/jhbuildrc_common.py b/Tools/jhbuild/jhbuildrc_common.py >index 61dfa7ec48e73dd579b43c9c2697b8f828594b51..9fc38f2307bcaf370163f5a104157e4595eda96d 100644 >--- a/Tools/jhbuild/jhbuildrc_common.py >+++ b/Tools/jhbuild/jhbuildrc_common.py >@@ -88,3 +88,10 @@ def init(jhbuildrc_globals, jhbuild_platform): > > if 'x86_64' in platform.machine(): > jhbuildrc_globals['conditions'].add('x86_64') >+ >+ __uninstalled_path = os.environ.get("WEBKIT_UNINSTALLED_PATH", "") >+ if __uninstalled_path: >+ __lib_path = os.path.join(__uninstalled_path, "lib") >+ addpath('GST_PLUGIN_PATH_1_0', __lib_path) >+ addpath('WEBKIT_EXEC_PATH', os.path.join(__uninstalled_path, "bin")) >+ addpath('WEBKIT_INJECTED_BUNDLE_PATH', __lib_path) >diff --git a/ChangeLog b/ChangeLog >index 03674a37a88a003eaa937b35be66b2613bdf3c9b..c901862697c8b923f6af753ded73a9e719884a84 100644 >--- a/ChangeLog >+++ b/ChangeLog >@@ -1,3 +1,12 @@ >+2018-12-04 Philippe Normand <pnormand@igalia.com> >+ >+ [WPE] GStreamer/WPE Source element >+ https://bugs.webkit.org/show_bug.cgi?id=192359 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * Source/CMakeLists.txt: Process WPE ThirdParty CMakeFiles. >+ > 2018-12-03 Don Olmstead <don.olmstead@sony.com> > > [CMake] Sync feature defines
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 192359
:
356483
|
356484
|
356487
|
356491
|
356492
|
356499