System: Add video capture feature
This commit is contained in:
@ -21,11 +21,14 @@ FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* dialog, QWidget* pare
|
||||
m_ui.coversOpen, m_ui.coversReset, "Folders", "Covers",
|
||||
Path::Combine(EmuFolders::DataRoot, "covers"));
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(
|
||||
sif, m_ui.screenshots, m_ui.screenshotsBrowse, tr("Select Screenshot Directory"), m_ui.screenshotsOpen,
|
||||
m_ui.screenshotsReset, "Folders", "Screenshots", Path::Combine(EmuFolders::DataRoot, "screenshots"));
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(
|
||||
sif, m_ui.saveStates, m_ui.saveStatesBrowse, tr("Select Save State Directory"), m_ui.saveStatesOpen,
|
||||
sif, m_ui.saveStates, m_ui.saveStatesBrowse, tr("Select Save States Directory"), m_ui.saveStatesOpen,
|
||||
m_ui.saveStatesReset, "Folders", "SaveStates", Path::Combine(EmuFolders::DataRoot, "savestates"));
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(
|
||||
sif, m_ui.screenshots, m_ui.screenshotsBrowse, tr("Select Screenshots Directory"), m_ui.screenshotsOpen,
|
||||
m_ui.screenshotsReset, "Folders", "Screenshots", Path::Combine(EmuFolders::DataRoot, "screenshots"));
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videos, m_ui.videosBrowse, tr("Select Videos Directory"),
|
||||
m_ui.videosOpen, m_ui.videosReset, "Folders", "Videos",
|
||||
Path::Combine(EmuFolders::DataRoot, "videos"));
|
||||
}
|
||||
|
||||
FolderSettingsWidget::~FolderSettingsWidget() = default;
|
||||
|
||||
@ -103,46 +103,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Screenshots Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="screenshots"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="screenshotsBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="screenshotsOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="screenshotsReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Used for screenshots.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
@ -183,10 +143,90 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Screenshots Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="screenshotsOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Used for screenshots.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="screenshotsBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="screenshots"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="screenshotsReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Videos Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="videosOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Used for media capture, regardless of whether audio and/or video is enabled.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="videosBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="videos"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="videosReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
@ -198,5 +238,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
#include "core/gpu.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
#include "util/media_capture.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
static QVariant GetMSAAModeValue(uint multisamples, bool ssaa)
|
||||
@ -202,6 +204,33 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "Display", "ScreenshotQuality",
|
||||
Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.mediaCaptureBackend, "MediaCapture", "Backend",
|
||||
&MediaCapture::ParseBackendName, &MediaCapture::GetBackendName,
|
||||
Settings::DEFAULT_MEDIA_CAPTURE_BACKEND);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCapture, "MediaCapture", "VideoCapture", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureWidth, "MediaCapture", "VideoWidth", 640);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureHeight, "MediaCapture", "VideoHeight", 480);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.videoCaptureResolutionAuto, "MediaCapture", "VideoAutoSize",
|
||||
false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.videoCaptureBitrate, "MediaCapture", "VideoBitrate", 6000);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCaptureArguments, "MediaCapture",
|
||||
"VideoCodecUseArgs", false);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureArguments, "MediaCapture", "AudioCodecArgs");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableAudioCapture, "MediaCapture", "AudioCapture", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.audioCaptureBitrate, "MediaCapture", "AudioBitrate", 128);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCaptureArguments, "MediaCapture",
|
||||
"VideoCodecUseArgs", false);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureArguments, "MediaCapture", "AudioCodecArgs");
|
||||
|
||||
connect(m_ui.mediaCaptureBackend, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onMediaCaptureBackendChanged);
|
||||
connect(m_ui.enableVideoCapture, &QCheckBox::checkStateChanged, this,
|
||||
&GraphicsSettingsWidget::onMediaCaptureVideoEnabledChanged);
|
||||
connect(m_ui.videoCaptureResolutionAuto, &QCheckBox::checkStateChanged, this,
|
||||
&GraphicsSettingsWidget::onMediaCaptureVideoAutoResolutionChanged);
|
||||
connect(m_ui.enableAudioCapture, &QCheckBox::checkStateChanged, this,
|
||||
&GraphicsSettingsWidget::onMediaCaptureAudioEnabledChanged);
|
||||
|
||||
// Texture Replacements Tab
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vramWriteReplacement, "TextureReplacements",
|
||||
@ -241,6 +270,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
onAspectRatioChanged();
|
||||
onDownsampleModeChanged();
|
||||
updateResolutionDependentOptions();
|
||||
onMediaCaptureBackendChanged();
|
||||
onMediaCaptureAudioEnabledChanged();
|
||||
onMediaCaptureVideoEnabledChanged();
|
||||
onEnableAnyTextureReplacementsChanged();
|
||||
onEnableVRAMWriteDumpingChanged();
|
||||
onShowDebugSettingsChanged(QtHost::ShouldShowDebugOptions());
|
||||
@ -483,6 +515,40 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||
QStringLiteral("%1%").arg(Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY),
|
||||
tr("Selects the quality at which screenshots will be compressed. Higher values preserve "
|
||||
"more detail for JPEG, and reduce file size for PNG."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.mediaCaptureBackend, tr("Backend"),
|
||||
QString::fromUtf8(MediaCapture::GetBackendDisplayName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND)),
|
||||
tr("Selects the framework that is used to encode video/audio."));
|
||||
dialog->registerWidgetHelp(m_ui.captureContainer, tr("Container"), tr("MP4"),
|
||||
tr("Determines the file format used to contain the captured audio/video"));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.videoCaptureCodec, tr("Video Codec"), tr("Default"),
|
||||
tr("Selects which Video Codec to be used for Video Capture. <b>If unsure, leave it on default.<b>"));
|
||||
dialog->registerWidgetHelp(m_ui.videoCaptureBitrate, tr("Video Bitrate"), tr("6000 kbps"),
|
||||
tr("Sets the video bitrate to be used. Larger bitrate generally yields better video "
|
||||
"quality at the cost of larger resulting file size."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.videoCaptureResolutionAuto, tr("Automatic Resolution"), tr("Unchecked"),
|
||||
tr("When checked, the video capture resolution will follows the internal resolution of the running "
|
||||
"game. <b>Be careful when using this setting especially when you are upscaling, as higher internal "
|
||||
"resolutions (above 4x) can cause system slowdown.</b>"));
|
||||
dialog->registerWidgetHelp(m_ui.enableVideoCaptureArguments, tr("Enable Extra Video Arguments"), tr("Unchecked"),
|
||||
tr("Allows you to pass arguments to the selected video codec."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.videoCaptureArguments, tr("Extra Video Arguments"), tr("Empty"),
|
||||
tr("Parameters passed to the selected video codec.<br><b>You must use '=' to separate key from value and ':' to "
|
||||
"separate two pairs from each other.</b><br>For example: \"crf = 21 : preset = veryfast\""));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.audioCaptureCodec, tr("Audio Codec"), tr("Default"),
|
||||
tr("Selects which Audio Codec to be used for Video Capture. <b>If unsure, leave it on default.<b>"));
|
||||
dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("160 kbps"),
|
||||
tr("Sets the audio bitrate to be used."));
|
||||
dialog->registerWidgetHelp(m_ui.enableAudioCaptureArguments, tr("Enable Extra Audio Arguments"), tr("Unchecked"),
|
||||
tr("Allows you to pass arguments to the selected audio codec."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.audioCaptureArguments, tr("Extra Audio Arguments"), tr("Empty"),
|
||||
tr("Parameters passed to the selected audio codec.<br><b>You must use '=' to separate key from value and ':' to "
|
||||
"separate two pairs from each other.</b><br>For example: \"compression_level = 4 : joint_stereo = 1\""));
|
||||
|
||||
// Texture Replacements Tab
|
||||
|
||||
@ -625,6 +691,12 @@ void GraphicsSettingsWidget::setupAdditionalUi()
|
||||
QString::fromUtf8(Settings::GetDisplayScreenshotFormatDisplayName(static_cast<DisplayScreenshotFormat>(i))));
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(MediaCaptureBackend::MaxCount); i++)
|
||||
{
|
||||
m_ui.mediaCaptureBackend->addItem(
|
||||
QString::fromUtf8(MediaCapture::GetBackendDisplayName(static_cast<MediaCaptureBackend>(i))));
|
||||
}
|
||||
|
||||
// Debugging Tab
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(GPUWireframeMode::Count); i++)
|
||||
@ -931,6 +1003,110 @@ void GraphicsSettingsWidget::onDownsampleModeChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onMediaCaptureBackendChanged()
|
||||
{
|
||||
SettingsInterface* const sif = m_dialog->getSettingsInterface();
|
||||
const MediaCaptureBackend backend =
|
||||
MediaCapture::ParseBackendName(
|
||||
m_dialog
|
||||
->getEffectiveStringValue("MediaCapture", "Backend",
|
||||
MediaCapture::GetBackendName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND))
|
||||
.c_str())
|
||||
.value_or(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND);
|
||||
|
||||
{
|
||||
m_ui.captureContainer->disconnect();
|
||||
m_ui.captureContainer->clear();
|
||||
|
||||
for (const auto& [name, display_name] : MediaCapture::GetContainerList(backend))
|
||||
{
|
||||
const QString qname = QString::fromStdString(name);
|
||||
m_ui.captureContainer->addItem(tr("%1 (%2)").arg(QString::fromStdString(display_name)).arg(qname), qname);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.captureContainer, "MediaCapture", "Container", "mp4");
|
||||
connect(m_ui.captureContainer, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onMediaCaptureContainerChanged);
|
||||
}
|
||||
|
||||
onMediaCaptureContainerChanged();
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onMediaCaptureContainerChanged()
|
||||
{
|
||||
SettingsInterface* const sif = m_dialog->getSettingsInterface();
|
||||
const MediaCaptureBackend backend =
|
||||
MediaCapture::ParseBackendName(
|
||||
m_dialog
|
||||
->getEffectiveStringValue("MediaCapture", "Backend",
|
||||
MediaCapture::GetBackendName(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND))
|
||||
.c_str())
|
||||
.value_or(Settings::DEFAULT_MEDIA_CAPTURE_BACKEND);
|
||||
const std::string container = m_dialog->getEffectiveStringValue("MediaCapture", "Container", "mp4");
|
||||
|
||||
{
|
||||
m_ui.videoCaptureCodec->disconnect();
|
||||
m_ui.videoCaptureCodec->clear();
|
||||
m_ui.videoCaptureCodec->addItem(tr("Default"), QVariant(QString()));
|
||||
|
||||
for (const auto& [name, display_name] : MediaCapture::GetVideoCodecList(backend, container.c_str()))
|
||||
{
|
||||
const QString qname = QString::fromStdString(name);
|
||||
m_ui.videoCaptureCodec->addItem(tr("%1 (%2)").arg(QString::fromStdString(display_name)).arg(qname), qname);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureCodec, "MediaCapture", "VideoCodec");
|
||||
}
|
||||
|
||||
{
|
||||
m_ui.audioCaptureCodec->disconnect();
|
||||
m_ui.audioCaptureCodec->clear();
|
||||
m_ui.audioCaptureCodec->addItem(tr("Default"), QVariant(QString()));
|
||||
|
||||
for (const auto& [name, display_name] : MediaCapture::GetAudioCodecList(backend, container.c_str()))
|
||||
{
|
||||
const QString qname = QString::fromStdString(name);
|
||||
m_ui.audioCaptureCodec->addItem(tr("%1 (%2)").arg(QString::fromStdString(display_name)).arg(qname), qname);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureCodec, "MediaCapture", "AudioCodec");
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onMediaCaptureVideoEnabledChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "VideoCapture", true);
|
||||
m_ui.videoCaptureCodecLabel->setEnabled(enabled);
|
||||
m_ui.videoCaptureCodec->setEnabled(enabled);
|
||||
m_ui.videoCaptureBitrateLabel->setEnabled(enabled);
|
||||
m_ui.videoCaptureBitrate->setEnabled(enabled);
|
||||
m_ui.videoCaptureResolutionLabel->setEnabled(enabled);
|
||||
m_ui.videoCaptureResolutionAuto->setEnabled(enabled);
|
||||
m_ui.enableVideoCaptureArguments->setEnabled(enabled);
|
||||
m_ui.videoCaptureArguments->setEnabled(enabled);
|
||||
onMediaCaptureVideoAutoResolutionChanged();
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onMediaCaptureVideoAutoResolutionChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "VideoCapture", true);
|
||||
const bool auto_enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "VideoAutoSize", false);
|
||||
m_ui.videoCaptureWidth->setEnabled(enabled && !auto_enabled);
|
||||
m_ui.xLabel->setEnabled(enabled && !auto_enabled);
|
||||
m_ui.videoCaptureHeight->setEnabled(enabled && !auto_enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onMediaCaptureAudioEnabledChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("MediaCapture", "AudioCapture", true);
|
||||
m_ui.audioCaptureCodecLabel->setEnabled(enabled);
|
||||
m_ui.audioCaptureCodec->setEnabled(enabled);
|
||||
m_ui.audioCaptureBitrateLabel->setEnabled(enabled);
|
||||
m_ui.audioCaptureBitrate->setEnabled(enabled);
|
||||
m_ui.enableAudioCaptureArguments->setEnabled(enabled);
|
||||
m_ui.audioCaptureArguments->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged()
|
||||
{
|
||||
const bool any_replacements_enabled =
|
||||
|
||||
@ -32,6 +32,13 @@ private Q_SLOTS:
|
||||
void updateResolutionDependentOptions();
|
||||
void onTrueColorChanged();
|
||||
void onDownsampleModeChanged();
|
||||
|
||||
void onMediaCaptureBackendChanged();
|
||||
void onMediaCaptureContainerChanged();
|
||||
void onMediaCaptureVideoEnabledChanged();
|
||||
void onMediaCaptureVideoAutoResolutionChanged();
|
||||
void onMediaCaptureAudioEnabledChanged();
|
||||
|
||||
void onEnableAnyTextureReplacementsChanged();
|
||||
void onEnableVRAMWriteDumpingChanged();
|
||||
|
||||
|
||||
@ -817,6 +817,244 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="captureTabGroupBox">
|
||||
<property name="title">
|
||||
<string>Media Capture</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="captureTabGroupBoxLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Backend:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="mediaCaptureBackend"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="captureContainerLabel">
|
||||
<property name="text">
|
||||
<string>Container:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="captureContainer"/>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="captureOptionLayout" columnstretch="1,1">
|
||||
<property name="horizontalSpacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="audioCaptureOptions" native="true">
|
||||
<layout class="QFormLayout" name="audioCaptureOptionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="audioCaptureCodecLabel">
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="audioCaptureCodec"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="audioCaptureBitrateLabel">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="audioCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2048</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="enableAudioCaptureArguments">
|
||||
<property name="text">
|
||||
<string>Extra Arguments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="audioCaptureArguments"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="enableAudioCapture">
|
||||
<property name="text">
|
||||
<string>Capture Audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="videoCaptureOptions" native="true">
|
||||
<layout class="QFormLayout" name="videoCaptureOptionsLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="videoCaptureCodecLabel">
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="videoCaptureCodec"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="videoCaptureBitrateLabel">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="videoCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string extracomment="Unit that will appear next to a number. Alter the space or whatever is needed before the text depending on your language."> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>6000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="videoCaptureResolutionLabel">
|
||||
<property name="text">
|
||||
<string>Resolution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="videoCaptureSizeLayout" stretch="1,0,1,0">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureWidth">
|
||||
<property name="minimum">
|
||||
<number>320</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>640</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="xLabel">
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureHeight">
|
||||
<property name="minimum">
|
||||
<number>240</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>480</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="videoCaptureResolutionAuto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="videoCaptureArguments"/>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="enableVideoCaptureArguments">
|
||||
<property name="text">
|
||||
<string>Extra Arguments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="enableVideoCapture">
|
||||
<property name="text">
|
||||
<string>Capture Video</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
|
||||
@ -623,6 +623,18 @@ void MainWindow::onRunningGameChanged(const QString& filename, const QString& ga
|
||||
updateWindowTitle();
|
||||
}
|
||||
|
||||
void MainWindow::onMediaCaptureStarted()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.actionMediaCapture);
|
||||
m_ui.actionMediaCapture->setChecked(true);
|
||||
}
|
||||
|
||||
void MainWindow::onMediaCaptureStopped()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.actionMediaCapture);
|
||||
m_ui.actionMediaCapture->setChecked(false);
|
||||
}
|
||||
|
||||
void MainWindow::onApplicationStateChanged(Qt::ApplicationState state)
|
||||
{
|
||||
if (!s_system_valid)
|
||||
@ -1122,7 +1134,7 @@ const GameList::Entry* MainWindow::resolveDiscSetEntry(const GameList::Entry* en
|
||||
std::shared_ptr<SystemBootParameters> MainWindow::getSystemBootParameters(std::string file)
|
||||
{
|
||||
std::shared_ptr<SystemBootParameters> ret = std::make_shared<SystemBootParameters>(std::move(file));
|
||||
ret->start_audio_dump = m_ui.actionDumpAudio->isChecked();
|
||||
ret->start_media_capture = m_ui.actionMediaCapture->isChecked();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2103,6 +2115,7 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.actionMemoryCardEditor, &QAction::triggered, this, &MainWindow::onToolsMemoryCardEditorTriggered);
|
||||
connect(m_ui.actionMemoryScanner, &QAction::triggered, this, &MainWindow::onToolsMemoryScannerTriggered);
|
||||
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||
connect(m_ui.actionMediaCapture, &QAction::toggled, this, &MainWindow::onToolsMediaCaptureToggled);
|
||||
connect(m_ui.actionCPUDebugger, &QAction::triggered, this, &MainWindow::openCPUDebugger);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableGDBServer, "Debug", "EnableGDBServer", false);
|
||||
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
||||
@ -2137,6 +2150,8 @@ void MainWindow::connectSignals()
|
||||
connect(g_emu_thread, &EmuThread::systemPaused, this, &MainWindow::onSystemPaused);
|
||||
connect(g_emu_thread, &EmuThread::systemResumed, this, &MainWindow::onSystemResumed);
|
||||
connect(g_emu_thread, &EmuThread::runningGameChanged, this, &MainWindow::onRunningGameChanged);
|
||||
connect(g_emu_thread, &EmuThread::mediaCaptureStarted, this, &MainWindow::onMediaCaptureStarted);
|
||||
connect(g_emu_thread, &EmuThread::mediaCaptureStopped, this, &MainWindow::onMediaCaptureStopped);
|
||||
connect(g_emu_thread, &EmuThread::mouseModeRequested, this, &MainWindow::onMouseModeRequested);
|
||||
connect(g_emu_thread, &EmuThread::fullscreenUIStateChange, this, &MainWindow::onFullscreenUIStateChange);
|
||||
connect(g_emu_thread, &EmuThread::achievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested);
|
||||
@ -2162,12 +2177,6 @@ void MainWindow::connectSignals()
|
||||
"DumpCPUToVRAMCopies", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionDebugDumpVRAMtoCPUCopies, "Debug",
|
||||
"DumpVRAMToCPUCopies", false);
|
||||
connect(m_ui.actionDumpAudio, &QAction::toggled, [](bool checked) {
|
||||
if (checked)
|
||||
g_emu_thread->startDumpingAudio();
|
||||
else
|
||||
g_emu_thread->stopDumpingAudio();
|
||||
});
|
||||
connect(m_ui.actionDumpRAM, &QAction::triggered, [this]() {
|
||||
const QString filename = QDir::toNativeSeparators(
|
||||
QFileDialog::getSaveFileName(this, tr("Destination File"), QString(), tr("Binary Files (*.bin)")));
|
||||
@ -3034,6 +3043,41 @@ void MainWindow::onToolsCoverDownloaderTriggered()
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void MainWindow::onToolsMediaCaptureToggled(bool checked)
|
||||
{
|
||||
if (!QtHost::IsSystemValid())
|
||||
{
|
||||
// leave it for later, we'll fill in the boot params
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
Host::RunOnCPUThread(&System::StopMediaCapture);
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string container =
|
||||
Host::GetStringSettingValue("MediaCapture", "Container", Settings::DEFAULT_MEDIA_CAPTURE_CONTAINER);
|
||||
const QString qcontainer = QString::fromStdString(container);
|
||||
const QString filter(tr("%1 Files (*.%2)").arg(qcontainer.toUpper()).arg(qcontainer));
|
||||
|
||||
QString path =
|
||||
QString::fromStdString(System::GetNewMediaCapturePath(QtHost::GetCurrentGameTitle().toStdString(), container));
|
||||
path = QDir::toNativeSeparators(QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter));
|
||||
if (path.isEmpty())
|
||||
{
|
||||
// uncheck it again
|
||||
const QSignalBlocker sb(m_ui.actionMediaCapture);
|
||||
m_ui.actionMediaCapture->setChecked(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Host::RunOnCPUThread([path = path.toStdString()]() {
|
||||
System::StartMediaCapture(path, g_settings.media_capture_video, g_settings.media_capture_audio);
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::onToolsMemoryScannerTriggered()
|
||||
{
|
||||
if (Achievements::IsHardcoreModeActive())
|
||||
|
||||
@ -140,6 +140,8 @@ private Q_SLOTS:
|
||||
void onSystemPaused();
|
||||
void onSystemResumed();
|
||||
void onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title);
|
||||
void onMediaCaptureStarted();
|
||||
void onMediaCaptureStopped();
|
||||
void onAchievementsLoginRequested(Achievements::LoginRequestReason reason);
|
||||
void onAchievementsChallengeModeChanged(bool enabled);
|
||||
void onApplicationStateChanged(Qt::ApplicationState state);
|
||||
@ -174,6 +176,7 @@ private Q_SLOTS:
|
||||
void onToolsMemoryCardEditorTriggered();
|
||||
void onToolsMemoryScannerTriggered();
|
||||
void onToolsCoverDownloaderTriggered();
|
||||
void onToolsMediaCaptureToggled(bool checked);
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
void onSettingsTriggeredFromToolbar();
|
||||
|
||||
|
||||
@ -188,7 +188,6 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionDebugDumpCPUtoVRAMCopies"/>
|
||||
<addaction name="actionDebugDumpVRAMtoCPUCopies"/>
|
||||
<addaction name="actionDumpAudio"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionDebugShowVRAM"/>
|
||||
<addaction name="actionDebugShowGPUState"/>
|
||||
@ -234,6 +233,8 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMemoryScanner"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMediaCapture"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOpenDataDirectory"/>
|
||||
</widget>
|
||||
<addaction name="menuSystem"/>
|
||||
@ -663,14 +664,6 @@
|
||||
<string>Disable All Enhancements</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDumpAudio">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dump Audio</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDumpRAM">
|
||||
<property name="text">
|
||||
<string>Dump RAM...</string>
|
||||
@ -945,6 +938,14 @@
|
||||
<string>Show Game Icons (List View)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMediaCapture">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Media Ca&pture</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources/duckstation-qt.qrc"/>
|
||||
|
||||
@ -1481,7 +1481,7 @@ void EmuThread::startDumpingAudio()
|
||||
return;
|
||||
}
|
||||
|
||||
System::StartDumpingAudio();
|
||||
//System::StartDumpingAudio();
|
||||
}
|
||||
|
||||
void EmuThread::stopDumpingAudio()
|
||||
@ -1492,7 +1492,7 @@ void EmuThread::stopDumpingAudio()
|
||||
return;
|
||||
}
|
||||
|
||||
System::StopDumpingAudio();
|
||||
//System::StopDumpingAudio();
|
||||
}
|
||||
|
||||
void EmuThread::singleStepCPU()
|
||||
@ -2065,6 +2065,16 @@ void Host::OnGameChanged(const std::string& disc_path, const std::string& game_s
|
||||
QString::fromStdString(game_name));
|
||||
}
|
||||
|
||||
void Host::OnMediaCaptureStarted()
|
||||
{
|
||||
emit g_emu_thread->mediaCaptureStarted();
|
||||
}
|
||||
|
||||
void Host::OnMediaCaptureStopped()
|
||||
{
|
||||
emit g_emu_thread->mediaCaptureStopped();
|
||||
}
|
||||
|
||||
void Host::SetMouseMode(bool relative, bool hide_cursor)
|
||||
{
|
||||
emit g_emu_thread->mouseModeRequested(relative, hide_cursor);
|
||||
|
||||
@ -148,6 +148,8 @@ Q_SIGNALS:
|
||||
void achievementsRefreshed(quint32 id, const QString& game_info_string);
|
||||
void achievementsChallengeModeChanged(bool enabled);
|
||||
void cheatEnabled(quint32 index, bool enabled);
|
||||
void mediaCaptureStarted();
|
||||
void mediaCaptureStopped();
|
||||
|
||||
/// Big Picture UI requests.
|
||||
void onCoverDownloaderOpenRequested();
|
||||
|
||||
Reference in New Issue
Block a user