From f82ba41fe0ccbfbb4db3cbfdbde54453b42bbf4d Mon Sep 17 00:00:00 2001 From: zhupengfei Date: Sat, 1 Feb 2020 12:38:13 +0800 Subject: [PATCH] citra_qt/dumping: Add dumping dialog This is the main dialog of video dumping. This dialog allows the user to set output format, output path, video/audio encoder and video/audio bitrate. When a format is selected, the list of video and audio encoders are updated. Only encoders of codecs that can be contained in the format is shown. --- src/citra_qt/dumping/dumping_dialog.cpp | 210 ++++++++++++++++++++++++ src/citra_qt/dumping/dumping_dialog.h | 41 +++++ src/citra_qt/dumping/dumping_dialog.ui | 183 +++++++++++++++++++++ 3 files changed, 434 insertions(+) create mode 100644 src/citra_qt/dumping/dumping_dialog.cpp create mode 100644 src/citra_qt/dumping/dumping_dialog.h create mode 100644 src/citra_qt/dumping/dumping_dialog.ui diff --git a/src/citra_qt/dumping/dumping_dialog.cpp b/src/citra_qt/dumping/dumping_dialog.cpp new file mode 100644 index 000000000..ee5fe6b2a --- /dev/null +++ b/src/citra_qt/dumping/dumping_dialog.cpp @@ -0,0 +1,210 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "citra_qt/dumping/dumping_dialog.h" +#include "citra_qt/dumping/options_dialog.h" +#include "citra_qt/uisettings.h" +#include "core/settings.h" +#include "ui_dumping_dialog.h" + +DumpingDialog::DumpingDialog(QWidget* parent) + : QDialog(parent), ui(std::make_unique()) { + + ui->setupUi(this); + + connect(ui->pathExplore, &QToolButton::clicked, this, &DumpingDialog::OnToolButtonClicked); + connect(ui->buttonBox, &QDialogButtonBox::accepted, [this] { + ApplyConfiguration(); + accept(); + }); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &DumpingDialog::reject); + connect(ui->formatOptionsButton, &QPushButton::clicked, [this] { + OpenOptionsDialog(formats.at(ui->formatComboBox->currentData().toUInt()).options, + format_options); + }); + connect(ui->videoEncoderOptionsButton, &QPushButton::clicked, [this] { + OpenOptionsDialog( + video_encoders.at(ui->videoEncoderComboBox->currentData().toUInt()).options, + video_encoder_options); + }); + connect(ui->audioEncoderOptionsButton, &QPushButton::clicked, [this] { + OpenOptionsDialog( + audio_encoders.at(ui->audioEncoderComboBox->currentData().toUInt()).options, + audio_encoder_options); + }); + + SetConfiguration(); + + connect(ui->formatComboBox, qOverload(&QComboBox::currentIndexChanged), [this] { + ui->pathLineEdit->setText(QString{}); + format_options.clear(); + PopulateEncoders(); + }); + + connect(ui->videoEncoderComboBox, qOverload(&QComboBox::currentIndexChanged), + [this] { video_encoder_options.clear(); }); + connect(ui->audioEncoderComboBox, qOverload(&QComboBox::currentIndexChanged), + [this] { audio_encoder_options.clear(); }); +} + +DumpingDialog::~DumpingDialog() = default; + +QString DumpingDialog::GetFilePath() const { + return ui->pathLineEdit->text(); +} + +void DumpingDialog::Populate() { + formats = VideoDumper::ListFormats(); + video_encoders = VideoDumper::ListEncoders(AVMEDIA_TYPE_VIDEO); + audio_encoders = VideoDumper::ListEncoders(AVMEDIA_TYPE_AUDIO); + + // Check that these are not empty + QString missing; + if (formats.empty()) { + missing = tr("output formats"); + } + if (video_encoders.empty()) { + missing = tr("video encoders"); + } + if (audio_encoders.empty()) { + missing = tr("audio encoders"); + } + + if (!missing.isEmpty()) { + QMessageBox::critical(this, tr("Citra"), + tr("Could not find any available %1.\nPlease check your FFmpeg " + "installation used for compilation.") + .arg(missing)); + reject(); + return; + } + + // Populate formats + for (std::size_t i = 0; i < formats.size(); ++i) { + const auto& format = formats[i]; + + // Check format: only formats that have video encoders and audio encoders are displayed + bool has_video = false; + for (const auto& video_encoder : video_encoders) { + if (format.supported_video_codecs.count(video_encoder.codec)) { + has_video = true; + break; + } + } + if (!has_video) + continue; + + bool has_audio = false; + for (const auto& audio_encoder : audio_encoders) { + if (format.supported_audio_codecs.count(audio_encoder.codec)) { + has_audio = true; + break; + } + } + if (!has_audio) + continue; + + ui->formatComboBox->addItem(tr("%1 (%2)").arg(QString::fromStdString(format.long_name), + QString::fromStdString(format.name)), + static_cast(i)); + if (format.name == Settings::values.output_format) { + ui->formatComboBox->setCurrentIndex(ui->formatComboBox->count() - 1); + } + } + PopulateEncoders(); +} + +void DumpingDialog::PopulateEncoders() { + const auto& format = formats.at(ui->formatComboBox->currentData().toUInt()); + + ui->videoEncoderComboBox->clear(); + for (std::size_t i = 0; i < video_encoders.size(); ++i) { + const auto& video_encoder = video_encoders[i]; + if (!format.supported_video_codecs.count(video_encoder.codec)) { + continue; + } + + ui->videoEncoderComboBox->addItem( + tr("%1 (%2)").arg(QString::fromStdString(video_encoder.long_name), + QString::fromStdString(video_encoder.name)), + static_cast(i)); + if (video_encoder.name == Settings::values.video_encoder) { + ui->videoEncoderComboBox->setCurrentIndex(ui->videoEncoderComboBox->count() - 1); + } + } + + ui->audioEncoderComboBox->clear(); + for (std::size_t i = 0; i < audio_encoders.size(); ++i) { + const auto& audio_encoder = audio_encoders[i]; + if (!format.supported_audio_codecs.count(audio_encoder.codec)) { + continue; + } + + ui->audioEncoderComboBox->addItem( + tr("%1 (%2)").arg(QString::fromStdString(audio_encoder.long_name), + QString::fromStdString(audio_encoder.name)), + static_cast(i)); + if (audio_encoder.name == Settings::values.audio_encoder) { + ui->audioEncoderComboBox->setCurrentIndex(ui->audioEncoderComboBox->count() - 1); + } + } +} + +void DumpingDialog::OnToolButtonClicked() { + const auto& format = formats.at(ui->formatComboBox->currentData().toUInt()); + + QString extensions; + for (const auto& ext : format.extensions) { + if (!extensions.isEmpty()) { + extensions.append(QLatin1Char{' '}); + } + extensions.append(QStringLiteral("*.%1").arg(QString::fromStdString(ext))); + } + + const auto path = QFileDialog::getSaveFileName( + this, tr("Select Video Output Path"), last_path, + tr("%1 (%2)").arg(QString::fromStdString(format.long_name), extensions)); + if (!path.isEmpty()) { + last_path = QFileInfo(ui->pathLineEdit->text()).path(); + ui->pathLineEdit->setText(path); + } +} + +void DumpingDialog::OpenOptionsDialog(const std::vector& options, + std::string& current_value) { + OptionsDialog dialog(this, options, current_value); + if (dialog.exec() != QDialog::DialogCode::Accepted) { + return; + } + + current_value = dialog.GetCurrentValue(); +} + +void DumpingDialog::SetConfiguration() { + Populate(); + + format_options = Settings::values.format_options; + video_encoder_options = Settings::values.video_encoder_options; + audio_encoder_options = Settings::values.audio_encoder_options; + last_path = UISettings::values.video_dumping_path; + ui->videoBitrateSpinBox->setValue(static_cast(Settings::values.video_bitrate)); + ui->audioBitrateSpinBox->setValue(static_cast(Settings::values.audio_bitrate)); +} + +void DumpingDialog::ApplyConfiguration() { + Settings::values.output_format = formats.at(ui->formatComboBox->currentData().toUInt()).name; + Settings::values.format_options = format_options; + Settings::values.video_encoder = + video_encoders.at(ui->videoEncoderComboBox->currentData().toUInt()).name; + Settings::values.video_encoder_options = video_encoder_options; + Settings::values.video_bitrate = ui->videoBitrateSpinBox->value(); + Settings::values.audio_encoder = + audio_encoders.at(ui->audioEncoderComboBox->currentData().toUInt()).name; + Settings::values.audio_encoder_options = audio_encoder_options; + Settings::values.audio_bitrate = ui->audioBitrateSpinBox->value(); + UISettings::values.video_dumping_path = last_path; + Settings::Apply(); +} diff --git a/src/citra_qt/dumping/dumping_dialog.h b/src/citra_qt/dumping/dumping_dialog.h new file mode 100644 index 000000000..7476770ba --- /dev/null +++ b/src/citra_qt/dumping/dumping_dialog.h @@ -0,0 +1,41 @@ +// Copyright 2020 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "core/dumping/ffmpeg_backend.h" + +namespace Ui { +class DumpingDialog; +} + +class DumpingDialog : public QDialog { + Q_OBJECT + +public: + explicit DumpingDialog(QWidget* parent); + ~DumpingDialog() override; + + QString GetFilePath() const; + void ApplyConfiguration(); + +private: + void Populate(); + void PopulateEncoders(); + void SetConfiguration(); + void OnToolButtonClicked(); + void OpenOptionsDialog(const std::vector& options, + std::string& current_value); + + std::unique_ptr ui; + std::string format_options; + std::string video_encoder_options; + std::string audio_encoder_options; + + QString last_path; + + std::vector formats; + std::vector video_encoders; + std::vector audio_encoders; +}; diff --git a/src/citra_qt/dumping/dumping_dialog.ui b/src/citra_qt/dumping/dumping_dialog.ui new file mode 100644 index 000000000..a3468ed3f --- /dev/null +++ b/src/citra_qt/dumping/dumping_dialog.ui @@ -0,0 +1,183 @@ + + + DumpingDialog + + + + 0 + 0 + 600 + 360 + + + + Dump Video + + + + + + Output + + + + + + Format: + + + + + + + + + + Options... + + + + + + + Path: + + + + + + + + + + ... + + + + + + + + + + Video + + + + + + Encoder: + + + + + + + + 0 + 0 + + + + + + + + Options... + + + + + + + Bitrate: + + + + + + + 10000000 + + + 1000 + + + + + + + bps + + + + + + + + + + Audio + + + + + + Encoder: + + + + + + + + 0 + 0 + + + + + + + + Options... + + + + + + + Bitrate: + + + + + + + 1000000 + + + 100 + + + + + + + bps + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + +