HYL_OK3568_LINUX/buildroot/package/qt5/qt5multimedia/0003-gsttools-videooverlay-Support-waylandsink-and-kmssin.patch
2025-05-10 21:49:39 +08:00

324 lines
10 KiB
Diff

From c4e12604a6a59a81ea8ba49e89eb52060987b8a0 Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Wed, 28 Nov 2018 21:31:49 +0800
Subject: [PATCH 03/17] gsttools: videooverlay: Support waylandsink and kmssink
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
src/gsttools/qgstreamervideooverlay.cpp | 181 ++++++++++++++++++++----
src/gsttools/qgstreamervideooverlay_p.h | 2 +
src/gsttools/qgstreamervideowidget.cpp | 16 ++-
3 files changed, 170 insertions(+), 29 deletions(-)
diff --git a/src/gsttools/qgstreamervideooverlay.cpp b/src/gsttools/qgstreamervideooverlay.cpp
index d410be7..8d2df0a 100644
--- a/src/gsttools/qgstreamervideooverlay.cpp
+++ b/src/gsttools/qgstreamervideooverlay.cpp
@@ -39,8 +39,13 @@
#include "qgstreamervideooverlay_p.h"
+#include <QtCore/qthread.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qpa/qplatformwindow.h>
+#include <QtGui/qpa/qplatformnativeinterface.h>
#include "qgstutils_p.h"
+#include "qdebug.h"
#if !GST_CHECK_VERSION(1,0,0)
#include <gst/interfaces/xoverlay.h>
@@ -48,6 +53,10 @@
#include <gst/video/videooverlay.h>
#endif
+#ifdef ENABLE_WAYLAND_PLATFORM
+#include <wayland-client-protocol.h>
+#endif
+
#include <QtMultimedia/private/qtmultimediaglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -445,29 +454,127 @@ QSize QGstreamerVideoOverlay::nativeVideoSize() const
void QGstreamerVideoOverlay::setWindowHandle(WId id)
{
+#ifndef ENABLE_WAYLAND_PLATFORM
+ if (m_windowId == id)
+ return;
+#endif
+
m_windowId = id;
- if (isActive())
- setWindowHandle_helper(id);
+ setWindowHandle_helper(id);
+}
+
+static QWindow *findWindow(WId id) {
+ const auto allWindows = QGuiApplication::allWindows();
+ for (QWindow *window : allWindows)
+ if (window->winId() == id)
+ return window;
+
+ return NULL;
+}
+
+static QWindow *getVideoWindow(WId id) {
+ QWindow *window = findWindow(id);
+
+ QVideoWindowAbstractInterface *intf =
+ dynamic_cast<QVideoWindowAbstractInterface *>(window);
+
+ return intf ? findWindow(intf->videoWinId()) : window;
}
void QGstreamerVideoOverlay::setWindowHandle_helper(WId id)
{
-#if GST_CHECK_VERSION(1,0,0)
- if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) {
- gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(m_videoSink), id);
-#else
- if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) {
-# if GST_CHECK_VERSION(0,10,31)
- gst_x_overlay_set_window_handle(GST_X_OVERLAY(m_videoSink), id);
-# else
- gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), id);
-# endif
+#ifdef ENABLE_WAYLAND_PLATFORM
+ QPlatformNativeInterface *native =
+ QGuiApplication::platformNativeInterface();
+ wl_surface *surface = NULL;
+ wl_compositor *compositor = NULL;
+ QWindow *window;
+#endif
+ GstVideoOverlay *overlay;
+ QPoint position;
+
+ bool main_thread =
+ QThread::currentThread() == QGuiApplication::instance()->thread();
+
+#if !GST_CHECK_VERSION(1,0,0)
+ qWarning("Only support gstreamer-1.0\n");
+ goto out;
+#endif
+
+ if (!m_videoSink || !GST_IS_VIDEO_OVERLAY(m_videoSink))
+ goto out;
+
+ overlay = GST_VIDEO_OVERLAY(m_videoSink);
+
+#ifdef ENABLE_WAYLAND_PLATFORM
+ window = (id && main_thread) ? getVideoWindow(id) : NULL;
+ if (!window) {
+ gst_video_overlay_set_window_handle(overlay, 0);
+ goto set_rectangle;
+ }
+
+ // HACK: Force updating decoration
+ window->setFlags(window->flags());
+
+ id = window->winId();
#endif
- // Properties need to be reset when changing the winId.
- m_sinkProperties->reset();
+#ifdef ENABLE_WAYLAND_PLATFORM
+ if (native) {
+ surface = (wl_surface*) native->nativeResourceForWindow("surface", window);
+ compositor = (wl_compositor*) native->nativeResourceForWindow("compositor", window);
}
+
+ // It's wayland platform, using wl_surface as window handle.
+ if (compositor) {
+ if (!isActive())
+ surface = NULL;
+
+ gst_video_overlay_set_window_handle(overlay, (WId) surface);
+
+ if (m_rect.width() <= 0 || m_rect.height() <= 0)
+ goto out;
+
+ position = QPoint(window->frameMargins().left(),
+ window->frameMargins().top());
+
+ // HACK: kmssink is using global position
+ if (strstr(GST_ELEMENT_NAME(m_videoSink), "kmssink"))
+ position += window->geometry().topLeft();
+
+ gst_video_overlay_set_render_rectangle(overlay,
+ position.x() + m_rect.x(),
+ position.y() + m_rect.y(),
+ m_rect.width(), m_rect.height());
+
+ if (!surface)
+ goto out;
+
+ // HACK: Tell wayland server about the video rectangle
+ struct wl_region *region = wl_compositor_create_region(compositor);
+ wl_region_add(region, position.x() + m_rect.x(),
+ position.y() + m_rect.y(),
+ m_rect.width(), m_rect.height());
+ wl_region_add(region, -1, -1, 1, 1);
+ wl_surface_set_opaque_region(surface, region);
+ wl_region_destroy(region);
+ wl_surface_set_opaque_region(surface, NULL);
+
+ goto out;
+ }
+#endif // ENABLE_WAYLAND_PLATFORM
+
+ gst_video_overlay_set_window_handle(overlay, id);
+
+set_rectangle:
+ if (m_rect.width() > 0 && m_rect.height() > 0)
+ gst_video_overlay_set_render_rectangle(overlay,
+ m_rect.x(), m_rect.y(), m_rect.width(), m_rect.height());
+
+out:
+ // Properties need to be reset when changing the winId.
+ m_sinkProperties->reset();
}
void QGstreamerVideoOverlay::expose()
@@ -499,24 +606,45 @@ void QGstreamerVideoOverlay::setRenderRectangle(const QRect &rect)
h = rect.height();
}
-#if GST_CHECK_VERSION(1,0,0)
- if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink))
- gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink), x, y, w, h);
-#elif GST_CHECK_VERSION(0, 10, 29)
- if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink))
- gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), x, y , w , h);
-#else
- Q_UNUSED(x)
- Q_UNUSED(y)
- Q_UNUSED(w)
- Q_UNUSED(h)
-#endif
+ m_rect = QRect(x, y, w, h);
+
+ setWindowHandle_helper(m_windowId);
}
bool QGstreamerVideoOverlay::processSyncMessage(const QGstreamerMessage &message)
{
GstMessage* gm = message.rawMessage();
+#if GST_CHECK_VERSION(1,0,0)
+
+#ifdef ENABLE_WAYLAND_PLATFORM
+#define GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType"
+#define GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE "GstWlDisplayHandleContextType"
+ if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_NEED_CONTEXT)) {
+ const gchar *type = NULL;
+
+ if (gst_message_parse_context_type(gm, &type) &&
+ (!g_strcmp0(type, GST_WL_DISPLAY_HANDLE_CONTEXT_TYPE) ||
+ !g_strcmp0(type, GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE))) {
+ GstContext *context =
+ gst_context_new(type, TRUE);
+ QPlatformNativeInterface *native =
+ QGuiApplication::platformNativeInterface();
+ void *handle = NULL;
+
+ if (native)
+ handle = native->nativeResourceForWindow("display", NULL);
+
+ gst_structure_set(gst_context_writable_structure(context),
+ "handle", G_TYPE_POINTER, handle, NULL);
+ gst_element_set_context(GST_ELEMENT(GST_MESSAGE_SRC(gm)), context);
+ gst_context_unref(context);
+ return true;
+ }
+ }
+#endif
+#endif
+
#if !GST_CHECK_VERSION(1,0,0)
if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) &&
gst_structure_has_name(gm->structure, "prepare-xwindow-id")) {
@@ -574,6 +702,7 @@ void QGstreamerVideoOverlay::updateIsActive()
if (newIsActive != m_isActive) {
m_isActive = newIsActive;
emit activeChanged();
+ setWindowHandle_helper(m_windowId);
}
}
diff --git a/src/gsttools/qgstreamervideooverlay_p.h b/src/gsttools/qgstreamervideooverlay_p.h
index f2ca8a2..32b3d93 100644
--- a/src/gsttools/qgstreamervideooverlay_p.h
+++ b/src/gsttools/qgstreamervideooverlay_p.h
@@ -54,6 +54,7 @@
#include <private/qgstreamerbushelper_p.h>
#include <private/qgstreamerbufferprobe_p.h>
#include <QtGui/qwindowdefs.h>
+#include <QtCore/qrect.h>
#include <QtCore/qsize.h>
QT_BEGIN_NAMESPACE
@@ -119,6 +120,7 @@ private:
QGstreamerSinkProperties *m_sinkProperties = nullptr;
WId m_windowId = 0;
+ QRect m_rect;
};
QT_END_NAMESPACE
diff --git a/src/gsttools/qgstreamervideowidget.cpp b/src/gsttools/qgstreamervideowidget.cpp
index 55f9157..95bfe6e 100644
--- a/src/gsttools/qgstreamervideowidget.cpp
+++ b/src/gsttools/qgstreamervideowidget.cpp
@@ -43,10 +43,11 @@
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
#include <QtGui/qpainter.h>
+#include <QtGui/qwindow.h>
QT_BEGIN_NAMESPACE
-class QGstreamerVideoWidget : public QWidget
+class QGstreamerVideoWidget : public QWidget, public QVideoWindowAbstractInterface
{
public:
QGstreamerVideoWidget(QGstreamerVideoOverlay *overlay, QWidget *parent = 0)
@@ -85,6 +86,15 @@ public:
painter.fillRect(rect(), palette().window());
}
+ WId videoWinId() const Q_DECL_OVERRIDE {
+#ifdef ENABLE_WAYLAND_PLATFORM
+ QWidget *parent = parentWidget();
+ if (parent)
+ return parent->winId() ?: parent->internalWinId();
+#endif
+ return winId() ?: internalWinId();
+ }
+
protected:
void paintEvent(QPaintEvent *) override
{
@@ -131,7 +141,7 @@ void QGstreamerVideoWidgetControl::createVideoWidget()
m_widget = new QGstreamerVideoWidget(&m_videoOverlay);
m_widget->installEventFilter(this);
- m_videoOverlay.setWindowHandle(m_windowId = m_widget->winId());
+ m_videoOverlay.setWindowHandle(m_windowId = m_widget->videoWinId());
}
GstElement *QGstreamerVideoWidgetControl::videoSink()
@@ -171,7 +181,7 @@ bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e)
{
if (m_widget && object == m_widget) {
if (e->type() == QEvent::ParentChange || e->type() == QEvent::Show || e->type() == QEvent::WinIdChange) {
- WId newWId = m_widget->winId();
+ WId newWId = m_widget->videoWinId();
if (newWId != m_windowId)
m_videoOverlay.setWindowHandle(m_windowId = newWId);
}
--
2.20.1