1From c4e12604a6a59a81ea8ba49e89eb52060987b8a0 Mon Sep 17 00:00:00 2001 2From: Jeffy Chen <jeffy.chen@rock-chips.com> 3Date: Wed, 28 Nov 2018 21:31:49 +0800 4Subject: [PATCH 03/17] gsttools: videooverlay: Support waylandsink and kmssink 5 6Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 7--- 8 src/gsttools/qgstreamervideooverlay.cpp | 181 ++++++++++++++++++++---- 9 src/gsttools/qgstreamervideooverlay_p.h | 2 + 10 src/gsttools/qgstreamervideowidget.cpp | 16 ++- 11 3 files changed, 170 insertions(+), 29 deletions(-) 12 13diff --git a/src/gsttools/qgstreamervideooverlay.cpp b/src/gsttools/qgstreamervideooverlay.cpp 14index d410be7..8d2df0a 100644 15--- a/src/gsttools/qgstreamervideooverlay.cpp 16+++ b/src/gsttools/qgstreamervideooverlay.cpp 17@@ -39,8 +39,13 @@ 18 19 #include "qgstreamervideooverlay_p.h" 20 21+#include <QtCore/qthread.h> 22 #include <QtGui/qguiapplication.h> 23+#include <QtGui/qwindow.h> 24+#include <QtGui/qpa/qplatformwindow.h> 25+#include <QtGui/qpa/qplatformnativeinterface.h> 26 #include "qgstutils_p.h" 27+#include "qdebug.h" 28 29 #if !GST_CHECK_VERSION(1,0,0) 30 #include <gst/interfaces/xoverlay.h> 31@@ -48,6 +53,10 @@ 32 #include <gst/video/videooverlay.h> 33 #endif 34 35+#ifdef ENABLE_WAYLAND_PLATFORM 36+#include <wayland-client-protocol.h> 37+#endif 38+ 39 #include <QtMultimedia/private/qtmultimediaglobal_p.h> 40 41 QT_BEGIN_NAMESPACE 42@@ -445,29 +454,127 @@ QSize QGstreamerVideoOverlay::nativeVideoSize() const 43 44 void QGstreamerVideoOverlay::setWindowHandle(WId id) 45 { 46+#ifndef ENABLE_WAYLAND_PLATFORM 47+ if (m_windowId == id) 48+ return; 49+#endif 50+ 51 m_windowId = id; 52 53- if (isActive()) 54- setWindowHandle_helper(id); 55+ setWindowHandle_helper(id); 56+} 57+ 58+static QWindow *findWindow(WId id) { 59+ const auto allWindows = QGuiApplication::allWindows(); 60+ for (QWindow *window : allWindows) 61+ if (window->winId() == id) 62+ return window; 63+ 64+ return NULL; 65+} 66+ 67+static QWindow *getVideoWindow(WId id) { 68+ QWindow *window = findWindow(id); 69+ 70+ QVideoWindowAbstractInterface *intf = 71+ dynamic_cast<QVideoWindowAbstractInterface *>(window); 72+ 73+ return intf ? findWindow(intf->videoWinId()) : window; 74 } 75 76 void QGstreamerVideoOverlay::setWindowHandle_helper(WId id) 77 { 78-#if GST_CHECK_VERSION(1,0,0) 79- if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) { 80- gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(m_videoSink), id); 81-#else 82- if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { 83-# if GST_CHECK_VERSION(0,10,31) 84- gst_x_overlay_set_window_handle(GST_X_OVERLAY(m_videoSink), id); 85-# else 86- gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), id); 87-# endif 88+#ifdef ENABLE_WAYLAND_PLATFORM 89+ QPlatformNativeInterface *native = 90+ QGuiApplication::platformNativeInterface(); 91+ wl_surface *surface = NULL; 92+ wl_compositor *compositor = NULL; 93+ QWindow *window; 94+#endif 95+ GstVideoOverlay *overlay; 96+ QPoint position; 97+ 98+ bool main_thread = 99+ QThread::currentThread() == QGuiApplication::instance()->thread(); 100+ 101+#if !GST_CHECK_VERSION(1,0,0) 102+ qWarning("Only support gstreamer-1.0\n"); 103+ goto out; 104+#endif 105+ 106+ if (!m_videoSink || !GST_IS_VIDEO_OVERLAY(m_videoSink)) 107+ goto out; 108+ 109+ overlay = GST_VIDEO_OVERLAY(m_videoSink); 110+ 111+#ifdef ENABLE_WAYLAND_PLATFORM 112+ window = (id && main_thread) ? getVideoWindow(id) : NULL; 113+ if (!window) { 114+ gst_video_overlay_set_window_handle(overlay, 0); 115+ goto set_rectangle; 116+ } 117+ 118+ // HACK: Force updating decoration 119+ window->setFlags(window->flags()); 120+ 121+ id = window->winId(); 122 #endif 123 124- // Properties need to be reset when changing the winId. 125- m_sinkProperties->reset(); 126+#ifdef ENABLE_WAYLAND_PLATFORM 127+ if (native) { 128+ surface = (wl_surface*) native->nativeResourceForWindow("surface", window); 129+ compositor = (wl_compositor*) native->nativeResourceForWindow("compositor", window); 130 } 131+ 132+ // It's wayland platform, using wl_surface as window handle. 133+ if (compositor) { 134+ if (!isActive()) 135+ surface = NULL; 136+ 137+ gst_video_overlay_set_window_handle(overlay, (WId) surface); 138+ 139+ if (m_rect.width() <= 0 || m_rect.height() <= 0) 140+ goto out; 141+ 142+ position = QPoint(window->frameMargins().left(), 143+ window->frameMargins().top()); 144+ 145+ // HACK: kmssink is using global position 146+ if (strstr(GST_ELEMENT_NAME(m_videoSink), "kmssink")) 147+ position += window->geometry().topLeft(); 148+ 149+ gst_video_overlay_set_render_rectangle(overlay, 150+ position.x() + m_rect.x(), 151+ position.y() + m_rect.y(), 152+ m_rect.width(), m_rect.height()); 153+ 154+ if (!surface) 155+ goto out; 156+ 157+ // HACK: Tell wayland server about the video rectangle 158+ struct wl_region *region = wl_compositor_create_region(compositor); 159+ wl_region_add(region, position.x() + m_rect.x(), 160+ position.y() + m_rect.y(), 161+ m_rect.width(), m_rect.height()); 162+ wl_region_add(region, -1, -1, 1, 1); 163+ wl_surface_set_opaque_region(surface, region); 164+ wl_region_destroy(region); 165+ wl_surface_set_opaque_region(surface, NULL); 166+ 167+ goto out; 168+ } 169+#endif // ENABLE_WAYLAND_PLATFORM 170+ 171+ gst_video_overlay_set_window_handle(overlay, id); 172+ 173+set_rectangle: 174+ if (m_rect.width() > 0 && m_rect.height() > 0) 175+ gst_video_overlay_set_render_rectangle(overlay, 176+ m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height()); 177+ 178+out: 179+ // Properties need to be reset when changing the winId. 180+ m_sinkProperties->reset(); 181 } 182 183 void QGstreamerVideoOverlay::expose() 184@@ -499,24 +606,45 @@ void QGstreamerVideoOverlay::setRenderRectangle(const QRect &rect) 185 h = rect.height(); 186 } 187 188-#if GST_CHECK_VERSION(1,0,0) 189- if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) 190- gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink), x, y, w, h); 191-#elif GST_CHECK_VERSION(0, 10, 29) 192- if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) 193- gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), x, y , w , h); 194-#else 195- Q_UNUSED(x) 196- Q_UNUSED(y) 197- Q_UNUSED(w) 198- Q_UNUSED(h) 199-#endif 200+ m_rect = QRect(x, y, w, h); 201+ 202+ setWindowHandle_helper(m_windowId); 203 } 204 205 bool QGstreamerVideoOverlay::processSyncMessage(const QGstreamerMessage &message) 206 { 207 GstMessage* gm = message.rawMessage(); 208 209+#if GST_CHECK_VERSION(1,0,0) 210+ 211+#ifdef ENABLE_WAYLAND_PLATFORM 212+#define GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType" 213+#define GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE "GstWlDisplayHandleContextType" 214+ if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_NEED_CONTEXT)) { 215+ const gchar *type = NULL; 216+ 217+ if (gst_message_parse_context_type(gm, &type) && 218+ (!g_strcmp0(type, GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE) || 219+ !g_strcmp0(type, GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE))) { 220+ GstContext *context = 221+ gst_context_new(type, TRUE); 222+ QPlatformNativeInterface *native = 223+ QGuiApplication::platformNativeInterface(); 224+ void *handle = NULL; 225+ 226+ if (native) 227+ handle = native->nativeResourceForWindow("display", NULL); 228+ 229+ gst_structure_set(gst_context_writable_structure(context), 230+ "handle", G_TYPE_POINTER, handle, NULL); 231+ gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(gm)), context); 232+ gst_context_unref(context); 233+ return true; 234+ } 235+ } 236+#endif 237+#endif 238+ 239 #if !GST_CHECK_VERSION(1,0,0) 240 if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) && 241 gst_structure_has_name(gm->structure, "prepare-xwindow-id")) { 242@@ -574,6 +702,7 @@ void QGstreamerVideoOverlay::updateIsActive() 243 if (newIsActive != m_isActive) { 244 m_isActive = newIsActive; 245 emit activeChanged(); 246+ setWindowHandle_helper(m_windowId); 247 } 248 } 249 250diff --git a/src/gsttools/qgstreamervideooverlay_p.h b/src/gsttools/qgstreamervideooverlay_p.h 251index f2ca8a2..32b3d93 100644 252--- a/src/gsttools/qgstreamervideooverlay_p.h 253+++ b/src/gsttools/qgstreamervideooverlay_p.h 254@@ -54,6 +54,7 @@ 255 #include <private/qgstreamerbushelper_p.h> 256 #include <private/qgstreamerbufferprobe_p.h> 257 #include <QtGui/qwindowdefs.h> 258+#include <QtCore/qrect.h> 259 #include <QtCore/qsize.h> 260 261 QT_BEGIN_NAMESPACE 262@@ -119,6 +120,7 @@ private: 263 264 QGstreamerSinkProperties *m_sinkProperties = nullptr; 265 WId m_windowId = 0; 266+ QRect m_rect; 267 }; 268 269 QT_END_NAMESPACE 270diff --git a/src/gsttools/qgstreamervideowidget.cpp b/src/gsttools/qgstreamervideowidget.cpp 271index 55f9157..95bfe6e 100644 272--- a/src/gsttools/qgstreamervideowidget.cpp 273+++ b/src/gsttools/qgstreamervideowidget.cpp 274@@ -43,10 +43,11 @@ 275 #include <QtCore/qdebug.h> 276 #include <QtGui/qevent.h> 277 #include <QtGui/qpainter.h> 278+#include <QtGui/qwindow.h> 279 280 QT_BEGIN_NAMESPACE 281 282-class QGstreamerVideoWidget : public QWidget 283+class QGstreamerVideoWidget : public QWidget, public QVideoWindowAbstractInterface 284 { 285 public: 286 QGstreamerVideoWidget(QGstreamerVideoOverlay *overlay, QWidget *parent = 0) 287@@ -85,6 +86,15 @@ public: 288 painter.fillRect(rect(), palette().window()); 289 } 290 291+ WId videoWinId() const Q_DECL_OVERRIDE { 292+#ifdef ENABLE_WAYLAND_PLATFORM 293+ QWidget *parent = parentWidget(); 294+ if (parent) 295+ return parent->winId() ?: parent->internalWinId(); 296+#endif 297+ return winId() ?: internalWinId(); 298+ } 299+ 300 protected: 301 void paintEvent(QPaintEvent *) override 302 { 303@@ -131,7 +141,7 @@ void QGstreamerVideoWidgetControl::createVideoWidget() 304 m_widget = new QGstreamerVideoWidget(&m_videoOverlay); 305 306 m_widget->installEventFilter(this); 307- m_videoOverlay.setWindowHandle(m_windowId = m_widget->winId()); 308+ m_videoOverlay.setWindowHandle(m_windowId = m_widget->videoWinId()); 309 } 310 311 GstElement *QGstreamerVideoWidgetControl::videoSink() 312@@ -171,7 +181,7 @@ bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e) 313 { 314 if (m_widget && object == m_widget) { 315 if (e->type() == QEvent::ParentChange || e->type() == QEvent::Show || e->type() == QEvent::WinIdChange) { 316- WId newWId = m_widget->winId(); 317+ WId newWId = m_widget->videoWinId(); 318 if (newWId != m_windowId) 319 m_videoOverlay.setWindowHandle(m_windowId = newWId); 320 } 321-- 3222.20.1 323 324