|
| 1 | +// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com> |
| 2 | +// SPDX-License-Identifier: CC-BY-NC-ND-4.0 |
| 3 | + |
| 4 | +#include "capturesettingswidget.h" |
| 5 | +#include "qtutils.h" |
| 6 | +#include "settingswindow.h" |
| 7 | +#include "settingwidgetbinder.h" |
| 8 | + |
| 9 | +#include "util/media_capture.h" |
| 10 | + |
| 11 | +#include "common/error.h" |
| 12 | + |
| 13 | +#include "moc_capturesettingswidget.cpp" |
| 14 | + |
| 15 | +CaptureSettingsWidget::CaptureSettingsWidget(SettingsWindow* dialog, QWidget* parent) |
| 16 | + : QWidget(parent), m_dialog(dialog) |
| 17 | +{ |
| 18 | + SettingsInterface* sif = dialog->getSettingsInterface(); |
| 19 | + |
| 20 | + m_ui.setupUi(this); |
| 21 | + |
| 22 | + SettingWidgetBinder::BindWidgetToEnumSetting( |
| 23 | + sif, m_ui.screenshotSize, "Display", "ScreenshotMode", &Settings::ParseDisplayScreenshotMode, |
| 24 | + &Settings::GetDisplayScreenshotModeName, &Settings::GetDisplayScreenshotModeDisplayName, |
| 25 | + Settings::DEFAULT_DISPLAY_SCREENSHOT_MODE, DisplayScreenshotMode::Count); |
| 26 | + SettingWidgetBinder::BindWidgetToEnumSetting( |
| 27 | + sif, m_ui.screenshotFormat, "Display", "ScreenshotFormat", &Settings::ParseDisplayScreenshotFormat, |
| 28 | + &Settings::GetDisplayScreenshotFormatName, &Settings::GetDisplayScreenshotFormatDisplayName, |
| 29 | + Settings::DEFAULT_DISPLAY_SCREENSHOT_FORMAT, DisplayScreenshotFormat::Count); |
| 30 | + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "Display", "ScreenshotQuality", |
| 31 | + Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY); |
| 32 | + |
| 33 | + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.mediaCaptureBackend, "MediaCapture", "Backend", |
| 34 | + &MediaCapture::ParseBackendName, &MediaCapture::GetBackendName, |
| 35 | + &MediaCapture::GetBackendDisplayName, |
| 36 | + Settings::DEFAULT_MEDIA_CAPTURE_BACKEND, MediaCaptureBackend::MaxCount); |
| 37 | + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCapture, "MediaCapture", "VideoCapture", true); |
| 38 | + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureWidth, "MediaCapture", "VideoWidth", |
| 39 | + Settings::DEFAULT_MEDIA_CAPTURE_VIDEO_WIDTH); |
| 40 | + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureHeight, "MediaCapture", "VideoHeight", |
| 41 | + Settings::DEFAULT_MEDIA_CAPTURE_VIDEO_HEIGHT); |
| 42 | + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.videoCaptureResolutionAuto, "MediaCapture", "VideoAutoSize", |
| 43 | + false); |
| 44 | + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureBitrate, "MediaCapture", "VideoBitrate", |
| 45 | + Settings::DEFAULT_MEDIA_CAPTURE_VIDEO_BITRATE); |
| 46 | + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCaptureArguments, "MediaCapture", |
| 47 | + "VideoCodecUseArgs", false); |
| 48 | + SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureArguments, "MediaCapture", "AudioCodecArgs"); |
| 49 | + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableAudioCapture, "MediaCapture", "AudioCapture", true); |
| 50 | + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.audioCaptureBitrate, "MediaCapture", "AudioBitrate", |
| 51 | + Settings::DEFAULT_MEDIA_CAPTURE_AUDIO_BITRATE); |
| 52 | + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCaptureArguments, "MediaCapture", |
| 53 | + "VideoCodecUseArgs", false); |
| 54 | + SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureArguments, "MediaCapture", "AudioCodecArgs"); |
| 55 | + |
| 56 | + connect(m_ui.mediaCaptureBackend, &QComboBox::currentIndexChanged, this, |
| 57 | + &CaptureSettingsWidget::onMediaCaptureBackendChanged); |
| 58 | + connect(m_ui.enableVideoCapture, &QCheckBox::checkStateChanged, this, |
| 59 | + &CaptureSettingsWidget::onMediaCaptureVideoEnabledChanged); |
| 60 | + connect(m_ui.videoCaptureResolutionAuto, &QCheckBox::checkStateChanged, this, |
| 61 | + &CaptureSettingsWidget::onMediaCaptureVideoAutoResolutionChanged); |
| 62 | + connect(m_ui.enableAudioCapture, &QCheckBox::checkStateChanged, this, |
| 63 | + &CaptureSettingsWidget::onMediaCaptureAudioEnabledChanged); |
| 64 | + |
| 65 | + // Init all dependent options. |
| 66 | + onMediaCaptureBackendChanged(); |
| 67 | + onMediaCaptureAudioEnabledChanged(); |
| 68 | + onMediaCaptureVideoEnabledChanged(); |
| 69 | + |
| 70 | + dialog->registerWidgetHelp(m_ui.screenshotSize, tr("Screenshot Size"), tr("Screen Resolution"), |
| 71 | + tr("Determines the resolution at which screenshots will be saved. Internal resolutions " |
| 72 | + "preserve more detail at the cost of file size.")); |
| 73 | + dialog->registerWidgetHelp( |
| 74 | + m_ui.screenshotFormat, tr("Screenshot Format"), tr("PNG"), |
| 75 | + tr("Selects the format which will be used to save screenshots. JPEG produces smaller files, but loses detail.")); |
| 76 | + dialog->registerWidgetHelp(m_ui.screenshotQuality, tr("Screenshot Quality"), |
| 77 | + QStringLiteral("%1%").arg(Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY), |
| 78 | + tr("Selects the quality at which screenshots will be compressed. Higher values preserve " |
| 79 | + "more detail for JPEG, and reduce file size for PNG.")); |
| 80 | + dialog->registerWidgetHelp( |
| 81 | + m_ui.mediaCaptureBackend, tr("Backend"), |
| 82 | + QString::fromUtf8(MediaCapture::GetBackendDisplayName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND)), |
| 83 | + tr("Selects the framework that is used to encode video/audio.")); |
| 84 | + dialog->registerWidgetHelp(m_ui.captureContainer, tr("Container"), tr("MP4"), |
| 85 | + tr("Determines the file format used to contain the captured audio/video.")); |
| 86 | + dialog->registerWidgetHelp(m_ui.enableVideoCapture, tr("Capture Video"), tr("Checked"), |
| 87 | + tr("Captures video to the chosen file when media capture is started. If unchecked, the " |
| 88 | + "file will only contain audio.")); |
| 89 | + dialog->registerWidgetHelp( |
| 90 | + m_ui.videoCaptureCodec, tr("Video Codec"), tr("Default"), |
| 91 | + tr("Selects which Video Codec to be used for media capture. <b>If unsure, leave it on default.<b>")); |
| 92 | + dialog->registerWidgetHelp(m_ui.videoCaptureBitrate, tr("Video Bitrate"), tr("6000 kbps"), |
| 93 | + tr("Sets the video bitrate to be used. Larger bitrate generally yields better video " |
| 94 | + "quality at the cost of larger resulting file size.")); |
| 95 | + dialog->registerWidgetHelp( |
| 96 | + m_ui.videoCaptureResolutionAuto, tr("Automatic Resolution"), tr("Unchecked"), |
| 97 | + tr("When checked, the video capture resolution will follows the internal resolution of the running " |
| 98 | + "game. <b>Be careful when using this setting especially when you are upscaling, as higher internal " |
| 99 | + "resolutions (above 4x) can cause system slowdown.</b>")); |
| 100 | + dialog->registerWidgetHelp(m_ui.enableVideoCaptureArguments, tr("Enable Extra Video Arguments"), tr("Unchecked"), |
| 101 | + tr("Allows you to pass arguments to the selected video codec.")); |
| 102 | + dialog->registerWidgetHelp( |
| 103 | + m_ui.videoCaptureArguments, tr("Extra Video Arguments"), tr("Empty"), |
| 104 | + tr("Parameters passed to the selected video codec.<br><b>You must use '=' to separate key from value and ':' to " |
| 105 | + "separate two pairs from each other.</b><br>For example: \"crf = 21 : preset = veryfast\"")); |
| 106 | + dialog->registerWidgetHelp(m_ui.enableAudioCapture, tr("Capture Audio"), tr("Checked"), |
| 107 | + tr("Captures audio to the chosen file when media capture is started. If unchecked, the " |
| 108 | + "file will only contain video.")); |
| 109 | + dialog->registerWidgetHelp( |
| 110 | + m_ui.audioCaptureCodec, tr("Audio Codec"), tr("Default"), |
| 111 | + tr("Selects which Audio Codec to be used for media capture. <b>If unsure, leave it on default.<b>")); |
| 112 | + dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("128 kbps"), |
| 113 | + tr("Sets the audio bitrate to be used.")); |
| 114 | + dialog->registerWidgetHelp(m_ui.enableAudioCaptureArguments, tr("Enable Extra Audio Arguments"), tr("Unchecked"), |
| 115 | + tr("Allows you to pass arguments to the selected audio codec.")); |
| 116 | + dialog->registerWidgetHelp( |
| 117 | + m_ui.audioCaptureArguments, tr("Extra Audio Arguments"), tr("Empty"), |
| 118 | + tr("Parameters passed to the selected audio codec.<br><b>You must use '=' to separate key from value and ':' to " |
| 119 | + "separate two pairs from each other.</b><br>For example: \"compression_level = 4 : joint_stereo = 1\"")); |
| 120 | +} |
| 121 | + |
| 122 | +CaptureSettingsWidget::~CaptureSettingsWidget() = default; |
| 123 | + |
| 124 | +void CaptureSettingsWidget::onMediaCaptureBackendChanged() |
| 125 | +{ |
| 126 | + SettingsInterface* const sif = m_dialog->getSettingsInterface(); |
| 127 | + const MediaCaptureBackend backend = |
| 128 | + MediaCapture::ParseBackendName( |
| 129 | + m_dialog |
| 130 | + ->getEffectiveStringValue("MediaCapture", "Backend", |
| 131 | + MediaCapture::GetBackendName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND)) |
| 132 | + .c_str()) |
| 133 | + .value_or(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND); |
| 134 | + |
| 135 | + { |
| 136 | + SettingWidgetBinder::DisconnectWidget(m_ui.captureContainer); |
| 137 | + m_ui.captureContainer->clear(); |
| 138 | + |
| 139 | + for (const auto& [name, display_name] : MediaCapture::GetContainerList(backend)) |
| 140 | + { |
| 141 | + const QString qname = QString::fromStdString(name); |
| 142 | + m_ui.captureContainer->addItem(tr("%1 (%2)").arg(QString::fromStdString(display_name)).arg(qname), qname); |
| 143 | + } |
| 144 | + |
| 145 | + SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.captureContainer, "MediaCapture", "Container", |
| 146 | + Settings::DEFAULT_MEDIA_CAPTURE_CONTAINER); |
| 147 | + connect(m_ui.captureContainer, &QComboBox::currentIndexChanged, this, |
| 148 | + &CaptureSettingsWidget::onMediaCaptureContainerChanged); |
| 149 | + } |
| 150 | + |
| 151 | + onMediaCaptureContainerChanged(); |
| 152 | +} |
| 153 | + |
| 154 | +void CaptureSettingsWidget::onMediaCaptureContainerChanged() |
| 155 | +{ |
| 156 | + SettingsInterface* const sif = m_dialog->getSettingsInterface(); |
| 157 | + const MediaCaptureBackend backend = |
| 158 | + MediaCapture::ParseBackendName( |
| 159 | + m_dialog |
| 160 | + ->getEffectiveStringValue("MediaCapture", "Backend", |
| 161 | + MediaCapture::GetBackendName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND)) |
| 162 | + .c_str()) |
| 163 | + .value_or(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND); |
| 164 | + const std::string container = m_dialog->getEffectiveStringValue("MediaCapture", "Container", "mp4"); |
| 165 | + |
| 166 | + { |
| 167 | + SettingWidgetBinder::DisconnectWidget(m_ui.videoCaptureCodec); |
| 168 | + m_ui.videoCaptureCodec->clear(); |
| 169 | + m_ui.videoCaptureCodec->addItem(tr("Default"), QVariant(QString())); |
| 170 | + |
| 171 | + for (const auto& [name, display_name] : MediaCapture::GetVideoCodecList(backend, container.c_str())) |
| 172 | + { |
| 173 | + const QString qname = QString::fromStdString(name); |
| 174 | + m_ui.videoCaptureCodec->addItem(tr("%1 (%2)").arg(QString::fromStdString(display_name)).arg(qname), qname); |
| 175 | + } |
| 176 | + |
| 177 | + SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureCodec, "MediaCapture", "VideoCodec"); |
| 178 | + } |
| 179 | + |
| 180 | + { |
| 181 | + SettingWidgetBinder::DisconnectWidget(m_ui.audioCaptureCodec); |
| 182 | + m_ui.audioCaptureCodec->clear(); |
| 183 | + m_ui.audioCaptureCodec->addItem(tr("Default"), QVariant(QString())); |
| 184 | + |
| 185 | + for (const auto& [name, display_name] : MediaCapture::GetAudioCodecList(backend, container.c_str())) |
| 186 | + { |
| 187 | + const QString qname = QString::fromStdString(name); |
| 188 | + m_ui.audioCaptureCodec->addItem(tr("%1 (%2)").arg(QString::fromStdString(display_name)).arg(qname), qname); |
| 189 | + } |
| 190 | + |
| 191 | + SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureCodec, "MediaCapture", "AudioCodec"); |
| 192 | + } |
| 193 | +} |
| 194 | + |
| 195 | +void CaptureSettingsWidget::onMediaCaptureVideoEnabledChanged() |
| 196 | +{ |
| 197 | + const bool enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "VideoCapture", true); |
| 198 | + m_ui.videoCaptureCodecLabel->setEnabled(enabled); |
| 199 | + m_ui.videoCaptureCodec->setEnabled(enabled); |
| 200 | + m_ui.videoCaptureBitrateLabel->setEnabled(enabled); |
| 201 | + m_ui.videoCaptureBitrate->setEnabled(enabled); |
| 202 | + m_ui.videoCaptureResolutionLabel->setEnabled(enabled); |
| 203 | + m_ui.videoCaptureResolutionAuto->setEnabled(enabled); |
| 204 | + m_ui.enableVideoCaptureArguments->setEnabled(enabled); |
| 205 | + m_ui.videoCaptureArguments->setEnabled(enabled); |
| 206 | + onMediaCaptureVideoAutoResolutionChanged(); |
| 207 | +} |
| 208 | + |
| 209 | +void CaptureSettingsWidget::onMediaCaptureVideoAutoResolutionChanged() |
| 210 | +{ |
| 211 | + const bool enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "VideoCapture", true); |
| 212 | + const bool auto_enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "VideoAutoSize", false); |
| 213 | + m_ui.videoCaptureWidth->setEnabled(enabled && !auto_enabled); |
| 214 | + m_ui.xLabel->setEnabled(enabled && !auto_enabled); |
| 215 | + m_ui.videoCaptureHeight->setEnabled(enabled && !auto_enabled); |
| 216 | +} |
| 217 | + |
| 218 | +void CaptureSettingsWidget::onMediaCaptureAudioEnabledChanged() |
| 219 | +{ |
| 220 | + const bool enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "AudioCapture", true); |
| 221 | + m_ui.audioCaptureCodecLabel->setEnabled(enabled); |
| 222 | + m_ui.audioCaptureCodec->setEnabled(enabled); |
| 223 | + m_ui.audioCaptureBitrateLabel->setEnabled(enabled); |
| 224 | + m_ui.audioCaptureBitrate->setEnabled(enabled); |
| 225 | + m_ui.enableAudioCaptureArguments->setEnabled(enabled); |
| 226 | + m_ui.audioCaptureArguments->setEnabled(enabled); |
| 227 | +} |
0 commit comments