From cf15ea91d7743dac546f4bfed2f305c4fd5e6216 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 26 Jul 2017 13:51:30 -0700 Subject: [PATCH] Qt: Preliminary QCamera support --- src/platform/qt/CMakeLists.txt | 2 ++ src/platform/qt/InputController.cpp | 34 +++++++++++++++++++++++- src/platform/qt/InputController.h | 24 +++++++++++++++-- src/platform/qt/VideoDumper.cpp | 41 +++++++++++++++++++++++++++++ src/platform/qt/VideoDumper.h | 27 +++++++++++++++++++ 5 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 src/platform/qt/VideoDumper.cpp create mode 100644 src/platform/qt/VideoDumper.h diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index dc1468c99..eb1ca8587 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -157,6 +157,8 @@ if(Qt5Multimedia_FOUND) list(APPEND AUDIO_SRC AudioProcessorQt.cpp AudioDevice.cpp) + list(APPEND SOURCE_FILES + VideoDumper.cpp) if (WIN32 AND QT_STATIC) list(APPEND QT_LIBRARIES qtaudio_windows strmiids winmm) endif() diff --git a/src/platform/qt/InputController.cpp b/src/platform/qt/InputController.cpp index 7ffa47d1a..2ca1b65d6 100644 --- a/src/platform/qt/InputController.cpp +++ b/src/platform/qt/InputController.cpp @@ -13,6 +13,9 @@ #include #include #include +#ifdef BUILD_QT_MULTIMEDIA +#include +#endif #include #include @@ -53,6 +56,10 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren m_gamepadTimer.setInterval(50); m_gamepadTimer.start(); +#ifdef BUILD_QT_MULTIMEDIA + connect(&m_videoDumper, &VideoDumper::imageAvailable, this, &InputController::setCamImage); +#endif + mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_X, GBA_KEY_A); mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_Z, GBA_KEY_B); mInputBindKey(&m_inputMap, KEYBOARD, Qt::Key_A, GBA_KEY_L); @@ -79,13 +86,33 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren setLuminanceLevel(0); #endif + m_image.p = this; m_image.startRequestImage = [](mImageSource* context) { InputControllerImage* image = static_cast(context); if (image->image.isNull()) { image->image.load(":/res/no-cam.png"); } +#ifdef BUILD_QT_MULTIMEDIA + if (image->p->m_config->getQtOption("cameraDriver").toInt() == static_cast(CameraDriver::QT_MULTIMEDIA)) { + if (!image->p->m_camera) { + image->p->m_camera = new QCamera; + } + image->p->m_camera->setViewfinder(&image->p->m_videoDumper); + image->p->m_camera->start(); + } +#endif }; - m_image.stopRequestImage = nullptr; + + m_image.stopRequestImage = [](mImageSource* context) { + InputControllerImage* image = static_cast(context); +#ifdef BUILD_QT_MULTIMEDIA + if (image->p->m_camera) { + image->p->m_camera->stop(); + delete image->p->m_camera; + } +#endif + }; + m_image.requestImage = [](mImageSource* context, unsigned w, unsigned h, const uint32_t** buffer, size_t* stride) { InputControllerImage* image = static_cast(context); image->resizedImage = image->image.scaled(w, h, Qt::KeepAspectRatioByExpanding); @@ -650,6 +677,11 @@ void InputController::loadCamImage(const QString& path) { m_image.resizedImage = QImage(); } +void InputController::setCamImage(const QImage& image) { + m_image.image = image; + m_image.resizedImage = QImage(); +} + void InputController::increaseLuminanceLevel() { setLuminanceLevel(m_luxLevel + 1); } diff --git a/src/platform/qt/InputController.h b/src/platform/qt/InputController.h index b5efea9f5..0da15dcd0 100644 --- a/src/platform/qt/InputController.h +++ b/src/platform/qt/InputController.h @@ -22,9 +22,16 @@ #include "platform/sdl/sdl-events.h" #endif + +#ifdef BUILD_QT_MULTIMEDIA +#include "VideoDumper.h" +#endif + struct mRotationSource; struct mRumble; +class QCamera; + namespace QGBA { class ConfigController; @@ -33,6 +40,13 @@ class InputController : public QObject { Q_OBJECT public: + enum class CameraDriver : int { + NONE = 0, +#ifdef BUILD_QT_MULTIMEDIA + QT_MULTIMEDIA = 1, +#endif + }; + static const uint32_t KEYBOARD = 0x51545F4B; InputController(int playerId = 0, QWidget* topLevel = nullptr, QObject* parent = nullptr); @@ -81,8 +95,6 @@ public: void stealFocus(QWidget* focus); void releaseFocus(QWidget* focus); - void loadCamImage(const QString& path); - mRumble* rumble(); mRotationSource* rotationSource(); mImageSource* imageSource() { return &m_image; } @@ -106,6 +118,9 @@ public slots: void setLuminanceLevel(int level); void setLuminanceValue(uint8_t value); + void loadCamImage(const QString& path); + void setCamImage(const QImage& image); + private: void postPendingEvent(GBAKey); void clearPendingEvent(GBAKey); @@ -125,6 +140,11 @@ private: QImage resizedImage; } m_image; +#ifdef BUILD_QT_MULTIMEDIA + QCamera* m_camera = nullptr; + VideoDumper m_videoDumper; +#endif + mInputMap m_inputMap; ConfigController* m_config = nullptr; int m_playerId; diff --git a/src/platform/qt/VideoDumper.cpp b/src/platform/qt/VideoDumper.cpp new file mode 100644 index 000000000..a036c6a2f --- /dev/null +++ b/src/platform/qt/VideoDumper.cpp @@ -0,0 +1,41 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "VideoDumper.h" + +#include + +using namespace QGBA; + +VideoDumper::VideoDumper(QObject* parent) + : QAbstractVideoSurface(parent) +{ +} + +bool VideoDumper::present(const QVideoFrame& frame) { + QVideoFrame mappedFrame(frame); + if (!mappedFrame.map(QAbstractVideoBuffer::ReadOnly)) { + return false; + } + QImage::Format format = QVideoFrame::imageFormatFromPixelFormat(mappedFrame.pixelFormat()); + const uchar* bits = mappedFrame.bits(); + QImage image(bits, mappedFrame.width(), mappedFrame.height(), mappedFrame.bytesPerLine(), + format); + image = std::move(image.copy()); // Create a deep copy of the bits + emit imageAvailable(image); + mappedFrame.unmap(); + return true; +} + +QList VideoDumper::supportedPixelFormats(QAbstractVideoBuffer::HandleType) const { + QList list; + list.append(QVideoFrame::Format_ARGB32); + list.append(QVideoFrame::Format_ARGB32_Premultiplied); + list.append(QVideoFrame::Format_RGB32); + list.append(QVideoFrame::Format_RGB24); + list.append(QVideoFrame::Format_RGB565); + list.append(QVideoFrame::Format_RGB555); + return list; +} diff --git a/src/platform/qt/VideoDumper.h b/src/platform/qt/VideoDumper.h new file mode 100644 index 000000000..f2deb1044 --- /dev/null +++ b/src/platform/qt/VideoDumper.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef QGBA_VIDEO_DUMPER +#define QGBA_VIDEO_DUMPER +#include + +namespace QGBA { + +class VideoDumper : public QAbstractVideoSurface { +Q_OBJECT + +public: + VideoDumper(QObject* parent = nullptr); + + bool present(const QVideoFrame& frame) override; + QList supportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const override; + +signals: + void imageAvailable(const QImage& image); +}; + +} + +#endif