mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									e769d90aa8
								
							
						
					
					
						commit
						f82ba41fe0
					
				
					 3 changed files with 434 additions and 0 deletions
				
			
		
							
								
								
									
										210
									
								
								src/citra_qt/dumping/dumping_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								src/citra_qt/dumping/dumping_dialog.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,210 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <QFileDialog> | ||||
| #include <QMessageBox> | ||||
| #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::DumpingDialog>()) { | ||||
| 
 | ||||
|     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<int>(&QComboBox::currentIndexChanged), [this] { | ||||
|         ui->pathLineEdit->setText(QString{}); | ||||
|         format_options.clear(); | ||||
|         PopulateEncoders(); | ||||
|     }); | ||||
| 
 | ||||
|     connect(ui->videoEncoderComboBox, qOverload<int>(&QComboBox::currentIndexChanged), | ||||
|             [this] { video_encoder_options.clear(); }); | ||||
|     connect(ui->audioEncoderComboBox, qOverload<int>(&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<unsigned long long>(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<unsigned long long>(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<unsigned long long>(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<VideoDumper::OptionInfo>& 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<int>(Settings::values.video_bitrate)); | ||||
|     ui->audioBitrateSpinBox->setValue(static_cast<int>(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(); | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/citra_qt/dumping/dumping_dialog.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/citra_qt/dumping/dumping_dialog.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| // Copyright 2020 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <QDialog> | ||||
| #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<VideoDumper::OptionInfo>& options, | ||||
|                            std::string& current_value); | ||||
| 
 | ||||
|     std::unique_ptr<Ui::DumpingDialog> ui; | ||||
|     std::string format_options; | ||||
|     std::string video_encoder_options; | ||||
|     std::string audio_encoder_options; | ||||
| 
 | ||||
|     QString last_path; | ||||
| 
 | ||||
|     std::vector<VideoDumper::FormatInfo> formats; | ||||
|     std::vector<VideoDumper::EncoderInfo> video_encoders; | ||||
|     std::vector<VideoDumper::EncoderInfo> audio_encoders; | ||||
| }; | ||||
							
								
								
									
										183
									
								
								src/citra_qt/dumping/dumping_dialog.ui
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/citra_qt/dumping/dumping_dialog.ui
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,183 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>DumpingDialog</class> | ||||
|  <widget class="QDialog" name="DumpingDialog"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>600</width> | ||||
|     <height>360</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Dump Video</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout"> | ||||
|    <item> | ||||
|     <widget class="QGroupBox"> | ||||
|      <property name="title"> | ||||
|       <string>Output</string> | ||||
|      </property> | ||||
|      <layout class="QGridLayout"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Format:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="formatComboBox"/> | ||||
|       </item> | ||||
|       <item row="0" column="2"> | ||||
|        <widget class="QPushButton" name="formatOptionsButton"> | ||||
|         <property name="text"> | ||||
|          <string>Options...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Path:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QLineEdit" name="pathLineEdit"/> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QToolButton" name="pathExplore"> | ||||
|         <property name="text"> | ||||
|          <string>...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QGroupBox"> | ||||
|      <property name="title"> | ||||
|       <string>Video</string> | ||||
|      </property> | ||||
|      <layout class="QGridLayout"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Encoder:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="videoEncoderComboBox"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="2"> | ||||
|        <widget class="QPushButton" name="videoEncoderOptionsButton"> | ||||
|         <property name="text"> | ||||
|          <string>Options...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Bitrate:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QSpinBox" name="videoBitrateSpinBox"> | ||||
|         <property name="maximum"> | ||||
|          <number>10000000</number> | ||||
|         </property> | ||||
|         <property name="singleStep"> | ||||
|          <number>1000</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>bps</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QGroupBox"> | ||||
|      <property name="title"> | ||||
|       <string>Audio</string> | ||||
|      </property> | ||||
|      <layout class="QGridLayout"> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Encoder:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1"> | ||||
|        <widget class="QComboBox" name="audioEncoderComboBox"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="2"> | ||||
|        <widget class="QPushButton" name="audioEncoderOptionsButton"> | ||||
|         <property name="text"> | ||||
|          <string>Options...</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>Bitrate:</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="1"> | ||||
|        <widget class="QSpinBox" name="audioBitrateSpinBox"> | ||||
|         <property name="maximum"> | ||||
|          <number>1000000</number> | ||||
|         </property> | ||||
|         <property name="singleStep"> | ||||
|          <number>100</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QLabel"> | ||||
|         <property name="text"> | ||||
|          <string>bps</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <widget class="QDialogButtonBox" name="buttonBox"> | ||||
|      <property name="standardButtons"> | ||||
|       <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> | ||||
|      </property> | ||||
|     </widget> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
| </ui> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue