Qt: Fix QCamera threading woes

This commit is contained in:
Vicki Pfau 2017-07-26 23:15:50 -07:00
parent ce9439031f
commit 9b7521ccea
5 changed files with 68 additions and 41 deletions

View File

@ -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()

View File

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

View File

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

View File

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

View File

@ -23,6 +23,7 @@
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
#ifdef BUILD_QT_MULTIMEDIA
Q_IMPORT_PLUGIN(QWindowsAudioPlugin);
Q_IMPORT_PLUGIN(DSServicePlugin);
#endif
#endif
#endif