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.
This commit is contained in:
Megamouse 2024-12-17 22:27:35 +01:00
parent 73a62b4bf6
commit f3ef4f3658
5 changed files with 78 additions and 41 deletions

View File

@ -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<camera_thread>();
if (!g_camera.init)
{
return false;
return 0;
}
if (!check_dev_num(dev_num))
{
return false;
return 0;
}
vm::var<s32> 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)
{

View File

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

View File

@ -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<camera_handler_state> 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<camera_handler_state> m_state = camera_handler_state::closed;
atomic_t<camera_handler_state> m_state_expected = camera_handler_state::closed;
};

View File

@ -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<QMediaCaptureSession>(nullptr);
m_video_sink = std::make_unique<qt_camera_video_sink>(front_facing, nullptr);
m_camera = std::make_unique<QCamera>(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)
{

View File

@ -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<QCamera> m_camera;
std::unique_ptr<QCamera> m_camera;
std::unique_ptr<QMediaCaptureSession> m_media_capture_session;
std::unique_ptr<qt_camera_video_sink> m_video_sink;