cellCamera: add error handling to qt camera

This commit is contained in:
Megamouse 2021-10-17 15:35:30 +02:00
parent e4b242955c
commit 81c216f330
12 changed files with 254 additions and 139 deletions

View File

@ -1328,17 +1328,6 @@ error_code cellCameraReadEx(s32 dev_num, vm::ptr<CellCameraReadEx> 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<gem_camera_shared>();
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<CellCameraReadEx> read)
u64 bytes_read{};
atomic_t<bool> 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<CellCameraReadEx> 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<CellCameraReadEx> 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<gem_camera_shared>();
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<bool> 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<int>(state));
handler->start_camera();
}
else if (is_open)
{
cellCamera.warning("Camera closed or disconnected (state=%d). Trying to open camera...", static_cast<int>(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<int>(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<int>(state));
handler->start_camera();
}
break;
}
}
return CELL_OK;
}

View File

@ -442,6 +442,7 @@ public:
static constexpr auto thread_name = "Camera Thread"sv;
std::shared_ptr<camera_handler_base> handler;
error_code on_handler_state(camera_handler_base::camera_handler_state state);
};
using camera_thread = named_thread<camera_context>;

View File

@ -1351,7 +1351,7 @@ error_code cellGemPrepareVideoConvert(vm::cptr<CellGemVideoConvertAttribute> 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)
{

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

View File

@ -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<camera_handler_state> m_state = camera_handler_state::closed;
atomic_t<camera_handler_state> m_state = camera_handler_state::not_available;
bool m_mirrored = false;
s32 m_format = 2; // CELL_CAMERA_RAW8
u32 m_bytes_per_pixel = 1;

View File

@ -303,6 +303,9 @@
<ClCompile Include="QTGeneratedFiles\Debug\moc_pkg_install_dialog.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug\moc_qt_camera_error_handler.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug\moc_recvmessage_dialog_frame.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
@ -501,6 +504,9 @@
<ClCompile Include="QTGeneratedFiles\Release\moc_pkg_install_dialog.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release\moc_qt_camera_error_handler.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release\moc_recvmessage_dialog_frame.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
@ -594,6 +600,7 @@
<ClCompile Include="rpcs3qt\patch_manager_dialog.cpp" />
<ClCompile Include="rpcs3qt\pkg_install_dialog.cpp" />
<ClCompile Include="rpcs3qt\persistent_settings.cpp" />
<ClCompile Include="rpcs3qt\qt_camera_error_handler.cpp" />
<ClCompile Include="rpcs3qt\qt_camera_handler.cpp" />
<ClCompile Include="rpcs3qt\recvmessage_dialog_frame.cpp" />
<ClCompile Include="rpcs3qt\render_creator.cpp" />
@ -1090,6 +1097,16 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(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"</Command>
</CustomBuild>
<CustomBuild Include="rpcs3qt\qt_camera_error_handler.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(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"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing %(Identity)...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(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"</Command>
</CustomBuild>
<ClInclude Include="rpcs3qt\qt_camera_handler.h" />
<ClInclude Include="rpcs3qt\richtext_item_delegate.h" />
<CustomBuild Include="rpcs3qt\sendmessage_dialog_frame.h">

View File

@ -786,6 +786,15 @@
<ClCompile Include="rpcs3qt\qt_camera_video_surface.cpp">
<Filter>Io\camera</Filter>
</ClCompile>
<ClCompile Include="rpcs3qt\qt_camera_error_handler.cpp">
<Filter>Io\camera</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Debug\moc_qt_camera_error_handler.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release\moc_qt_camera_error_handler.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Input\ds4_pad_handler.h">
@ -1153,6 +1162,9 @@
<CustomBuild Include="rpcs3qt\recvmessage_dialog_frame.h">
<Filter>Gui\message dialog</Filter>
</CustomBuild>
<CustomBuild Include="rpcs3qt\qt_camera_error_handler.h">
<Filter>Io\camera</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="rpcs3.ico" />

View File

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

View File

@ -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<QCamera> camera, std::function<void(QCamera::Status)> status_callback)
: m_camera(std::move(camera))
, m_status_callback(std::move(status_callback))
{
if (m_camera)
{
connect(m_camera.get(), QOverload<QMultimedia::AvailabilityStatus>::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<QCamera::LockStatus, QCamera::LockChangeReason>::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<int>(availability));
}
void qt_camera_error_handler::handle_camera_state(QCamera::State state)
{
camera_log.notice("Camera state changed to %d", static_cast<int>(state));
}
void qt_camera_error_handler::handle_camera_status(QCamera::Status status)
{
camera_log.notice("Camera status changed to %d", static_cast<int>(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<int>(status), static_cast<int>(reason));
}
void qt_camera_error_handler::handle_capture_modes(QCamera::CaptureModes capture_modes)
{
camera_log.notice("Camera capture modes changed to %d", static_cast<int>(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<int>(error));
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <QObject>
#include <QCamera>
class qt_camera_error_handler : public QObject
{
Q_OBJECT
public:
qt_camera_error_handler(std::shared_ptr<QCamera> camera, std::function<void(QCamera::Status)> 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<QCamera> m_camera;
std::function<void(QCamera::Status)> m_status_callback = nullptr;
};

View File

@ -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<QCamera::LockStatus, QCamera::LockChangeReason>::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<int>(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<int>(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<int>(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<int>(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<int>(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<int>(state));
}
void qt_camera_handler::handle_camera_status(QCamera::Status status)
{
camera_log.notice("Camera status changed to %d", static_cast<int>(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<int>(status), static_cast<int>(reason));
}
void qt_camera_handler::handle_capture_modes(QCamera::CaptureModes capture_modes)
{
camera_log.notice("Camera capture modes changed to %d", static_cast<int>(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<int>(error));
}

View File

@ -2,20 +2,19 @@
#include "Emu/Io/camera_handler_base.h"
#include "qt_camera_video_surface.h"
#include "qt_camera_error_handler.h"
#include <QCamera>
#include <QCameraImageCapture>
#include <QAbstractVideoSurface>
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<QCamera> m_camera;
std::shared_ptr<QCamera> m_camera;
std::unique_ptr<qt_camera_video_surface> m_surface;
std::unique_ptr<qt_camera_error_handler> m_error_handler;
};