diff --git a/CMakeLists.txt b/CMakeLists.txt index 11d97724de..4490df21cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,7 @@ endif() option(ENABLE_QT "Enable the Qt frontend" ON) option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) option(ENABLE_UPDATE_CHECKER "Enable update checker (for Qt and Android)" OFF) -# option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) +cmake_dependent_option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF "NOT YUZU_USE_BUNDLED_QT" OFF) cmake_dependent_option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF "NOT YUZU_USE_BUNDLED_QT" OFF) set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries") cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF) @@ -577,9 +577,9 @@ if (ENABLE_QT) find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Charts Concurrent) - # if (YUZU_USE_QT_MULTIMEDIA) - # find_package(Qt6 REQUIRED COMPONENTS Multimedia) - # endif() + if (YUZU_USE_QT_MULTIMEDIA) + find_package(Qt6 REQUIRED COMPONENTS Multimedia) + endif() if (PLATFORM_LINUX OR PLATFORM_FREEBSD) # yes Qt, we get it @@ -618,9 +618,9 @@ if (ENABLE_QT) if (PLATFORM_LINUX) list(APPEND YUZU_QT_COMPONENTS DBus) endif() - # if (YUZU_USE_QT_MULTIMEDIA) - # list(APPEND YUZU_QT_COMPONENTS Multimedia) - # endif() + if (YUZU_USE_QT_MULTIMEDIA) + list(APPEND YUZU_QT_COMPONENTS Multimedia) + endif() if (YUZU_USE_QT_WEB_ENGINE) list(APPEND YUZU_QT_COMPONENTS WebEngineCore WebEngineWidgets) endif() diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index c85d43235a..99fb2fec15 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -412,10 +412,10 @@ if (ENABLE_WEB_SERVICE) target_compile_definitions(yuzu PRIVATE ENABLE_WEB_SERVICE) endif() -# if (YUZU_USE_QT_MULTIMEDIA) -# target_link_libraries(yuzu PRIVATE Qt6::Multimedia) -# target_compile_definitions(yuzu PRIVATE YUZU_USE_QT_MULTIMEDIA) -# endif () +if (YUZU_USE_QT_MULTIMEDIA) + target_link_libraries(yuzu PRIVATE Qt6::Multimedia) + target_compile_definitions(yuzu PRIVATE YUZU_USE_QT_MULTIMEDIA) +endif () if (YUZU_USE_QT_WEB_ENGINE) target_link_libraries(yuzu PRIVATE Qt6::WebEngineCore Qt6::WebEngineWidgets) diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1b88f4133f..72a5157fc4 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -13,10 +13,11 @@ #include #include "common/settings_enums.h" #include "qt_common/config/uisettings.h" -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA #include -#include -#include +#include +#include +#include #endif #include #include @@ -756,24 +757,25 @@ void GRenderWindow::TouchEndEvent() { } void GRenderWindow::InitializeCamera() { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA constexpr auto camera_update_ms = std::chrono::milliseconds{50}; // (50ms, 20Hz) if (!Settings::values.enable_ir_sensor) { return; } bool camera_found = false; - const QList cameras = QCameraInfo::availableCameras(); - for (const QCameraInfo& cameraInfo : cameras) { - if (Settings::values.ir_sensor_device.GetValue() == cameraInfo.deviceName().toStdString() || - Settings::values.ir_sensor_device.GetValue() == "Auto") { - camera = std::make_unique(cameraInfo); - if (!camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureViewfinder) && - !camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureStillImage)) { - LOG_ERROR(Frontend, - "Camera doesn't support CaptureViewfinder or CaptureStillImage"); + std::string current_device = Settings::values.ir_sensor_device.GetValue(); +#ifdef _WIN32 + std::replace(current_device.begin(), current_device.end(), '|', '\\'); +#endif + const QList cameras = QMediaDevices::videoInputs(); + for (const QCameraDevice& cameraDevice : cameras) { + if (current_device == cameraDevice.id().toStdString() || current_device == "auto") { + if (cameraDevice.videoFormats().isEmpty()) { + LOG_ERROR(Frontend, "Camera doesn't provide any video formats."); continue; } + camera = std::make_unique(cameraDevice); camera_found = true; break; } @@ -783,27 +785,16 @@ void GRenderWindow::InitializeCamera() { return; } - camera_capture = std::make_unique(camera.get()); - - if (!camera_capture->isCaptureDestinationSupported( - QCameraImageCapture::CaptureDestination::CaptureToBuffer)) { - LOG_ERROR(Frontend, "Camera doesn't support saving to buffer"); - return; - } + capture_session = std::make_unique(); + camera_capture = std::make_unique(); + capture_session->setCamera(camera.get()); + capture_session->setImageCapture(camera_capture.get()); const auto camera_width = input_subsystem->GetCamera()->getImageWidth(); const auto camera_height = input_subsystem->GetCamera()->getImageHeight(); camera_data.resize(camera_width * camera_height); - camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); - connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, + connect(camera_capture.get(), &QImageCapture::imageCaptured, this, &GRenderWindow::OnCameraCapture); - camera->unload(); - if (camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureViewfinder)) { - camera->setCaptureMode(QCamera::CaptureViewfinder); - } else if (camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureStillImage)) { - camera->setCaptureMode(QCamera::CaptureStillImage); - } - camera->load(); camera->start(); pending_camera_snapshots = 0; @@ -817,18 +808,18 @@ void GRenderWindow::InitializeCamera() { } void GRenderWindow::FinalizeCamera() { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA if (camera_timer) { camera_timer->stop(); } if (camera) { - camera->unload(); + camera->stop(); } #endif } void GRenderWindow::RequestCameraCapture() { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA if (!Settings::values.enable_ir_sensor) { return; } @@ -849,7 +840,7 @@ void GRenderWindow::RequestCameraCapture() { } void GRenderWindow::OnCameraCapture(int requestId, const QImage& img) { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA // TODO: Capture directly in the format and resolution needed const auto camera_width = input_subsystem->GetCamera()->getImageWidth(); const auto camera_height = input_subsystem->GetCamera()->getImageHeight(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 83d364df4b..837156a725 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2014 Citra Emulator Project @@ -34,7 +34,8 @@ class MainWindow; class QCamera; -class QCameraImageCapture; +class QImageCapture; +class QMediaCaptureSession; class QCloseEvent; class QFocusEvent; class QKeyEvent; @@ -264,12 +265,13 @@ private: bool first_frame = false; InputCommon::TasInput::TasState last_tas_state; -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA bool is_virtual_camera; int pending_camera_snapshots; std::vector camera_data; std::unique_ptr camera; - std::unique_ptr camera_capture; + std::unique_ptr camera_capture; + std::unique_ptr capture_session; std::unique_ptr camera_timer; #endif diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp index 3368f53f30..eb39bbdc9f 100644 --- a/src/yuzu/configuration/configure_camera.cpp +++ b/src/yuzu/configuration/configure_camera.cpp @@ -1,11 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // Text : Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later #include #include -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA -#include -#include +#if YUZU_USE_QT_MULTIMEDIA +#include +#include +#include +#include #endif #include #include @@ -36,22 +41,20 @@ ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* i ConfigureCamera::~ConfigureCamera() = default; void ConfigureCamera::PreviewCamera() { -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA const auto index = ui->ir_sensor_combo_box->currentIndex(); bool camera_found = false; - const QList cameras = QCameraInfo::availableCameras(); - for (const QCameraInfo& cameraInfo : cameras) { - if (input_devices[index] == cameraInfo.deviceName().toStdString() || - input_devices[index] == "Auto") { - LOG_INFO(Frontend, "Selected Camera {} {}", cameraInfo.description().toStdString(), - cameraInfo.deviceName().toStdString()); - camera = std::make_unique(cameraInfo); - if (!camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureViewfinder) && - !camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureStillImage)) { - LOG_ERROR(Frontend, - "Camera doesn't support CaptureViewfinder or CaptureStillImage"); + const QList cameras = QMediaDevices::videoInputs(); + for (const QCameraDevice& cameraDevice : cameras) { + if (input_devices[index] == cameraDevice.id().toStdString() || + input_devices[index] == "auto") { + LOG_INFO(Frontend, "Selected Camera {} {}", cameraDevice.description().toStdString(), + cameraDevice.id().toStdString()); + if (cameraDevice.videoFormats().isEmpty()) { + LOG_ERROR(Frontend, "Camera doesn't provide any video formats."); continue; } + camera = std::make_unique(cameraDevice); camera_found = true; break; } @@ -66,24 +69,12 @@ void ConfigureCamera::PreviewCamera() { return; } - camera_capture = std::make_unique(camera.get()); - - if (!camera_capture->isCaptureDestinationSupported( - QCameraImageCapture::CaptureDestination::CaptureToBuffer)) { - LOG_ERROR(Frontend, "Camera doesn't support saving to buffer"); - return; - } - - camera_capture->setCaptureDestination(QCameraImageCapture::CaptureDestination::CaptureToBuffer); - connect(camera_capture.get(), &QCameraImageCapture::imageCaptured, this, + capture_session = std::make_unique(); + camera_capture = std::make_unique(); + capture_session->setCamera(camera.get()); + capture_session->setImageCapture(camera_capture.get()); + connect(camera_capture.get(), &QImageCapture::imageCaptured, this, &ConfigureCamera::DisplayCapturedFrame); - camera->unload(); - if (camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureViewfinder)) { - camera->setCaptureMode(QCamera::CaptureViewfinder); - } else if (camera->isCaptureModeSupported(QCamera::CaptureMode::CaptureStillImage)) { - camera->setCaptureMode(QCamera::CaptureStillImage); - } - camera->load(); camera->start(); pending_snapshots = 0; @@ -129,24 +120,31 @@ void ConfigureCamera::RetranslateUI() { } void ConfigureCamera::ApplyConfiguration() { - const auto index = ui->ir_sensor_combo_box->currentIndex(); - Settings::values.ir_sensor_device.SetValue(input_devices[index]); + std::string current_device = input_devices[ui->ir_sensor_combo_box->currentIndex()]; +#ifdef _WIN32 + // for whatever reason replacing with / isn't enough so we use | for saving + std::replace(current_device.begin(), current_device.end(), '\\', '|'); +#endif + Settings::values.ir_sensor_device.SetValue(current_device); } void ConfigureCamera::LoadConfiguration() { input_devices.clear(); ui->ir_sensor_combo_box->clear(); - input_devices.push_back("Auto"); + input_devices.push_back("auto"); ui->ir_sensor_combo_box->addItem(tr("Auto")); -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA - const auto cameras = QCameraInfo::availableCameras(); - for (const QCameraInfo& cameraInfo : cameras) { - input_devices.push_back(cameraInfo.deviceName().toStdString()); - ui->ir_sensor_combo_box->addItem(cameraInfo.description()); +#if YUZU_USE_QT_MULTIMEDIA + const auto cameras = QMediaDevices::videoInputs(); + for (const QCameraDevice& cameraDevice : cameras) { + input_devices.push_back(cameraDevice.id().toStdString()); + ui->ir_sensor_combo_box->addItem(cameraDevice.description()); } #endif - const auto current_device = Settings::values.ir_sensor_device.GetValue(); + std::string current_device = Settings::values.ir_sensor_device.GetValue(); +#ifdef _WIN32 + std::replace(current_device.begin(), current_device.end(), '|', '\\'); +#endif const auto devices_it = std::find_if( input_devices.begin(), input_devices.end(), diff --git a/src/yuzu/configuration/configure_camera.h b/src/yuzu/configuration/configure_camera.h index 3d822da7bb..610b362419 100644 --- a/src/yuzu/configuration/configure_camera.h +++ b/src/yuzu/configuration/configure_camera.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // Text : Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -8,7 +11,8 @@ class QTimer; class QCamera; -class QCameraImageCapture; +class QImageCapture; +class QMediaCaptureSession; namespace InputCommon { class InputSubsystem; @@ -46,9 +50,10 @@ private: bool is_virtual_camera; int pending_snapshots; -#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA +#if YUZU_USE_QT_MULTIMEDIA std::unique_ptr camera; - std::unique_ptr camera_capture; + std::unique_ptr camera_capture; + std::unique_ptr capture_session; #endif std::unique_ptr camera_timer; std::vector input_devices; diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 241d445cea..b1c19114bf 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project @@ -201,7 +201,7 @@ void ConfigureInputAdvanced::UpdateUIEnabled() { ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); ui->ring_controller_configure->setEnabled(ui->enable_ring_controller->isChecked()); -#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0) || !defined(YUZU_USE_QT_MULTIMEDIA) +#if !defined(YUZU_USE_QT_MULTIMEDIA) ui->enable_ir_sensor->setEnabled(false); ui->camera_configure->setEnabled(false); #endif