From fd49f0e33492e5965671ecd1cfd2b7c8c07b5e27 Mon Sep 17 00:00:00 2001 From: capitalistspz Date: Sun, 18 May 2025 20:40:17 +0100 Subject: [PATCH] Make camera selection persistent and add logging --- src/Cemu/Logging/CemuLogging.h | 1 + src/camera/CameraManager.cpp | 56 ++++++++++++++++++++++++-------- src/camera/CameraManager.h | 1 + src/config/CemuConfig.cpp | 2 +- src/gui/CameraSettingsWindow.cpp | 11 +++---- src/gui/CameraSettingsWindow.h | 3 +- src/gui/MainWindow.cpp | 1 + 7 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index d729d364..c0debfb8 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -14,6 +14,7 @@ enum class LogType : sint32 UnsupportedAPI = 2, SoundAPI = 4, // any audio related API InputAPI = 5, // any input related API + CameraAPI = 27, Socket = 6, Save = 7, H264 = 9, diff --git a/src/camera/CameraManager.cpp b/src/camera/CameraManager.cpp index 1df42f10..28fbf6cc 100644 --- a/src/camera/CameraManager.cpp +++ b/src/camera/CameraManager.cpp @@ -18,7 +18,6 @@ constexpr unsigned CAMERA_PITCH = 768; namespace CameraManager { std::mutex s_mutex; - bool s_initialized = false; CapContext s_ctx; std::optional s_device; std::optional s_stream; @@ -29,17 +28,38 @@ namespace CameraManager std::atomic_bool s_capturing = false; std::atomic_bool s_running = false; + std::string FourCC(uint32le value) + { + return { + static_cast((value >> 0) & 0xFF), + static_cast((value >> 8) & 0xFF), + static_cast((value >> 16) & 0xFF), + static_cast((value >> 24) & 0xFF)}; + } + + void CaptureLogFunction(uint32_t level, const char* string) + { + cemuLog_log(LogType::CameraAPI, "OpenPNPCapture: {}: {}", level, string); + } + std::optional FindCorrectFormat() { - const auto formatCount = Cap_getNumFormats(s_ctx, *s_device); + const auto device = *s_device; + cemuLog_log(LogType::CameraAPI, "Video capture device '{}' available formats:", Cap_getDeviceName(s_ctx, device)); + const auto formatCount = Cap_getNumFormats(s_ctx, device); for (int32_t formatId = 0; formatId < formatCount; ++formatId) { CapFormatInfo formatInfo; - if (Cap_getFormatInfo(s_ctx, *s_device, formatId, &formatInfo) != CAPRESULT_OK) + if (Cap_getFormatInfo(s_ctx, device, formatId, &formatInfo) != CAPRESULT_OK) continue; + cemuLog_log(LogType::CameraAPI, "{}: {} {}x{} @ {} fps, {} bpp", formatId, FourCC(formatInfo.fourcc), formatInfo.width, formatInfo.height, formatInfo.fps, formatInfo.bpp); if (formatInfo.width == CAMERA_WIDTH && formatInfo.height == CAMERA_HEIGHT) + { + cemuLog_log(LogType::CameraAPI, "Selected video format {}", formatId); return formatId; + } } + cemuLog_log(LogType::CameraAPI, "Failed to find suitable video format"); return std::nullopt; } @@ -92,16 +112,16 @@ namespace CameraManager { { std::scoped_lock lock(s_mutex); - if (s_initialized) + if (s_running) return; - s_initialized = true; s_running = true; + s_ctx = Cap_createContext(); + Cap_setLogLevel(4); + Cap_installCustomLogFunction(CaptureLogFunction); } - s_ctx = Cap_createContext(); s_captureThread = std::thread(&CaptureWorker); - const auto uniqueId = GetConfig().camera_id.GetValue(); if (!uniqueId.empty()) { @@ -121,8 +141,8 @@ namespace CameraManager { CloseStream(); Cap_releaseContext(s_ctx); + s_running = false; s_captureThread.join(); - s_initialized = false; } void FillNV12Buffer(uint8* nv12Buffer) { @@ -173,6 +193,7 @@ namespace CameraManager std::scoped_lock lock(s_mutex); std::vector infos; const auto deviceCount = Cap_getDeviceCount(s_ctx); + cemuLog_log(LogType::CameraAPI, "Available video capture devices:"); for (CapDeviceID deviceNo = 0; deviceNo < deviceCount; ++deviceNo) { const auto uniqueId = Cap_getDeviceUniqueID(s_ctx, deviceNo); @@ -181,19 +202,26 @@ namespace CameraManager info.uniqueId = uniqueId; if (name) - info.name = fmt::format("{}: {}", deviceNo + 1, name); + info.name = fmt::format("{}: {}", deviceNo, name); else - info.name = fmt::format("{}: Unknown", deviceNo + 1); + info.name = fmt::format("{}: Unknown", deviceNo); infos.push_back(info); + cemuLog_log(LogType::CameraAPI, "{}", info.name); } + if (infos.empty()) + cemuLog_log(LogType::CameraAPI, "No available video capture devices"); return infos; } void SaveDevice() { std::scoped_lock lock(s_mutex); - if (s_device) - GetConfig().camera_id = Cap_getDeviceUniqueID(s_ctx, *s_device); - else - GetConfig().camera_id = ""; + auto& config = GetConfig(); + const auto cameraId = s_device ? Cap_getDeviceUniqueID(s_ctx, *s_device) : ""; + config.camera_id = cameraId; + } + + std::optional GetCurrentDevice() + { + return s_device; } } // namespace CameraManager \ No newline at end of file diff --git a/src/camera/CameraManager.h b/src/camera/CameraManager.h index f372e86c..28e751a0 100644 --- a/src/camera/CameraManager.h +++ b/src/camera/CameraManager.h @@ -21,4 +21,5 @@ namespace CameraManager void SetDevice(uint32 deviceNo); std::vector EnumerateDevices(); void SaveDevice(); + std::optional GetCurrentDevice(); } // namespace CameraManager diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 95ef42b2..23256370 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -344,7 +344,7 @@ void CemuConfig::Load(XMLConfigParser& parser) dsu_client.port = dsuc.get_attribute("port", dsu_client.port); auto camera = parser.get("Camera"); - camera_id = camera.get_attribute("Id", ""); + camera_id = camera.get("Id", ""); // emulatedusbdevices auto usbdevices = parser.get("EmulatedUsbDevices"); diff --git a/src/gui/CameraSettingsWindow.cpp b/src/gui/CameraSettingsWindow.cpp index 4014513f..24cd96db 100644 --- a/src/gui/CameraSettingsWindow.cpp +++ b/src/gui/CameraSettingsWindow.cpp @@ -15,7 +15,8 @@ CameraSettingsWindow::CameraSettingsWindow(wxWindow* parent) m_imageBitmap(CAMERA_WIDTH, CAMERA_HEIGHT, 24), m_imageBuffer(CAMERA_WIDTH * CAMERA_HEIGHT * 3) { - + CameraManager::Init(); + CameraManager::Open(); auto* rootSizer = new wxBoxSizer(wxVERTICAL); { auto* topSizer = new wxBoxSizer(wxHORIZONTAL); @@ -37,8 +38,6 @@ CameraSettingsWindow::CameraSettingsWindow(wxWindow* parent) rootSizer->Add(m_imageWindow, wxEXPAND); } SetSizerAndFit(rootSizer); - CameraManager::Init(); - CameraManager::Open(); m_imageUpdateTimer.Bind(wxEVT_TIMER, &CameraSettingsWindow::UpdateImage, this); m_imageUpdateTimer.Start(33, wxTIMER_CONTINUOUS); this->Bind(wxEVT_CLOSE_WINDOW, &CameraSettingsWindow::OnClose, this); @@ -61,8 +60,8 @@ void CameraSettingsWindow::OnRefreshPressed(wxCommandEvent&) choices.push_back(entry.name); } m_cameraChoice->Set(choices); - wxArrayString str; - + if (auto currentDevice = CameraManager::GetCurrentDevice()) + m_cameraChoice->SetSelection(*currentDevice + 1); } void CameraSettingsWindow::UpdateImage(const wxTimerEvent&) { @@ -95,4 +94,4 @@ void CameraSettingsWindow::OnClose(wxCloseEvent& event) CameraManager::Close(); CameraManager::SaveDevice(); event.Skip(); -} +} \ No newline at end of file diff --git a/src/gui/CameraSettingsWindow.h b/src/gui/CameraSettingsWindow.h index 86014d65..1a6dc6df 100644 --- a/src/gui/CameraSettingsWindow.h +++ b/src/gui/CameraSettingsWindow.h @@ -18,5 +18,4 @@ class CameraSettingsWindow : public wxDialog void OnRefreshPressed(wxCommandEvent&); void UpdateImage(const wxTimerEvent&); void OnClose(wxCloseEvent& event); -}; - +}; \ No newline at end of file diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 3bf0f6a4..92ac331a 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -2242,6 +2242,7 @@ void MainWindow::RecreateMenu() logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("gx2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2)); logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI)); logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI)); + logCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CameraAPI), _("Camera API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CameraAPI)); debugLoggingMenu->AppendSubMenu(logCosModulesMenu, _("&CafeOS modules logging")); debugLoggingMenu->AppendSeparator();