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