citra/src/citra_qt/camera/qt_multimedia_camera.cpp

225 lines
8 KiB
C++
Raw Normal View History

citra_qt: camera integration (#3566) * Implement camera feature * Make OpenCVCamera optional * Fix styling problems * CI configuration * Fix CI * Hopefully final fix * Hopefully final fix * Fix all the problems * Oops.. * Add Qt Multimedia Camera * Another oops * Try to fix broken linux CI * Try to fix broken linux CI * Fix problems * Improve UI * Fix problems * camera: Add support for Qt <5.10 and fix preview error * CI: try to fix linux-frozen travis build * camera: fix problems and add multiple handlers support * fix CI * remove most ServiceFramework changes * Fix format * Remove last ServiceFramework change * camera: remove unused interfaces; revert submodule change * camera: fix CI error * ci: use ccache for opencv build * citra_qt: fix configuration error; CI: add mediaservice plugin * citra_qt: fix clang-format * citra_qt: fix documentation error * citra_qt: fix configuration page; camera: fix pausing crash * citra_qt: fix preview not stopping * camera: extend handlers length * camera: fix camera resume error * camera: fix clang-format * camera: remove all OpenCV; citra_qt: rewrite configuration * camera: remove all OpenCV; citra_qt: rewrite configuration * camera: remove all OpenCV; citra_qt: rewrite configuration * CI: fix linux ci * camera: check settings update; citra_qt: fix configuration error * service_cam: use a better way to apply configuration * Service_CAM: rewrite camera reload * cam: fix clang format * citra_qt: fix argument load issue; camera: base of system camera selection * citra_qt: Add system camera selection * camera: fix image upside down, Implement SetFrameRate in Qt Multimedia Camera * camera: Add missing <array> include, update SetFrameRate and add settings in Qt Multimedia Camera header * camera: move started in Qt Multimedia Camera header * QtMultimediaCamera: Move frame rates to SetFrameRate; Set minimum and maximum frame rate * Update appveyor.yml
2018-05-11 17:42:23 +00:00
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QCamera>
#include <QCameraInfo>
#include <QImageReader>
#include <QMessageBox>
#include <QThread>
#include "citra_qt/camera/qt_multimedia_camera.h"
#include "citra_qt/main.h"
namespace Camera {
QList<QVideoFrame::PixelFormat> QtCameraSurface::supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const {
Q_UNUSED(handleType);
return QList<QVideoFrame::PixelFormat>()
<< QVideoFrame::Format_ARGB32 << QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB32 << QVideoFrame::Format_RGB24 << QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555 << QVideoFrame::Format_ARGB8565_Premultiplied
<< QVideoFrame::Format_BGRA32 << QVideoFrame::Format_BGRA32_Premultiplied
<< QVideoFrame::Format_BGR32 << QVideoFrame::Format_BGR24 << QVideoFrame::Format_BGR565
<< QVideoFrame::Format_BGR555 << QVideoFrame::Format_BGRA5658_Premultiplied
<< QVideoFrame::Format_AYUV444 << QVideoFrame::Format_AYUV444_Premultiplied
<< QVideoFrame::Format_YUV444 << QVideoFrame::Format_YUV420P << QVideoFrame::Format_YV12
<< QVideoFrame::Format_UYVY << QVideoFrame::Format_YUYV << QVideoFrame::Format_NV12
<< QVideoFrame::Format_NV21 << QVideoFrame::Format_IMC1 << QVideoFrame::Format_IMC2
<< QVideoFrame::Format_IMC3 << QVideoFrame::Format_IMC4 << QVideoFrame::Format_Y8
<< QVideoFrame::Format_Y16 << QVideoFrame::Format_Jpeg << QVideoFrame::Format_CameraRaw
<< QVideoFrame::Format_AdobeDng; // Supporting all the formats
}
bool QtCameraSurface::present(const QVideoFrame& frame) {
if (!frame.isValid()) {
return false;
}
QVideoFrame cloneFrame(frame);
cloneFrame.map(QAbstractVideoBuffer::ReadOnly);
const QImage image(cloneFrame.bits(), cloneFrame.width(), cloneFrame.height(),
QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat()));
QMutexLocker locker(&mutex);
current_frame = image.mirrored(true, true);
locker.unlock();
cloneFrame.unmap();
return true;
}
QtMultimediaCamera::QtMultimediaCamera(const std::string& camera_name)
: handler(QtMultimediaCameraHandler::GetHandler()) {
if (handler->thread() == QThread::currentThread()) {
handler->CreateCamera(camera_name);
} else {
QMetaObject::invokeMethod(handler.get(), "CreateCamera", Qt::BlockingQueuedConnection,
Q_ARG(const std::string&, camera_name));
}
}
QtMultimediaCamera::~QtMultimediaCamera() {
handler->StopCamera();
QtMultimediaCameraHandler::ReleaseHandler(handler);
}
void QtMultimediaCamera::StartCapture() {
if (handler->thread() == QThread::currentThread()) {
handler->StartCamera();
} else {
QMetaObject::invokeMethod(handler.get(), "StartCamera", Qt::BlockingQueuedConnection);
}
}
void QtMultimediaCamera::StopCapture() {
handler->StopCamera();
}
void QtMultimediaCamera::SetFormat(Service::CAM::OutputFormat output_format) {
output_rgb = output_format == Service::CAM::OutputFormat::RGB565;
}
void QtMultimediaCamera::SetFrameRate(Service::CAM::FrameRate frame_rate) {
const std::array<QCamera::FrameRateRange, 13> FrameRateList = {
/* Rate_15 */ QCamera::FrameRateRange(15, 15),
/* Rate_15_To_5 */ QCamera::FrameRateRange(5, 15),
/* Rate_15_To_2 */ QCamera::FrameRateRange(2, 15),
/* Rate_10 */ QCamera::FrameRateRange(10, 10),
/* Rate_8_5 */ QCamera::FrameRateRange(8.5, 8.5),
/* Rate_5 */ QCamera::FrameRateRange(5, 5),
/* Rate_20 */ QCamera::FrameRateRange(20, 20),
/* Rate_20_To_5 */ QCamera::FrameRateRange(5, 20),
/* Rate_30 */ QCamera::FrameRateRange(30, 30),
/* Rate_30_To_5 */ QCamera::FrameRateRange(5, 30),
/* Rate_15_To_10 */ QCamera::FrameRateRange(10, 15),
/* Rate_20_To_10 */ QCamera::FrameRateRange(10, 20),
/* Rate_30_To_10 */ QCamera::FrameRateRange(10, 30),
};
auto framerate = FrameRateList[static_cast<int>(frame_rate)];
handler->settings.setMinimumFrameRate(framerate.minimumFrameRate);
handler->settings.setMinimumFrameRate(framerate.maximumFrameRate);
}
void QtMultimediaCamera::SetResolution(const Service::CAM::Resolution& resolution) {
width = resolution.width;
height = resolution.height;
}
void QtMultimediaCamera::SetFlip(Service::CAM::Flip flip) {
using namespace Service::CAM;
flip_horizontal = (flip == Flip::Horizontal) || (flip == Flip::Reverse);
flip_vertical = (flip == Flip::Vertical) || (flip == Flip::Reverse);
}
void QtMultimediaCamera::SetEffect(Service::CAM::Effect effect) {
if (effect != Service::CAM::Effect::None) {
NGLOG_ERROR(Service_CAM, "Unimplemented effect {}", static_cast<int>(effect));
}
}
std::vector<u16> QtMultimediaCamera::ReceiveFrame() {
QMutexLocker locker(&handler->camera_surface.mutex);
return CameraUtil::ProcessImage(handler->camera_surface.current_frame, width, height,
output_rgb, flip_horizontal, flip_vertical);
}
bool QtMultimediaCamera::IsPreviewAvailable() {
return handler->CameraAvailable();
}
std::unique_ptr<CameraInterface> QtMultimediaCameraFactory::Create(
const std::string& config) const {
return std::make_unique<QtMultimediaCamera>(config);
}
std::array<std::shared_ptr<QtMultimediaCameraHandler>, 3> QtMultimediaCameraHandler::handlers;
std::array<bool, 3> QtMultimediaCameraHandler::status;
void QtMultimediaCameraHandler::Init() {
for (auto& handler : handlers) {
handler = std::make_shared<QtMultimediaCameraHandler>();
}
}
std::shared_ptr<QtMultimediaCameraHandler> QtMultimediaCameraHandler::GetHandler() {
for (int i = 0; i < handlers.size(); i++) {
if (!status[i]) {
NGLOG_INFO(Service_CAM, "Successfully got handler {}", i);
status[i] = true;
return handlers[i];
}
}
NGLOG_CRITICAL(Service_CAM, "All handlers taken up");
return nullptr;
}
void QtMultimediaCameraHandler::ReleaseHandler(
const std::shared_ptr<Camera::QtMultimediaCameraHandler>& handler) {
for (int i = 0; i < handlers.size(); i++) {
if (handlers[i] == handler) {
NGLOG_INFO(Service_CAM, "Successfully released handler {}", i);
status[i] = false;
handlers[i]->started = false;
break;
}
}
}
void QtMultimediaCameraHandler::CreateCamera(const std::string& camera_name) {
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
for (const QCameraInfo& cameraInfo : cameras) {
if (cameraInfo.deviceName().toStdString() == camera_name)
camera = std::make_unique<QCamera>(cameraInfo);
}
if (!camera) { // no cameras found, using default camera
camera = std::make_unique<QCamera>();
}
settings.setMinimumFrameRate(30);
settings.setMaximumFrameRate(30);
camera->setViewfinder(&camera_surface);
}
void QtMultimediaCameraHandler::StopCamera() {
camera->stop();
started = false;
}
void QtMultimediaCameraHandler::StartCamera() {
camera->setViewfinderSettings(settings);
camera->start();
started = true;
}
bool QtMultimediaCameraHandler::CameraAvailable() const {
return camera && camera->isAvailable();
}
void QtMultimediaCameraHandler::StopCameras() {
NGLOG_INFO(Service_CAM, "Stopping all cameras");
for (auto& handler : handlers) {
if (handler && handler->started) {
handler->StopCamera();
}
}
}
void QtMultimediaCameraHandler::ResumeCameras() {
for (auto& handler : handlers) {
if (handler && handler->started) {
handler->StartCamera();
}
}
}
void QtMultimediaCameraHandler::ReleaseHandlers() {
StopCameras();
NGLOG_INFO(Service_CAM, "Releasing all handlers");
for (int i = 0; i < handlers.size(); i++) {
status[i] = false;
handlers[i]->started = false;
}
}
} // namespace Camera