From f3ef4f3658c1dcbac1100243a5e08aafe9fcb7f5 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 17 Dec 2024 22:27:35 +0100 Subject: [PATCH] cellCamera: try to fix internal state on stop When stopping, the camera is supposed to be open still. Add an expected state to check the camera signal does what it should. --- rpcs3/Emu/Cell/Modules/cellCamera.cpp | 14 +++--- rpcs3/Emu/Io/Null/null_camera_handler.h | 10 ++-- rpcs3/Emu/Io/camera_handler_base.h | 23 ++++++--- rpcs3/rpcs3qt/qt_camera_handler.cpp | 67 ++++++++++++++++++------- rpcs3/rpcs3qt/qt_camera_handler.h | 5 +- 5 files changed, 78 insertions(+), 41 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp index 89ab8ef9f9..64135ca5fa 100644 --- a/rpcs3/Emu/Cell/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -784,26 +784,26 @@ s32 cellCameraIsAttached(s32 dev_num) if (g_cfg.io.camera == camera_handler::null) { - return false; + return 0; } auto& g_camera = g_fxo->get(); if (!g_camera.init) { - return false; + return 0; } if (!check_dev_num(dev_num)) { - return false; + return 0; } vm::var type; if (cellCameraGetType(dev_num, type) != CELL_OK) { - return false; + return 0; } std::lock_guard lock(g_camera.mutex); @@ -821,12 +821,12 @@ s32 cellCameraIsAttached(s32 dev_num) } } - return is_attached; + return is_attached ? 1 : 0; } s32 cellCameraIsOpen(s32 dev_num) { - cellCamera.notice("cellCameraIsOpen(dev_num=%d)", dev_num); + cellCamera.trace("cellCameraIsOpen(dev_num=%d)", dev_num); if (g_cfg.io.camera == camera_handler::null) { @@ -852,7 +852,7 @@ s32 cellCameraIsOpen(s32 dev_num) s32 cellCameraIsStarted(s32 dev_num) { - cellCamera.notice("cellCameraIsStarted(dev_num=%d)", dev_num); + cellCamera.trace("cellCameraIsStarted(dev_num=%d)", dev_num); if (g_cfg.io.camera == camera_handler::null) { diff --git a/rpcs3/Emu/Io/Null/null_camera_handler.h b/rpcs3/Emu/Io/Null/null_camera_handler.h index 61e26a8d96..a250facd75 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 { 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 open_camera() override { set_state(camera_handler_state::open); } + void close_camera() override { set_state(camera_handler_state::closed); } + void start_camera() override { set_state(camera_handler_state::running); } + void stop_camera() override { set_state(camera_handler_state::open); } void set_format(s32 format, u32 bytesize) override { @@ -45,6 +45,6 @@ public: height = 0; frame_number = 0; bytes_read = 0; - return m_state; + return get_state(); } }; diff --git a/rpcs3/Emu/Io/camera_handler_base.h b/rpcs3/Emu/Io/camera_handler_base.h index 531fa3abe3..49ce4dc635 100644 --- a/rpcs3/Emu/Io/camera_handler_base.h +++ b/rpcs3/Emu/Io/camera_handler_base.h @@ -30,22 +30,29 @@ public: virtual u64 frame_number() const = 0; // Convenience function to check if there's a new frame. 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(); }; + camera_handler_state get_state() const { return m_state.load(); } + void set_state(camera_handler_state state) { m_state = m_state_expected = state; } - bool mirrored() const { return m_mirrored; }; - s32 format() const { return m_format; }; - u32 bytesize() const { return m_bytesize; }; - u32 width() const { return m_width; }; - u32 height() const { return m_height; }; - u32 frame_rate() const { return m_frame_rate; }; + camera_handler_state get_expected_state() const { return m_state_expected.load(); } + void set_expected_state(camera_handler_state state) { m_state_expected = state; } + + bool mirrored() const { return m_mirrored; } + s32 format() const { return m_format; } + u32 bytesize() const { return m_bytesize; } + u32 width() const { return m_width; } + u32 height() const { return m_height; } + u32 frame_rate() const { return m_frame_rate; } protected: std::mutex m_mutex; - atomic_t m_state = camera_handler_state::closed; bool m_mirrored = false; s32 m_format = 2; // CELL_CAMERA_RAW8 u32 m_bytesize = 0; u32 m_width = 640; u32 m_height = 480; u32 m_frame_rate = 30; + +private: + atomic_t m_state = camera_handler_state::closed; + atomic_t m_state_expected = camera_handler_state::closed; }; diff --git a/rpcs3/rpcs3qt/qt_camera_handler.cpp b/rpcs3/rpcs3qt/qt_camera_handler.cpp index f0d11f937c..88d8c15963 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.cpp +++ b/rpcs3/rpcs3qt/qt_camera_handler.cpp @@ -47,6 +47,7 @@ void qt_camera_handler::set_camera(const QCameraDevice& camera_info) { if (camera_info.isNull()) { + set_expected_state(camera_handler_state::closed); reset(); return; } @@ -57,9 +58,9 @@ void qt_camera_handler::set_camera(const QCameraDevice& camera_info) camera_log.success("Using camera: id=\"%s\", description=\"%s\", front_facing=%d", camera_info.id().toStdString(), camera_info.description(), front_facing); // Create camera and video surface - m_media_capture_session.reset(new QMediaCaptureSession(nullptr)); - m_video_sink.reset(new qt_camera_video_sink(front_facing, nullptr)); - m_camera.reset(new QCamera(camera_info)); + m_media_capture_session = std::make_unique(nullptr); + m_video_sink = std::make_unique(front_facing, nullptr); + m_camera = std::make_unique(camera_info); connect(m_camera.get(), &QCamera::activeChanged, this, &qt_camera_handler::handle_camera_active); connect(m_camera.get(), &QCamera::errorOccurred, this, &qt_camera_handler::handle_camera_error); @@ -76,14 +77,37 @@ void qt_camera_handler::handle_camera_active(bool is_active) { camera_log.notice("Camera active status changed to %d", is_active); - if (is_active) + // Check if the camera does what it's supposed to do. + const camera_handler_state expected_state = get_expected_state(); + + switch (expected_state) { - m_state = camera_handler_state::running; - } - else + case camera_handler_state::closed: + case camera_handler_state::open: { - m_state = camera_handler_state::closed; + if (is_active) + { + // This is not supposed to happen and indicates an unexpected QCamera issue + camera_log.error("Camera started unexpectedly"); + set_state(camera_handler_state::running); + return; + } + break; } + case camera_handler_state::running: + { + if (!is_active) + { + // This is not supposed to happen and indicates an unexpected QCamera issue + camera_log.error("Camera stopped unexpectedly"); + set_state(camera_handler_state::open); + return; + } + break; + } + } + + set_state(expected_state); } void qt_camera_handler::handle_camera_error(QCamera::Error error, const QString& errorString) @@ -100,7 +124,11 @@ void qt_camera_handler::open_camera() { camera_log.notice("Switching camera from %s to %s", m_camera_id, camera_id); camera_log.notice("Stopping old camera..."); - if (m_camera) m_camera->stop(); + if (m_camera) + { + set_expected_state(camera_handler_state::open); + m_camera->stop(); + } m_camera_id = camera_id; } @@ -129,7 +157,7 @@ void qt_camera_handler::open_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } @@ -148,7 +176,7 @@ void qt_camera_handler::open_camera() // Update camera and view finder settings update_camera_settings(); - m_state = camera_handler_state::open; + set_state(camera_handler_state::open); } void qt_camera_handler::close_camera() @@ -159,11 +187,12 @@ void qt_camera_handler::close_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } // Unload/close camera + set_expected_state(camera_handler_state::closed); m_camera->stop(); } @@ -175,7 +204,7 @@ void qt_camera_handler::start_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } @@ -206,6 +235,7 @@ void qt_camera_handler::start_camera() #endif // Start camera. We will start receiving frames now. + set_expected_state(camera_handler_state::running); m_camera->start(); } @@ -217,7 +247,7 @@ void qt_camera_handler::stop_camera() { if (m_camera_id.empty()) camera_log.notice("Camera disabled"); else camera_log.error("No camera found"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return; } @@ -228,6 +258,7 @@ void qt_camera_handler::stop_camera() } // Stop camera. The camera will still be drawing power. + set_expected_state(camera_handler_state::open); m_camera->stop(); } @@ -284,26 +315,26 @@ camera_handler_base::camera_handler_state qt_camera_handler::get_image(u8* buf, m_camera_id != camera_id) { camera_log.notice("Switching cameras"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return camera_handler_state::closed; } if (m_camera_id.empty()) { camera_log.notice("Camera disabled"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return camera_handler_state::closed; } if (!m_camera || !m_video_sink) { camera_log.fatal("Error: camera invalid"); - m_state = camera_handler_state::closed; + set_state(camera_handler_state::closed); return camera_handler_state::closed; } // Backup current state. State may change through events. - const camera_handler_state current_state = m_state; + const camera_handler_state current_state = get_state(); if (current_state == camera_handler_state::running) { diff --git a/rpcs3/rpcs3qt/qt_camera_handler.h b/rpcs3/rpcs3qt/qt_camera_handler.h index d828bd6c84..0759d739c6 100644 --- a/rpcs3/rpcs3qt/qt_camera_handler.h +++ b/rpcs3/rpcs3qt/qt_camera_handler.h @@ -17,8 +17,6 @@ public: qt_camera_handler(); virtual ~qt_camera_handler(); - void set_camera(const QCameraDevice& camera_info); - void open_camera() override; void close_camera() override; void start_camera() override; @@ -31,11 +29,12 @@ public: camera_handler_state get_image(u8* buf, u64 size, u32& width, u32& height, u64& frame_number, u64& bytes_read) override; private: + void set_camera(const QCameraDevice& camera_info); void reset(); void update_camera_settings(); std::string m_camera_id; - std::shared_ptr m_camera; + std::unique_ptr m_camera; std::unique_ptr m_media_capture_session; std::unique_ptr m_video_sink;