mirror of https://github.com/mgba-emu/mgba.git
Qt: Fix QCamera threading woes
This commit is contained in:
parent
ce9439031f
commit
9b7521ccea
|
@ -160,7 +160,8 @@ if(Qt5Multimedia_FOUND)
|
|||
list(APPEND SOURCE_FILES
|
||||
VideoDumper.cpp)
|
||||
if (WIN32 AND QT_STATIC)
|
||||
list(APPEND QT_LIBRARIES qtaudio_windows strmiids winmm)
|
||||
list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin
|
||||
strmiids winmm mfuuid mfplat mf ksguid dxva2 evr d3d9)
|
||||
endif()
|
||||
list(APPEND QT_LIBRARIES Qt5::Multimedia)
|
||||
list(APPEND QT_DEFINES BUILD_QT_MULTIMEDIA)
|
||||
|
@ -283,10 +284,12 @@ if(APPLE)
|
|||
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
get_target_property(QTCOCOA Qt5::QCocoaIntegrationPlugin LOCATION)
|
||||
get_target_property(COREAUDIO Qt5::CoreAudioPlugin LOCATION)
|
||||
get_target_property(QTAVFSERVICE Qt5::AVFServicePlugin LOCATION)
|
||||
set(BUNDLE_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.app)
|
||||
target_sources(${BINARY_NAME}-qt PRIVATE "${PLUGINS}")
|
||||
set_source_files_properties("${QTCOCOA}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
|
||||
set_source_files_properties("${COREAUDIO}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
|
||||
set_source_files_properties("${QTAVFSERVICE}" PROPERTIES MACOSX_PACKAGE_LOCATION Contents/PlugIns)
|
||||
install(CODE "
|
||||
include(BundleUtilities)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
|
@ -294,7 +297,7 @@ if(APPLE)
|
|||
fixup_bundle(\"${BUNDLE_PATH}\" \"${PLUGINS}\" \"\")
|
||||
" COMPONENT ${BINARY_NAME}-qt)
|
||||
else()
|
||||
set(DEPLOY_OPTIONS -p platforms/libqcocoa.dylib,audio/libqtaudio_coreaudio.dylib)
|
||||
set(DEPLOY_OPTIONS -p platforms/libqcocoa.dylib,audio/libqtaudio_coreaudio.dylib,mediaservice/libqavfcamera.dylib.dylib)
|
||||
if(NOT CMAKE_INSTALL_NAME_TOOL EQUAL "install_name_tool")
|
||||
set(DEPLOY_OPTIONS ${DEPLOY_OPTIONS} -I "${CMAKE_INSTALL_NAME_TOOL}")
|
||||
endif()
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QWidget>
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
#include <QCamera>
|
||||
#include <QVideoSurfaceFormat>
|
||||
#endif
|
||||
|
||||
#include <mgba/core/interface.h>
|
||||
|
@ -94,37 +95,9 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren
|
|||
if (image->image.isNull()) {
|
||||
image->image.load(":/res/no-cam.png");
|
||||
}
|
||||
image->resizedImage = image->image.scaled(w, h, Qt::KeepAspectRatioByExpanding);
|
||||
#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;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
|
||||
QCameraViewfinderSettings settings;
|
||||
QSize size(1920, 1080);
|
||||
auto cameraRes = image->p->m_camera->supportedViewfinderResolutions(settings);
|
||||
for (auto& cameraSize : cameraRes) {
|
||||
if (cameraSize.width() < w || cameraSize.height() < h) {
|
||||
continue;
|
||||
}
|
||||
if (cameraSize.width() <= size.width() && cameraSize.height() <= size.height()) {
|
||||
size = cameraSize;
|
||||
}
|
||||
}
|
||||
settings.setResolution(size);
|
||||
auto cameraFormats = image->p->m_camera->supportedViewfinderPixelFormats(settings);
|
||||
auto goodFormats = image->p->m_videoDumper.supportedPixelFormats();
|
||||
for (auto& format : goodFormats) {
|
||||
if (cameraFormats.contains(format)) {
|
||||
settings.setPixelFormat(format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
image->p->m_camera->setViewfinderSettings(settings);
|
||||
#endif
|
||||
image->p->m_camera->setViewfinder(&image->p->m_videoDumper);
|
||||
image->p->m_camera->start();
|
||||
QMetaObject::invokeMethod(image->p, "setupCam");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
@ -132,15 +105,15 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren
|
|||
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;
|
||||
}
|
||||
QMetaObject::invokeMethod(image->p, "teardownCam");
|
||||
#endif
|
||||
};
|
||||
|
||||
m_image.requestImage = [](mImageSource* context, const uint32_t** buffer, size_t* stride) {
|
||||
InputControllerImage* image = static_cast<InputControllerImage*>(context);
|
||||
if (image->resizedImage.isNull()) {
|
||||
image->resizedImage = image->image.scaled(image->w, image->h, Qt::KeepAspectRatioByExpanding);
|
||||
}
|
||||
image->resizedImage = image->resizedImage.convertToFormat(QImage::Format_RGB32);
|
||||
const uint32_t* bits = reinterpret_cast<const uint32_t*>(image->resizedImage.constBits());
|
||||
QSize size = image->resizedImage.size();
|
||||
|
@ -737,3 +710,48 @@ void InputController::setLuminanceValue(uint8_t value) {
|
|||
emit luminanceValueChanged(m_luxValue);
|
||||
}
|
||||
|
||||
void InputController::setupCam() {
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (!m_camera) {
|
||||
m_camera = std::make_unique<QCamera>();
|
||||
}
|
||||
QVideoFrame::PixelFormat format(QVideoFrame::Format_RGB32);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
|
||||
m_camera->load();
|
||||
QCameraViewfinderSettings settings;
|
||||
QSize size(1920, 1080);
|
||||
auto cameraRes = m_camera->supportedViewfinderResolutions(settings);
|
||||
for (auto& cameraSize : cameraRes) {
|
||||
if (cameraSize.width() < m_image.w || cameraSize.height() < m_image.h) {
|
||||
continue;
|
||||
}
|
||||
if (cameraSize.width() <= size.width() && cameraSize.height() <= size.height()) {
|
||||
size = cameraSize;
|
||||
}
|
||||
}
|
||||
settings.setResolution(size);
|
||||
auto cameraFormats = m_camera->supportedViewfinderPixelFormats(settings);
|
||||
auto goodFormats = m_videoDumper.supportedPixelFormats();
|
||||
for (auto& goodFormat : goodFormats) {
|
||||
if (cameraFormats.contains(goodFormat)) {
|
||||
settings.setPixelFormat(goodFormat);
|
||||
format = goodFormat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_camera->setViewfinderSettings(settings);
|
||||
#endif
|
||||
m_camera->setCaptureMode(QCamera::CaptureVideo);
|
||||
m_camera->setViewfinder(&m_videoDumper);
|
||||
m_camera->start();
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputController::teardownCam() {
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (m_camera) {
|
||||
m_camera->stop();
|
||||
m_camera.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <QTimer>
|
||||
#include <QVector>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <mgba/gba/interface.h>
|
||||
#include <mgba/internal/gba/input.h>
|
||||
|
||||
|
@ -121,6 +123,10 @@ public slots:
|
|||
void loadCamImage(const QString& path);
|
||||
void setCamImage(const QImage& image);
|
||||
|
||||
private slots:
|
||||
void setupCam();
|
||||
void teardownCam();
|
||||
|
||||
private:
|
||||
void postPendingEvent(GBAKey);
|
||||
void clearPendingEvent(GBAKey);
|
||||
|
@ -142,7 +148,7 @@ private:
|
|||
} m_image;
|
||||
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
QCamera* m_camera = nullptr;
|
||||
std::unique_ptr<QCamera> m_camera;
|
||||
VideoDumper m_videoDumper;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -20,12 +20,11 @@ bool VideoDumper::present(const QVideoFrame& frame) {
|
|||
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);
|
||||
uchar* bits = mappedFrame.bits();
|
||||
QImage image(bits, mappedFrame.width(), mappedFrame.height(), mappedFrame.bytesPerLine(), format);
|
||||
image = image.copy(); // Create a deep copy of the bits
|
||||
mappedFrame.unmap();
|
||||
emit imageAvailable(image);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
Q_IMPORT_PLUGIN(QWindowsAudioPlugin);
|
||||
Q_IMPORT_PLUGIN(DSServicePlugin);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue