From 81c216f3303f26d349af856be3cc424aee2ad889 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 17 Oct 2021 15:35:30 +0200 Subject: [PATCH] cellCamera: add error handling to qt camera --- rpcs3/Emu/Cell/Modules/cellCamera.cpp | 116 +++++++++++++------- rpcs3/Emu/Cell/Modules/cellCamera.h | 1 + rpcs3/Emu/Cell/Modules/cellGem.cpp | 2 +- rpcs3/Emu/Io/Null/null_camera_handler.h | 12 +- rpcs3/Emu/Io/camera_handler_base.h | 5 +- rpcs3/rpcs3.vcxproj | 17 +++ rpcs3/rpcs3.vcxproj.filters | 12 ++ rpcs3/rpcs3qt/CMakeLists.txt | 1 + rpcs3/rpcs3qt/qt_camera_error_handler.cpp | 58 ++++++++++ rpcs3/rpcs3qt/qt_camera_error_handler.h | 25 +++++ rpcs3/rpcs3qt/qt_camera_handler.cpp | 127 ++++++++-------------- rpcs3/rpcs3qt/qt_camera_handler.h | 17 +-- 12 files changed, 254 insertions(+), 139 deletions(-) create mode 100644 rpcs3/rpcs3qt/qt_camera_error_handler.cpp create mode 100644 rpcs3/rpcs3qt/qt_camera_error_handler.h diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp index dcecaad327..fc20f7d6c0 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -1328,17 +1328,6 @@ error_code cellCameraReadEx(s32 dev_num, vm::ptr read) // can call cellCameraReset() and cellCameraStop() in some cases - if (read) // NULL returns CELL_OK - { - read->timestamp = (get_guest_system_time() - g_camera.start_timestamp); - read->frame = g_camera.frame_num; - read->bytesread = g_camera.is_streaming ? get_video_buffer_size(g_camera.info) : 0; - - auto& shared_data = g_fxo->get(); - - shared_data.frame_timestamp.exchange(read->timestamp); - } - if (g_camera.handler) { u32 width{}; @@ -1347,7 +1336,7 @@ error_code cellCameraReadEx(s32 dev_num, vm::ptr read) u64 bytes_read{}; atomic_t wake_up = false; - bool result = false; + camera_handler_base::camera_handler_state result = camera_handler_base::camera_handler_state::not_available; Emu.CallAfter([&]() { @@ -1361,10 +1350,9 @@ error_code cellCameraReadEx(s32 dev_num, vm::ptr read) thread_ctrl::wait_on(wake_up, false); } - if (!result) + if (error_code error = g_camera.on_handler_state(result); error != CELL_OK) { - g_camera.send_attach_state(false); - return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND; + return error; } if (read) @@ -1377,6 +1365,21 @@ error_code cellCameraReadEx(s32 dev_num, vm::ptr read) frame_number, width, height, bytes_read, read ? read->frame.get() : 0, read ? read->bytesread.get() : 0); } + if (read) // NULL returns CELL_OK + { + read->timestamp = (get_guest_system_time() - g_camera.start_timestamp); + + if (!g_camera.handler) + { + read->frame = g_camera.frame_num; + read->bytesread = g_camera.is_streaming ? get_video_buffer_size(g_camera.info) : 0; + } + + auto& shared_data = g_fxo->get(); + + shared_data.frame_timestamp.exchange(read->timestamp); + } + return CELL_OK; } @@ -1624,7 +1627,7 @@ void camera_context::operator()() if (handler && send_frame_update_event) { atomic_t wake_up = false; - bool result = false; + camera_handler_base::camera_handler_state result = camera_handler_base::camera_handler_state::not_available; Emu.CallAfter([&]() { @@ -1645,15 +1648,12 @@ void camera_context::operator()() pbuf_write_index = pbuf_next_index(); - if (!result) - { - send_attach_state(false); - } + send_frame_update_event = on_handler_state(result) = CELL_OK; } } else { - send_frame_update_event = true; + send_frame_update_event = on_handler_state(handler->get_state()) = CELL_OK; } } @@ -1731,32 +1731,21 @@ void camera_context::reset_state() void camera_context::send_attach_state(bool attached) { - if (!attached) - { - is_streaming = false; - is_open = false; - } - std::lock_guard lock(mutex_notify_data_map); - if (!notify_data_map.empty()) + for (const auto& [key, evt_data] : notify_data_map) { - for (const auto& [key, evt_data] : notify_data_map) + if (auto queue = lv2_event_queue::find(key)) { - if (auto queue = lv2_event_queue::find(key)) + if (queue->send(evt_data.source, attached ? CELL_CAMERA_ATTACH : CELL_CAMERA_DETACH, 0, 0) == 0) [[likely]] { - if (queue->send(evt_data.source, attached ? CELL_CAMERA_ATTACH : CELL_CAMERA_DETACH, 0, 0) == 0) [[likely]] - { - is_attached = attached; - } + is_attached = attached; } } } - else - { - // We're not expected to send any events for attaching/detaching - is_attached = attached; - } + + // We're not expected to send any events for attaching/detaching + is_attached = attached; } void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2) @@ -1817,3 +1806,52 @@ u32 camera_context::pbuf_next_index() const // The read buffer index cannot be the same as the write index return (pbuf_write_index + 1u) % 2; } + +error_code camera_context::on_handler_state(camera_handler_base::camera_handler_state state) +{ + switch (state) + { + case camera_handler_base::camera_handler_state::not_available: + case camera_handler_base::camera_handler_state::closed: + { + if (is_attached) + { + send_attach_state(false); + } + if (handler) + { + if (is_streaming) + { + cellCamera.warning("Camera closed or disconnected (state=%d). Trying to start camera...", static_cast(state)); + handler->start_camera(); + } + else if (is_open) + { + cellCamera.warning("Camera closed or disconnected (state=%d). Trying to open camera...", static_cast(state)); + handler->open_camera(); + } + } + return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND; + } + case camera_handler_base::camera_handler_state::running: + { + if (!is_attached) + { + cellCamera.warning("Camera handler not attached. Sending attach event...", static_cast(state)); + send_attach_state(true); + } + break; + } + case camera_handler_base::camera_handler_state::open: + { + if (handler && is_streaming) + { + cellCamera.warning("Camera handler not running (state=%d). Trying to start camera...", static_cast(state)); + handler->start_camera(); + } + break; + } + } + + return CELL_OK; +} diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.h b/rpcs3/Emu/Cell/Modules/cellCamera.h index 7b4b9f2519..6ec75a66fb 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.h +++ b/rpcs3/Emu/Cell/Modules/cellCamera.h @@ -442,6 +442,7 @@ public: static constexpr auto thread_name = "Camera Thread"sv; std::shared_ptr handler; + error_code on_handler_state(camera_handler_base::camera_handler_state state); }; using camera_thread = named_thread; diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 1412ae5c20..aba700babe 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -1351,7 +1351,7 @@ error_code cellGemPrepareVideoConvert(vm::cptr vc_ return CELL_GEM_ERROR_INVALID_PARAMETER; } - const auto vc = *vc_attribute; + const CellGemVideoConvertAttribute vc = *vc_attribute; if (!vc_attribute || vc.version != CELL_GEM_VERSION) { diff --git a/rpcs3/Emu/Io/Null/null_camera_handler.h b/rpcs3/Emu/Io/Null/null_camera_handler.h index c0bd2d0bc2..b7450eff93 100644 --- a/rpcs3/Emu/Io/Null/null_camera_handler.h +++ b/rpcs3/Emu/Io/Null/null_camera_handler.h @@ -7,10 +7,10 @@ class null_camera_handler final : public camera_handler_base public: null_camera_handler() : camera_handler_base() {} - void open_camera() override {}; - void close_camera() override {}; - void start_camera() override {}; - void stop_camera() override {}; + void open_camera() override { m_state = camera_handler_state::open; }; + void close_camera() override { m_state = camera_handler_state::closed; }; + void start_camera() override { m_state = camera_handler_state::running; }; + void stop_camera() override { m_state = camera_handler_state::open; }; void set_format(s32 format, u32 bytes_per_pixel) override { @@ -39,12 +39,12 @@ public: return 0; } - bool get_image(u8* /*buf*/, u64 /*size*/, u32& width, u32& height, u64& frame_number, u64& bytes_read) override + camera_handler_state get_image(u8* /*buf*/, u64 /*size*/, u32& width, u32& height, u64& frame_number, u64& bytes_read) override { width = 0; height = 0; frame_number = 0; bytes_read = 0; - return true; + return m_state; } }; diff --git a/rpcs3/Emu/Io/camera_handler_base.h b/rpcs3/Emu/Io/camera_handler_base.h index c421c9e58d..5329e77398 100644 --- a/rpcs3/Emu/Io/camera_handler_base.h +++ b/rpcs3/Emu/Io/camera_handler_base.h @@ -8,6 +8,7 @@ class camera_handler_base public: enum class camera_handler_state { + not_available, closed, open, running @@ -26,13 +27,13 @@ public: virtual void set_mirrored(bool mirrored) = 0; virtual u64 frame_number() const = 0; // Convenience function to check if there's a new frame. - virtual bool get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) = 0; + virtual camera_handler_state get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) = 0; camera_handler_state get_state() const { return m_state.load(); }; protected: std::mutex m_mutex; - atomic_t m_state = camera_handler_state::closed; + atomic_t m_state = camera_handler_state::not_available; bool m_mirrored = false; s32 m_format = 2; // CELL_CAMERA_RAW8 u32 m_bytes_per_pixel = 1; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index f4832f178c..2c2a34b3e9 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -303,6 +303,9 @@ true + + true + true @@ -501,6 +504,9 @@ true + + true + true @@ -594,6 +600,7 @@ + @@ -1090,6 +1097,16 @@ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 143c58fbfe..8cf6530b2f 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -786,6 +786,15 @@ Io\camera + + Io\camera + + + Generated Files\Debug + + + Generated Files\Release + @@ -1153,6 +1162,9 @@ Gui\message dialog + + Io\camera + diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index 78a011755c..3200de5c76 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -49,6 +49,7 @@ set(SRC_FILES persistent_settings.cpp pkg_install_dialog.cpp progress_dialog.cpp + qt_camera_error_handler.cpp qt_camera_handler.cpp qt_camera_video_surface.cpp qt_utils.cpp diff --git a/rpcs3/rpcs3qt/qt_camera_error_handler.cpp b/rpcs3/rpcs3qt/qt_camera_error_handler.cpp new file mode 100644 index 0000000000..cba2da863f --- /dev/null +++ b/rpcs3/rpcs3qt/qt_camera_error_handler.cpp @@ -0,0 +1,58 @@ +#include "stdafx.h" +#include "qt_camera_error_handler.h" + +LOG_CHANNEL(camera_log, "Camera"); + +qt_camera_error_handler::qt_camera_error_handler(std::shared_ptr camera, std::function status_callback) + : m_camera(std::move(camera)) + , m_status_callback(std::move(status_callback)) +{ + if (m_camera) + { + connect(m_camera.get(), QOverload::of(&QCamera::availabilityChanged), this, &qt_camera_error_handler::handle_availability); + connect(m_camera.get(), &QCamera::stateChanged, this, &qt_camera_error_handler::handle_camera_state); + connect(m_camera.get(), &QCamera::statusChanged, this, &qt_camera_error_handler::handle_camera_status); + connect(m_camera.get(), &QCamera::errorOccurred, this, &qt_camera_error_handler::handle_camera_error); + connect(m_camera.get(), &QCamera::captureModeChanged, this, &qt_camera_error_handler::handle_capture_modes); + connect(m_camera.get(), QOverload::of(&QCamera::lockStatusChanged), this, &qt_camera_error_handler::handle_lock_status); + } +} + +qt_camera_error_handler::~qt_camera_error_handler() +{ +} + +void qt_camera_error_handler::handle_availability(QMultimedia::AvailabilityStatus availability) +{ + camera_log.notice("Camera availability changed to %d", static_cast(availability)); +} + +void qt_camera_error_handler::handle_camera_state(QCamera::State state) +{ + camera_log.notice("Camera state changed to %d", static_cast(state)); +} + +void qt_camera_error_handler::handle_camera_status(QCamera::Status status) +{ + camera_log.notice("Camera status changed to %d", static_cast(status)); + + if (m_status_callback) + { + m_status_callback(status); + } +} + +void qt_camera_error_handler::handle_lock_status(QCamera::LockStatus status, QCamera::LockChangeReason reason) +{ + camera_log.notice("Camera lock status changed to %d (reason=%d)", static_cast(status), static_cast(reason)); +} + +void qt_camera_error_handler::handle_capture_modes(QCamera::CaptureModes capture_modes) +{ + camera_log.notice("Camera capture modes changed to %d", static_cast(capture_modes)); +} + +void qt_camera_error_handler::handle_camera_error(QCamera::Error error) +{ + camera_log.error("Error event: \"%s\" (error=%d)", m_camera ? m_camera->errorString().toStdString() : "", static_cast(error)); +} diff --git a/rpcs3/rpcs3qt/qt_camera_error_handler.h b/rpcs3/rpcs3qt/qt_camera_error_handler.h new file mode 100644 index 0000000000..cf97a120be --- /dev/null +++ b/rpcs3/rpcs3qt/qt_camera_error_handler.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +class qt_camera_error_handler : public QObject +{ + Q_OBJECT + +public: + qt_camera_error_handler(std::shared_ptr camera, std::function status_callback); + virtual ~qt_camera_error_handler(); + +private Q_SLOTS: + void handle_availability(QMultimedia::AvailabilityStatus availability); + void handle_lock_status(QCamera::LockStatus, QCamera::LockChangeReason); + void handle_capture_modes(QCamera::CaptureModes capture_modes); + void handle_camera_state(QCamera::State state); + void handle_camera_status(QCamera::Status status); + void handle_camera_error(QCamera::Error error); + +private: + std::shared_ptr m_camera; + std::function m_status_callback = nullptr; +}; diff --git a/rpcs3/rpcs3qt/qt_camera_handler.cpp b/rpcs3/rpcs3qt/qt_camera_handler.cpp index f0677e1e22..ce592a1be8 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.cpp +++ b/rpcs3/rpcs3qt/qt_camera_handler.cpp @@ -32,21 +32,37 @@ void qt_camera_handler::set_camera(const QCameraInfo& cameraInfo) // Create camera and video surface m_surface.reset(new qt_camera_video_surface(front_facing, nullptr)); m_camera.reset(new QCamera(cameraInfo)); - - // Create connects (may not work due to threading) - connect(m_camera.get(), &QCamera::stateChanged, this, [this](QCamera::State state){ handle_camera_state(state); }); - connect(m_camera.get(), &QCamera::statusChanged, this, [this](QCamera::Status status){ handle_camera_status(status); }); - connect(m_camera.get(), &QCamera::errorOccurred, this, [this](QCamera::Error error){ handle_camera_error(error); }); - connect(m_camera.get(), &QCamera::captureModeChanged, this, [this](QCamera::CaptureModes modes){ handle_capture_modes(modes); }); - connect(m_camera.get(), QOverload::of(&QCamera::lockStatusChanged), this, [this](QCamera::LockStatus status, QCamera::LockChangeReason reason){ handle_lock_status(status, reason); }); + m_error_handler.reset(new qt_camera_error_handler(m_camera, + [this](QCamera::Status status) + { + switch (status) + { + case QCamera::UnavailableStatus: + m_state = camera_handler_state::not_available; + break; + case QCamera::UnloadedStatus: + case QCamera::UnloadingStatus: + m_state = camera_handler_state::closed; + break; + case QCamera::StandbyStatus: + case QCamera::StoppingStatus: + case QCamera::LoadedStatus: + case QCamera::LoadingStatus: + m_state = camera_handler_state::open; + break; + case QCamera::StartingStatus: + case QCamera::ActiveStatus: + m_state = camera_handler_state::running; + break; + default: + camera_log.error("Ignoring unknown status %d", static_cast(status)); + break; + } + })); // Set view finder and update the settings m_camera->setViewfinder(m_surface.get()); update_camera_settings(); - - // Log some states - handle_camera_state(m_camera->state()); - handle_lock_status(m_camera->lockStatus(), QCamera::UserRequest); } void qt_camera_handler::open_camera() @@ -65,7 +81,7 @@ void qt_camera_handler::open_camera() if (!m_camera) { camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + m_state = camera_handler_state::not_available; return; } @@ -93,8 +109,6 @@ void qt_camera_handler::open_camera() // Update camera and view finder settings update_camera_settings(); - - m_state = camera_handler_state::open; } void qt_camera_handler::close_camera() @@ -104,7 +118,7 @@ void qt_camera_handler::close_camera() if (!m_camera) { camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + m_state = camera_handler_state::not_available; return; } @@ -115,7 +129,6 @@ void qt_camera_handler::close_camera() // Unload/close camera m_camera->unload(); - m_state = camera_handler_state::closed; } void qt_camera_handler::start_camera() @@ -125,7 +138,7 @@ void qt_camera_handler::start_camera() if (!m_camera) { camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + m_state = camera_handler_state::not_available; return; } @@ -141,7 +154,6 @@ void qt_camera_handler::start_camera() // Start camera. We will start receiving frames now. m_camera->start(); - m_state = camera_handler_state::running; } void qt_camera_handler::stop_camera() @@ -151,7 +163,7 @@ void qt_camera_handler::stop_camera() if (!m_camera) { camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + m_state = camera_handler_state::not_available; return; } @@ -162,7 +174,6 @@ void qt_camera_handler::stop_camera() // Stop camera. The camera will still be drawing power. m_camera->stop(); - m_state = camera_handler_state::open; } void qt_camera_handler::set_format(s32 format, u32 bytes_per_pixel) @@ -200,53 +211,34 @@ u64 qt_camera_handler::frame_number() const return m_surface ? m_surface->frame_number() : 0; } -bool qt_camera_handler::get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) +camera_handler_base::camera_handler_state qt_camera_handler::get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) { width = 0; height = 0; frame_number = 0; bytes_read = 0; - // Check for errors - if (!m_camera || !m_surface || m_state != camera_handler_state::running) + if (!m_camera || !m_surface) { - camera_log.error("Error: camera invalid"); - m_state = camera_handler_state::closed; - return false; + camera_log.fatal("Error: camera invalid"); + m_state = camera_handler_state::not_available; + return camera_handler_state::not_available; } - if (QCamera::Error error = m_camera->error(); error != QCamera::NoError) + // Backup current state. State may change through events. + const camera_handler_state current_state = m_state; + + if (current_state == camera_handler_state::running) { - camera_log.error("Error: \"%s\" (error=%d)", m_camera ? m_camera->errorString().toStdString() : "", static_cast(error)); - m_state = camera_handler_state::closed; - return false; + // Copy latest image into out buffer. + m_surface->get_image(buf, size, width, height, frame_number, bytes_read); + } + else + { + camera_log.error("Camera not running (m_state=%d)", static_cast(current_state)); } - switch (QCamera::Status status = m_camera->status()) - { - case QCamera::UnavailableStatus: - case QCamera::UnloadedStatus: - case QCamera::UnloadingStatus: - camera_log.error("Camera not open. State=%d", static_cast(status)); - m_state = camera_handler_state::closed; - return false; - case QCamera::LoadedStatus: - case QCamera::StandbyStatus: - case QCamera::StoppingStatus: - camera_log.error("Camera not active. State=%d", static_cast(status)); - m_state = camera_handler_state::open; - return false; - case QCamera::LoadingStatus: - case QCamera::StartingStatus: - case QCamera::ActiveStatus: - default: - break; - } - - // Copy latest image into out buffer. - m_surface->get_image(buf, size, width, height, frame_number, bytes_read); - - return true; + return current_state; } void qt_camera_handler::update_camera_settings() @@ -306,28 +298,3 @@ void qt_camera_handler::update_camera_settings() m_surface->set_mirrored(m_mirrored); } } - -void qt_camera_handler::handle_camera_state(QCamera::State state) -{ - camera_log.notice("Camera state changed to %d", static_cast(state)); -} - -void qt_camera_handler::handle_camera_status(QCamera::Status status) -{ - camera_log.notice("Camera status changed to %d", static_cast(status)); -} - -void qt_camera_handler::handle_lock_status(QCamera::LockStatus status, QCamera::LockChangeReason reason) -{ - camera_log.notice("Camera lock status changed to %d (reason=%d)", static_cast(status), static_cast(reason)); -} - -void qt_camera_handler::handle_capture_modes(QCamera::CaptureModes capture_modes) -{ - camera_log.notice("Camera capture modes changed to %d", static_cast(capture_modes)); -} - -void qt_camera_handler::handle_camera_error(QCamera::Error error) -{ - camera_log.error("Error: \"%s\" (error=%d)", m_camera ? m_camera->errorString().toStdString() : "", static_cast(error)); -} diff --git a/rpcs3/rpcs3qt/qt_camera_handler.h b/rpcs3/rpcs3qt/qt_camera_handler.h index 729ae4dfed..523a53643c 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.h +++ b/rpcs3/rpcs3qt/qt_camera_handler.h @@ -2,20 +2,19 @@ #include "Emu/Io/camera_handler_base.h" #include "qt_camera_video_surface.h" +#include "qt_camera_error_handler.h" #include #include #include -class video_surface; - -class qt_camera_handler final : public camera_handler_base, public QObject +class qt_camera_handler final : public camera_handler_base { public: qt_camera_handler(); virtual ~qt_camera_handler(); - void set_camera(const QCameraInfo &cameraInfo); + void set_camera(const QCameraInfo& cameraInfo); void open_camera() override; void close_camera() override; @@ -26,16 +25,12 @@ public: void set_resolution(u32 width, u32 height) override; void set_mirrored(bool mirrored) override; u64 frame_number() const override; - bool get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) override; + camera_handler_state get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) override; private: - void handle_lock_status(QCamera::LockStatus, QCamera::LockChangeReason); - void handle_capture_modes(QCamera::CaptureModes capture_modes); - void handle_camera_state(QCamera::State state); - void handle_camera_status(QCamera::Status status); - void handle_camera_error(QCamera::Error error); void update_camera_settings(); - std::unique_ptr m_camera; + std::shared_ptr m_camera; std::unique_ptr m_surface; + std::unique_ptr m_error_handler; };