Fix: Correct image orientation in Wayland grabber

Resolved the issue where captured images were appearing upside down or flipped.
Implemented a final vertical flip on the QImage after reading from the OpenGL
Framebuffer Object (FBO) to ensure correct orientation before sending to Hyperion.
This completes the basic hardware-accelerated scaling pipeline.
This commit is contained in:
Tobias J. Endres 2025-08-14 22:19:15 +02:00
parent 2fe9844a04
commit 3dda269c4b
88 changed files with 309 additions and 25 deletions

View File

@ -9,7 +9,7 @@ set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 COMPONENTS Core Gui WaylandClient Multimedia Widgets MultimediaWidgets Network REQUIRED)
find_package(Qt6 COMPONENTS Core Gui WaylandClient Multimedia Widgets MultimediaWidgets Network OpenGL REQUIRED)
add_executable(Hyperion_Grabber_Wayland_QT
hyperiongrabber.cpp
@ -25,6 +25,7 @@ target_link_libraries(Hyperion_Grabber_Wayland_QT
Qt6::Multimedia
Qt6::Widgets
Qt6::MultimediaWidgets
Qt6::OpenGL
${PIPEWIRE_LIBRARIES}
)

Binary file not shown.

View File

@ -41,19 +41,19 @@ template <> constexpr inline auto WaylandGrabber::qt_create_metaobjectdata<qt_me
"WaylandGrabber",
"frameReady",
"",
"QVideoFrame",
"frame",
"handleFrame",
"QVideoFrame"
"handleFrame"
};
QtMocHelpers::UintData qt_methods {
// Signal 'frameReady'
QtMocHelpers::SignalData<void(const QImage &)>(1, 2, QMC::AccessPublic, QMetaType::Void, {{
{ QMetaType::QImage, 3 },
QtMocHelpers::SignalData<void(const QVideoFrame &)>(1, 2, QMC::AccessPublic, QMetaType::Void, {{
{ 0x80000000 | 3, 4 },
}}),
// Slot 'handleFrame'
QtMocHelpers::SlotData<void(const QVideoFrame &)>(4, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ 0x80000000 | 5, 3 },
QtMocHelpers::SlotData<void(const QVideoFrame &)>(5, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ 0x80000000 | 3, 4 },
}}),
};
QtMocHelpers::UintData qt_properties {
@ -78,13 +78,13 @@ void WaylandGrabber::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _
auto *_t = static_cast<WaylandGrabber *>(_o);
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: _t->frameReady((*reinterpret_cast< std::add_pointer_t<QImage>>(_a[1]))); break;
case 0: _t->frameReady((*reinterpret_cast< std::add_pointer_t<QVideoFrame>>(_a[1]))); break;
case 1: _t->handleFrame((*reinterpret_cast< std::add_pointer_t<QVideoFrame>>(_a[1]))); break;
default: ;
}
}
if (_c == QMetaObject::IndexOfMethod) {
if (QtMocHelpers::indexOfMethod<void (WaylandGrabber::*)(const QImage & )>(_a, &WaylandGrabber::frameReady, 0))
if (QtMocHelpers::indexOfMethod<void (WaylandGrabber::*)(const QVideoFrame & )>(_a, &WaylandGrabber::frameReady, 0))
return;
}
}
@ -121,7 +121,7 @@ int WaylandGrabber::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
// SIGNAL 0
void WaylandGrabber::frameReady(const QImage & _t1)
void WaylandGrabber::frameReady(const QVideoFrame & _t1)
{
QMetaObject::activate<void>(this, &staticMetaObject, 0, nullptr, _t1);
}

View File

@ -7,6 +7,7 @@
*****************************************************************************/
#include "../../hyperiongrabber.h"
#include <QtGui/qscreen.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qtmochelpers.h>
@ -42,6 +43,7 @@ template <> constexpr inline auto HyperionGrabber::qt_create_metaobjectdata<qt_m
"_inActivity",
"",
"_processFrame",
"QVideoFrame",
"frame",
"_setImgSize",
"width",
@ -52,12 +54,12 @@ template <> constexpr inline auto HyperionGrabber::qt_create_metaobjectdata<qt_m
// Slot '_inActivity'
QtMocHelpers::SlotData<void()>(1, 2, QMC::AccessPrivate, QMetaType::Void),
// Slot '_processFrame'
QtMocHelpers::SlotData<void(const QImage &)>(3, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ QMetaType::QImage, 4 },
QtMocHelpers::SlotData<void(const QVideoFrame &)>(3, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ 0x80000000 | 4, 5 },
}}),
// Slot '_setImgSize'
QtMocHelpers::SlotData<void(int, int)>(5, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ QMetaType::Int, 6 }, { QMetaType::Int, 7 },
QtMocHelpers::SlotData<void(int, int)>(6, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ QMetaType::Int, 7 }, { QMetaType::Int, 8 },
}}),
};
QtMocHelpers::UintData qt_properties {
@ -83,11 +85,23 @@ void HyperionGrabber::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: _t->_inActivity(); break;
case 1: _t->_processFrame((*reinterpret_cast< std::add_pointer_t<QImage>>(_a[1]))); break;
case 1: _t->_processFrame((*reinterpret_cast< std::add_pointer_t<QVideoFrame>>(_a[1]))); break;
case 2: _t->_setImgSize((*reinterpret_cast< std::add_pointer_t<int>>(_a[1])),(*reinterpret_cast< std::add_pointer_t<int>>(_a[2]))); break;
default: ;
}
}
if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
switch (_id) {
default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;
case 1:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;
case 0:
*reinterpret_cast<QMetaType *>(_a[0]) = QMetaType::fromType< QVideoFrame >(); break;
}
break;
}
}
}
const QMetaObject *HyperionGrabber::metaObject() const
@ -115,7 +129,7 @@ int HyperionGrabber::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
}
if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 3)
*reinterpret_cast<QMetaType *>(_a[0]) = QMetaType();
qt_static_metacall(this, _c, _id, _a);
_id -= 3;
}
return _id;

View File

@ -2,6 +2,7 @@
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/Hyperion_Grabber_Wayland_QT_autogen/moc_predefs.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/WaylandGrabber.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/hyperionclient.h \
/usr/include/GL/gl.h \
/usr/include/alloca.h \
/usr/include/asm-generic/bitsperlong.h \
/usr/include/asm-generic/errno-base.h \
@ -36,6 +37,8 @@
/usr/include/bits/select.h \
/usr/include/bits/setjmp.h \
/usr/include/bits/stdint-intn.h \
/usr/include/bits/stdint-least.h \
/usr/include/bits/stdint-uintn.h \
/usr/include/bits/stdio_lim.h \
/usr/include/bits/stdlib-float.h \
/usr/include/bits/struct_mutex.h \
@ -254,6 +257,7 @@
/usr/include/features.h \
/usr/include/gnu/stubs-64.h \
/usr/include/gnu/stubs.h \
/usr/include/inttypes.h \
/usr/include/limits.h \
/usr/include/linux/errno.h \
/usr/include/linux/limits.h \
@ -267,6 +271,7 @@
/usr/include/qt6/QtCore/QMargins \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QRect \
/usr/include/qt6/QtCore/QScopedPointer \
/usr/include/qt6/QtCore/QSize \
/usr/include/qt6/QtCore/QSizeF \
/usr/include/qt6/QtCore/QTimer \
@ -407,20 +412,34 @@
/usr/include/qt6/QtCore/qxptype_traits.h \
/usr/include/qt6/QtCore/qyieldcpu.h \
/usr/include/qt6/QtGui/QImage \
/usr/include/qt6/QtGui/QOffscreenSurface \
/usr/include/qt6/QtGui/QOpenGLContext \
/usr/include/qt6/QtGui/QOpenGLFunctions \
/usr/include/qt6/QtGui/QScreen \
/usr/include/qt6/QtGui/QSurfaceFormat \
/usr/include/qt6/QtGui/QTransform \
/usr/include/qt6/QtGui/qbitmap.h \
/usr/include/qt6/QtGui/qcolor.h \
/usr/include/qt6/QtGui/qcursor.h \
/usr/include/qt6/QtGui/qgenericmatrix.h \
/usr/include/qt6/QtGui/qguiapplication.h \
/usr/include/qt6/QtGui/qguiapplication_platform.h \
/usr/include/qt6/QtGui/qicon.h \
/usr/include/qt6/QtGui/qimage.h \
/usr/include/qt6/QtGui/qinputmethod.h \
/usr/include/qt6/QtGui/qmatrix4x4.h \
/usr/include/qt6/QtGui/qoffscreensurface.h \
/usr/include/qt6/QtGui/qoffscreensurface_platform.h \
/usr/include/qt6/QtGui/qopengl.h \
/usr/include/qt6/QtGui/qopenglcontext.h \
/usr/include/qt6/QtGui/qopenglcontext_platform.h \
/usr/include/qt6/QtGui/qopenglext.h \
/usr/include/qt6/QtGui/qopenglfunctions.h \
/usr/include/qt6/QtGui/qpaintdevice.h \
/usr/include/qt6/QtGui/qpixelformat.h \
/usr/include/qt6/QtGui/qpixmap.h \
/usr/include/qt6/QtGui/qpolygon.h \
/usr/include/qt6/QtGui/qquaternion.h \
/usr/include/qt6/QtGui/qregion.h \
/usr/include/qt6/QtGui/qrgb.h \
/usr/include/qt6/QtGui/qrgba64.h \
@ -432,16 +451,24 @@
/usr/include/qt6/QtGui/qtguiexports.h \
/usr/include/qt6/QtGui/qtguiglobal.h \
/usr/include/qt6/QtGui/qtransform.h \
/usr/include/qt6/QtGui/qvector2d.h \
/usr/include/qt6/QtGui/qvector3d.h \
/usr/include/qt6/QtGui/qvector4d.h \
/usr/include/qt6/QtGui/qvectornd.h \
/usr/include/qt6/QtGui/qwindow.h \
/usr/include/qt6/QtGui/qwindowdefs.h \
/usr/include/qt6/QtMultimedia/QMediaCaptureSession \
/usr/include/qt6/QtMultimedia/QScreenCapture \
/usr/include/qt6/QtMultimedia/QVideoFrame \
/usr/include/qt6/QtMultimedia/QVideoSink \
/usr/include/qt6/QtMultimedia/qmediacapturesession.h \
/usr/include/qt6/QtMultimedia/qscreencapture.h \
/usr/include/qt6/QtMultimedia/qtmultimedia-config.h \
/usr/include/qt6/QtMultimedia/qtmultimediaexports.h \
/usr/include/qt6/QtMultimedia/qtmultimediaglobal.h \
/usr/include/qt6/QtMultimedia/qtvideo.h \
/usr/include/qt6/QtMultimedia/qvideoframe.h \
/usr/include/qt6/QtMultimedia/qvideoframeformat.h \
/usr/include/qt6/QtMultimedia/qvideosink.h \
/usr/include/qt6/QtNetwork/QTcpSocket \
/usr/include/qt6/QtNetwork/qabstractsocket.h \
@ -450,8 +477,18 @@
/usr/include/qt6/QtNetwork/qtnetwork-config.h \
/usr/include/qt6/QtNetwork/qtnetworkexports.h \
/usr/include/qt6/QtNetwork/qtnetworkglobal.h \
/usr/include/qt6/QtOpenGL/QOpenGLFramebufferObject \
/usr/include/qt6/QtOpenGL/QOpenGLShader \
/usr/include/qt6/QtOpenGL/QOpenGLShaderProgram \
/usr/include/qt6/QtOpenGL/QOpenGLTexture \
/usr/include/qt6/QtOpenGL/qopenglframebufferobject.h \
/usr/include/qt6/QtOpenGL/qopenglshaderprogram.h \
/usr/include/qt6/QtOpenGL/qopengltexture.h \
/usr/include/qt6/QtOpenGL/qtopenglexports.h \
/usr/include/qt6/QtOpenGL/qtopenglglobal.h \
/usr/include/sched.h \
/usr/include/stdc-predef.h \
/usr/include/stdint.h \
/usr/include/stdio.h \
/usr/include/stdlib.h \
/usr/include/string.h \

View File

@ -11,6 +11,7 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/hyperiongrabber.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/hyperiongrabber.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/main.cpp \
/usr/include/GL/gl.h \
/usr/include/alloca.h \
/usr/include/asm-generic/bitsperlong.h \
/usr/include/asm-generic/errno-base.h \
@ -45,6 +46,8 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/bits/select.h \
/usr/include/bits/setjmp.h \
/usr/include/bits/stdint-intn.h \
/usr/include/bits/stdint-least.h \
/usr/include/bits/stdint-uintn.h \
/usr/include/bits/stdio_lim.h \
/usr/include/bits/stdlib-float.h \
/usr/include/bits/struct_mutex.h \
@ -263,6 +266,7 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/features.h \
/usr/include/gnu/stubs-64.h \
/usr/include/gnu/stubs.h \
/usr/include/inttypes.h \
/usr/include/limits.h \
/usr/include/linux/errno.h \
/usr/include/linux/limits.h \
@ -276,6 +280,7 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/qt6/QtCore/QMargins \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QRect \
/usr/include/qt6/QtCore/QScopedPointer \
/usr/include/qt6/QtCore/QSize \
/usr/include/qt6/QtCore/QSizeF \
/usr/include/qt6/QtCore/QTimer \
@ -416,20 +421,34 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/qt6/QtCore/qxptype_traits.h \
/usr/include/qt6/QtCore/qyieldcpu.h \
/usr/include/qt6/QtGui/QImage \
/usr/include/qt6/QtGui/QOffscreenSurface \
/usr/include/qt6/QtGui/QOpenGLContext \
/usr/include/qt6/QtGui/QOpenGLFunctions \
/usr/include/qt6/QtGui/QScreen \
/usr/include/qt6/QtGui/QSurfaceFormat \
/usr/include/qt6/QtGui/QTransform \
/usr/include/qt6/QtGui/qbitmap.h \
/usr/include/qt6/QtGui/qcolor.h \
/usr/include/qt6/QtGui/qcursor.h \
/usr/include/qt6/QtGui/qgenericmatrix.h \
/usr/include/qt6/QtGui/qguiapplication.h \
/usr/include/qt6/QtGui/qguiapplication_platform.h \
/usr/include/qt6/QtGui/qicon.h \
/usr/include/qt6/QtGui/qimage.h \
/usr/include/qt6/QtGui/qinputmethod.h \
/usr/include/qt6/QtGui/qmatrix4x4.h \
/usr/include/qt6/QtGui/qoffscreensurface.h \
/usr/include/qt6/QtGui/qoffscreensurface_platform.h \
/usr/include/qt6/QtGui/qopengl.h \
/usr/include/qt6/QtGui/qopenglcontext.h \
/usr/include/qt6/QtGui/qopenglcontext_platform.h \
/usr/include/qt6/QtGui/qopenglext.h \
/usr/include/qt6/QtGui/qopenglfunctions.h \
/usr/include/qt6/QtGui/qpaintdevice.h \
/usr/include/qt6/QtGui/qpixelformat.h \
/usr/include/qt6/QtGui/qpixmap.h \
/usr/include/qt6/QtGui/qpolygon.h \
/usr/include/qt6/QtGui/qquaternion.h \
/usr/include/qt6/QtGui/qregion.h \
/usr/include/qt6/QtGui/qrgb.h \
/usr/include/qt6/QtGui/qrgba64.h \
@ -441,16 +460,24 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/qt6/QtGui/qtguiexports.h \
/usr/include/qt6/QtGui/qtguiglobal.h \
/usr/include/qt6/QtGui/qtransform.h \
/usr/include/qt6/QtGui/qvector2d.h \
/usr/include/qt6/QtGui/qvector3d.h \
/usr/include/qt6/QtGui/qvector4d.h \
/usr/include/qt6/QtGui/qvectornd.h \
/usr/include/qt6/QtGui/qwindow.h \
/usr/include/qt6/QtGui/qwindowdefs.h \
/usr/include/qt6/QtMultimedia/QMediaCaptureSession \
/usr/include/qt6/QtMultimedia/QScreenCapture \
/usr/include/qt6/QtMultimedia/QVideoFrame \
/usr/include/qt6/QtMultimedia/QVideoSink \
/usr/include/qt6/QtMultimedia/qmediacapturesession.h \
/usr/include/qt6/QtMultimedia/qscreencapture.h \
/usr/include/qt6/QtMultimedia/qtmultimedia-config.h \
/usr/include/qt6/QtMultimedia/qtmultimediaexports.h \
/usr/include/qt6/QtMultimedia/qtmultimediaglobal.h \
/usr/include/qt6/QtMultimedia/qtvideo.h \
/usr/include/qt6/QtMultimedia/qvideoframe.h \
/usr/include/qt6/QtMultimedia/qvideoframeformat.h \
/usr/include/qt6/QtMultimedia/qvideosink.h \
/usr/include/qt6/QtNetwork/QTcpSocket \
/usr/include/qt6/QtNetwork/qabstractsocket.h \
@ -459,8 +486,18 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/qt6/QtNetwork/qtnetwork-config.h \
/usr/include/qt6/QtNetwork/qtnetworkexports.h \
/usr/include/qt6/QtNetwork/qtnetworkglobal.h \
/usr/include/qt6/QtOpenGL/QOpenGLFramebufferObject \
/usr/include/qt6/QtOpenGL/QOpenGLShader \
/usr/include/qt6/QtOpenGL/QOpenGLShaderProgram \
/usr/include/qt6/QtOpenGL/QOpenGLTexture \
/usr/include/qt6/QtOpenGL/qopenglframebufferobject.h \
/usr/include/qt6/QtOpenGL/qopenglshaderprogram.h \
/usr/include/qt6/QtOpenGL/qopengltexture.h \
/usr/include/qt6/QtOpenGL/qtopenglexports.h \
/usr/include/qt6/QtOpenGL/qtopenglglobal.h \
/usr/include/sched.h \
/usr/include/stdc-predef.h \
/usr/include/stdint.h \
/usr/include/stdio.h \
/usr/include/stdlib.h \
/usr/include/string.h \
@ -821,6 +858,21 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/lib/cmake/Qt6NetworkPrivate/Qt6NetworkPrivateDependencies.cmake \
/usr/lib/cmake/Qt6NetworkPrivate/Qt6NetworkPrivateTargets.cmake \
/usr/lib/cmake/Qt6NetworkPrivate/Qt6NetworkPrivateVersionlessAliasTargets.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLAdditionalTargetInfo.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLConfig.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLConfigVersion.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLConfigVersionImpl.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLDependencies.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLTargets-relwithdebinfo.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLTargets.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLVersionlessAliasTargets.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateAdditionalTargetInfo.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateConfig.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateConfigVersion.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateConfigVersionImpl.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateDependencies.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateTargets.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateVersionlessAliasTargets.cmake \
/usr/lib/cmake/Qt6WaylandClient/Qt6DmaBufServerBufferPluginAdditionalTargetInfo.cmake \
/usr/lib/cmake/Qt6WaylandClient/Qt6DmaBufServerBufferPluginConfig.cmake \
/usr/lib/cmake/Qt6WaylandClient/Qt6DmaBufServerBufferPluginTargets-relwithdebinfo.cmake \

View File

@ -42,6 +42,7 @@
#define __cpp_variable_templates 201304L
#define __FLT32X_MAX_EXP__ 1024
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
#define QT_OPENGL_LIB 1
#define __FLT32_HAS_DENORM__ 1
#define __UINT_FAST8_MAX__ 0xff
#define __cpp_rvalue_reference 200610L

View File

@ -19,10 +19,6 @@ void WaylandGrabber::handleFrame(const QVideoFrame &frame)
{
if (frame.isValid())
{
QImage image = frame.toImage();
if (!image.isNull())
{
emit frameReady(image);
}
emit frameReady(frame);
}
}

View File

@ -16,7 +16,7 @@ public:
void start();
signals:
void frameReady(const QImage &frame);
void frameReady(const QVideoFrame &frame);
private slots:
void handleFrame(const QVideoFrame &frame);

View File

@ -802,6 +802,21 @@ hyperion-mock_autogen/timestamp: \
/usr/lib/cmake/Qt6NetworkPrivate/Qt6NetworkPrivateDependencies.cmake \
/usr/lib/cmake/Qt6NetworkPrivate/Qt6NetworkPrivateTargets.cmake \
/usr/lib/cmake/Qt6NetworkPrivate/Qt6NetworkPrivateVersionlessAliasTargets.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLAdditionalTargetInfo.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLConfig.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLConfigVersion.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLConfigVersionImpl.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLDependencies.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLTargets-relwithdebinfo.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLTargets.cmake \
/usr/lib/cmake/Qt6OpenGL/Qt6OpenGLVersionlessAliasTargets.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateAdditionalTargetInfo.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateConfig.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateConfigVersion.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateConfigVersionImpl.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateDependencies.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateTargets.cmake \
/usr/lib/cmake/Qt6OpenGLPrivate/Qt6OpenGLPrivateVersionlessAliasTargets.cmake \
/usr/lib/cmake/Qt6WaylandClient/Qt6DmaBufServerBufferPluginAdditionalTargetInfo.cmake \
/usr/lib/cmake/Qt6WaylandClient/Qt6DmaBufServerBufferPluginConfig.cmake \
/usr/lib/cmake/Qt6WaylandClient/Qt6DmaBufServerBufferPluginTargets-relwithdebinfo.cmake \

View File

@ -4,6 +4,15 @@
#include <QGuiApplication>
#include <QBuffer>
#include <QImage>
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOffscreenSurface>
// public
@ -50,6 +59,58 @@ HyperionGrabber::HyperionGrabber(QHash<QString, QString> opts)
_hclient_p = new HyperionClient(addr, port, _hyperionPriority_m);
_hclient_p->ledAdjustments(redAdjust, greenAdjust, blueAdjust, temperature, threshold, transform);
// Initialize OpenGL for hardware acceleration
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3); // Or higher, depending on your OpenGL version
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setRedBufferSize(8);
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
format.setAlphaBufferSize(8);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
_offscreenSurface = new QOffscreenSurface();
_offscreenSurface->setFormat(format);
_offscreenSurface->create();
_context = new QOpenGLContext(this);
_context->setFormat(format);
_context->create();
_context->makeCurrent(_offscreenSurface);
_functions = _context->functions();
_functions->initializeOpenGLFunctions();
// Shaders for scaling
const char *vertexShaderSource = R"(
attribute highp vec4 vertices;
attribute highp vec2 texCoords;
varying highp vec2 v_texCoords;
void main() {
gl_Position = vertices;
v_texCoords = texCoords;
}
)";
const char *fragmentShaderSource = R"(
uniform sampler2D textureSampler;
varying highp vec2 v_texCoords;
void main() {
gl_FragColor = texture2D(textureSampler, v_texCoords);
}
)";
_shaderProgram = new QOpenGLShaderProgram(this);
_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
_shaderProgram->link();
_fbo = new QOpenGLFramebufferObject(1, 1, QOpenGLFramebufferObject::CombinedDepthStencil); // Placeholder size, will be resized later
_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); // Placeholder, will be created from QVideoFrame
_waylandGrabber_p = new WaylandGrabber(this);
connect(_waylandGrabber_p, &WaylandGrabber::frameReady, this, &HyperionGrabber::_processFrame);
_waylandGrabber_p->start();
@ -76,6 +137,19 @@ HyperionGrabber::~HyperionGrabber()
delete _timer_p;
}
delete _hclient_p;
// OpenGL cleanup
if (_context) {
_context->makeCurrent(_offscreenSurface);
delete _fbo;
delete _shaderProgram;
delete _texture;
_context->doneCurrent();
delete _context;
}
if (_offscreenSurface) {
delete _offscreenSurface;
}
}
// private
@ -109,15 +183,94 @@ void HyperionGrabber::_inActivity()
_hclient_p->clearLeds();
}
void HyperionGrabber::_processFrame(const QImage &frame)
void HyperionGrabber::_processFrame(const QVideoFrame &frame)
{
QImage scaledImage = frame.scaled(frame.width() / _scale_m, frame.height() / _scale_m, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (!frame.isValid()) {
return;
}
_context->makeCurrent(_offscreenSurface);
// Convert QVideoFrame to QImage
QImage inputImage = frame.toImage();
if (inputImage.isNull()) {
qWarning() << "Failed to convert QVideoFrame to QImage.";
_context->doneCurrent();
return;
}
qDebug() << "Input QImage dimensions:" << inputImage.width() << "x" << inputImage.height();
qDebug() << "Input QImage format:" << inputImage.format();
// Resize FBO if needed
QSize targetSize(inputImage.width() / _scale_m, inputImage.height() / _scale_m);
if (_fbo->size() != targetSize) {
delete _fbo;
_fbo = new QOpenGLFramebufferObject(targetSize, QOpenGLFramebufferObject::CombinedDepthStencil);
}
_fbo->bind();
_functions->glViewport(0, 0, _fbo->width(), _fbo->height());
qDebug() << "FBO size:" << _fbo->size();
_functions->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
_functions->glClear(GL_COLOR_BUFFER_BIT);
// Create texture from QImage
if (_texture->isCreated()) {
_texture->destroy();
}
_texture->create();
_texture->setData(inputImage.flipped(Qt::Vertical)); // Flip vertically
qDebug() << "Texture size after setData:" << _texture->width() << "x" << _texture->height();
_shaderProgram->bind();
_shaderProgram->setUniformValue("textureSampler", 0); // Texture unit 0
// Vertices for a quad
GLfloat vertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
// Texture coordinates (flipped vertically for QImage top-left origin)
GLfloat texCoords[] = {
0.0f, 1.0f, // Top-left of texture (maps to bottom-left of quad)
1.0f, 1.0f, // Top-right of texture (maps to bottom-right of quad)
0.0f, 0.0f, // Bottom-left of texture (maps to top-left of quad)
1.0f, 0.0f, // Bottom-right of texture (maps to top-right of quad)
};
_shaderProgram->setAttributeArray("vertices", vertices, 2);
_shaderProgram->enableAttributeArray("vertices");
_shaderProgram->setAttributeArray("texCoords", texCoords, 2);
_shaderProgram->enableAttributeArray("texCoords");
_functions->glActiveTexture(GL_TEXTURE0);
_texture->bind();
_functions->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
_shaderProgram->disableAttributeArray("vertices");
_shaderProgram->disableAttributeArray("texCoords");
_shaderProgram->release();
_fbo->release();
// Read pixels back from FBO
QImage scaledImage = _fbo->toImage();
scaledImage = scaledImage.flipped(Qt::Vertical); // Flip vertically again if needed
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
scaledImage.save(&buffer, "PNG"); // Save as PNG for now, can be optimized later
_hclient_p->sendImage(QString(ba.toBase64()));
_context->doneCurrent();
}
void HyperionGrabber::_setImgSize(int width, int height)

View File

@ -4,6 +4,14 @@
#include "hyperionclient.h"
#include "WaylandGrabber.h"
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>
#include <QVideoFrame>
#include <QOffscreenSurface>
class HyperionGrabber : public QObject
{
@ -21,10 +29,17 @@ private:
QString _hyperionPriority_m;
unsigned short _scale_m = 8;
QOpenGLContext *_context;
QOpenGLFramebufferObject *_fbo;
QOpenGLShaderProgram *_shaderProgram;
QOpenGLTexture *_texture;
QOpenGLFunctions *_functions;
QOffscreenSurface *_offscreenSurface;
QString _parseColorArr(QString, bool);
private slots:
void _inActivity();
void _processFrame(const QImage &frame);
void _processFrame(const QVideoFrame &frame);
void _setImgSize(int width, int height);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB