mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-13 03:40:49 +00:00
cellCamera: add error handling to qt camera
This commit is contained in:
parent
e4b242955c
commit
81c216f330
@ -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;
|
||||
}
|
||||
|
@ -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>;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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">
|
||||
|
@ -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" />
|
||||
|
@ -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
|
||||
|
58
rpcs3/rpcs3qt/qt_camera_error_handler.cpp
Normal file
58
rpcs3/rpcs3qt/qt_camera_error_handler.cpp
Normal 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));
|
||||
}
|
25
rpcs3/rpcs3qt/qt_camera_error_handler.h
Normal file
25
rpcs3/rpcs3qt/qt_camera_error_handler.h
Normal 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;
|
||||
};
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user