all repos — mgba @ cf15ea91d7743dac546f4bfed2f305c4fd5e6216

mGBA Game Boy Advance Emulator

Qt: Preliminary QCamera support
Vicki Pfau vi@endrift.com
Wed, 26 Jul 2017 13:51:30 -0700
commit

cf15ea91d7743dac546f4bfed2f305c4fd5e6216

parent

a1acf8bcef00cbc2c3a8f7506d6e9db70a943c28

M src/platform/qt/CMakeLists.txtsrc/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()
M src/platform/qt/InputController.cppsrc/platform/qt/InputController.cpp

@@ -13,6 +13,9 @@

#include <QApplication> #include <QTimer> #include <QWidget> +#ifdef BUILD_QT_MULTIMEDIA +#include <QCamera> +#endif #include <mgba/core/interface.h> #include <mgba-util/configuration.h>

@@ -53,6 +56,10 @@ #endif

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 @@ };

setLuminanceLevel(0); #endif + m_image.p = this; m_image.startRequestImage = [](mImageSource* context) { InputControllerImage* image = static_cast<InputControllerImage*>(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<int>(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<InputControllerImage*>(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<InputControllerImage*>(context); image->resizedImage = image->image.scaled(w, h, Qt::KeepAspectRatioByExpanding);

@@ -647,6 +674,11 @@ }

void InputController::loadCamImage(const QString& path) { m_image.image.load(path); + m_image.resizedImage = QImage(); +} + +void InputController::setCamImage(const QImage& image) { + m_image.image = image; m_image.resizedImage = QImage(); }
M src/platform/qt/InputController.hsrc/platform/qt/InputController.h

@@ -22,9 +22,16 @@ #ifdef BUILD_SDL

#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 @@

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 @@ void decreaseLuminanceLevel();

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);

@@ -124,6 +139,11 @@ InputController* p;

QImage image; QImage resizedImage; } m_image; + +#ifdef BUILD_QT_MULTIMEDIA + QCamera* m_camera = nullptr; + VideoDumper m_videoDumper; +#endif mInputMap m_inputMap; ConfigController* m_config = nullptr;
A 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 <QImage> + +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<QVideoFrame::PixelFormat> VideoDumper::supportedPixelFormats(QAbstractVideoBuffer::HandleType) const { + QList<QVideoFrame::PixelFormat> 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; +}
A 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 <QAbstractVideoSurface> + +namespace QGBA { + +class VideoDumper : public QAbstractVideoSurface { +Q_OBJECT + +public: + VideoDumper(QObject* parent = nullptr); + + bool present(const QVideoFrame& frame) override; + QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType type = QAbstractVideoBuffer::NoHandle) const override; + +signals: + void imageAvailable(const QImage& image); +}; + +} + +#endif