From 5d9c70db0395971a8950cca4872ef34687697c1f Mon Sep 17 00:00:00 2001 From: lordmulder Date: Mon, 10 Feb 2014 21:33:04 +0100 Subject: [PATCH] Initial multi-encoder support. This will allow adding support for x265 in a future version. Also it makes switching between 32-Bit/64-Bit and 8-Bit/10-Bit x264 binaries more convenient. --- gui/win_addJob.ui | 248 +++++++++++++++++++++++++++++++----------- src/model_options.cpp | 61 ++++++++--- src/model_options.h | 34 +++++- src/thread_encode.cpp | 6 +- src/version.h | 2 +- src/win_addJob.cpp | 83 +++++++------- src/win_addJob.h | 6 +- 7 files changed, 307 insertions(+), 133 deletions(-) diff --git a/gui/win_addJob.ui b/gui/win_addJob.ui index 6ad4278..b073624 100644 --- a/gui/win_addJob.ui +++ b/gui/win_addJob.ui @@ -6,8 +6,8 @@ 0 0 - 569 - 614 + 557 + 611 @@ -29,26 +29,19 @@ Input / Output - - - - Qt::Vertical - - - - 0 - 0 - - - - + + 3 + + + 3 + - 4 + 1 - + Select the source video file. This can be an Avisynth/VapourSynth script or any type of video file supported by FFmpegSource2 (libavformat). @@ -86,26 +79,13 @@ - - - - Qt::Vertical - - - - 0 - 0 - - - - - 4 + 1 - + Select the output H.264/AVC file. This can be a Matroska (MKV,) MPEG-4 Part-14 (MP4) or "raw" H.264 file. @@ -143,19 +123,6 @@ - - - - Qt::Vertical - - - - 0 - 0 - - - - @@ -165,10 +132,13 @@ Configuration + + 3 + - + Here you can load a user-defined template that you have saved before. Use the "Save As" button to save your current configuration to a new template. @@ -253,20 +223,139 @@ - - - Qt::Vertical + + + Encoder Selection - - QSizePolicy::Fixed - - - - 20 - 4 - - - + + + 3 + + + + + + + 2 + + + + + Encoder: + + + + + + + + x264 (AVC) + + + + + x265 (HEVC) + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 20 + + + + + + + + 2 + + + + + Architecture: + + + + + + + 1 + + + + 32-Bit (x86) + + + + + 64-Bit (x86_64) + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 20 + + + + + + + + 2 + + + + + Variant: + + + + + + + + 8-Bit + + + + + 10-Bit + + + + + + + + + + @@ -280,6 +369,9 @@ Rate Control + + 3 + @@ -297,8 +389,11 @@ + + 2 + - + Select the x264 rate-control mode. Use 'CRF' mode to hit a specific level of quality or use '2-Pass' mode to hit a specific file size. @@ -357,8 +452,11 @@ + + 2 + - + Select the quantizer or CRF value. Smaller value means better quality, but bigger file. Higher value means smaller file, but lower quality. A value of '0' triggers lossless mode. @@ -403,8 +501,11 @@ + + 2 + - + Select the target average(!) bitrate, in kilobit/sec. Higher value means better quality, but bigger file. Lower value means smaller file, but lower quality. @@ -461,6 +562,9 @@ Basic Encoder Options + + 3 + @@ -478,8 +582,11 @@ + + 2 + - + This option controls the "Speed -vs- Quality" trade-off. Use a slower preset to improve the quality at the same bitrate (file size). Use a faster preset to save encoding time, at the cost of reduced quality. @@ -568,8 +675,11 @@ + + 2 + - + This option tweaks x264 for a specific type of source/content. For real-life footage, CGI and most other stuff, use the "Film" option. For anime/cartoon use the "Animation" option. @@ -658,8 +768,11 @@ + + 2 + - + This option can be used to enforce the restrictions of a specific H.264/AVC Proifle, though it won't force a higher profile than needed. Use "Auto" for an unrestricted encode. @@ -745,6 +858,9 @@ Advanced Encoder Options + + 3 + @@ -777,7 +893,7 @@ <nobr>All command&minus;line parameters you enter here will be passed to x264 unmodified and unchecked. Some parameters are forbidden, as they are reserved for the GUI.<br>The following macros can be used:<tt> $(INPUT)</tt> expands to the current source file path and<tt> $(OUTPUT)</tt> expands to the current output file path.</nobr> - Custom x264 Parameters: + Custom Encoder Parameters: diff --git a/src/model_options.cpp b/src/model_options.cpp index 26dc410..9888ca6 100644 --- a/src/model_options.cpp +++ b/src/model_options.cpp @@ -28,15 +28,38 @@ #include #include +#define COMPARE_VAL(OTHER, NAME) ((this->NAME) == (OTHER->NAME)) +#define COMPARE_STR(OTHER, NAME) ((this->NAME).compare((model->NAME), Qt::CaseInsensitive) == 0) +#define ASSIGN_FROM(OTHER, NAME) ((this->NAME) = (OTHER.NAME)) + OptionsModel::OptionsModel(void) { + m_encoderType = EncType_X264; + m_encoderArch = EncArch_x32; + m_encoderVariant = EncVariant_LoBit; m_rcMode = RCMode_CRF; m_bitrate = 1200; m_quantizer = 22; m_preset = "Medium"; m_tune = "None"; m_profile = "Auto"; - m_custom_x264 = ""; + m_custom_encoder = ""; + m_custom_avs2yuv = ""; +} + +OptionsModel::OptionsModel(const OptionsModel &rhs) +{ + ASSIGN_FROM(rhs, m_encoderType); + ASSIGN_FROM(rhs, m_encoderArch); + ASSIGN_FROM(rhs, m_encoderVariant); + ASSIGN_FROM(rhs, m_rcMode); + ASSIGN_FROM(rhs, m_bitrate); + ASSIGN_FROM(rhs, m_quantizer); + ASSIGN_FROM(rhs, m_preset); + ASSIGN_FROM(rhs, m_tune); + ASSIGN_FROM(rhs, m_profile); + ASSIGN_FROM(rhs, m_custom_encoder); + ASSIGN_FROM(rhs, m_custom_avs2yuv); } OptionsModel::~OptionsModel(void) @@ -68,15 +91,18 @@ QString OptionsModel::rcMode2String(RCMode mode) bool OptionsModel::equals(OptionsModel *model) { bool equal = true; - - if(this->m_rcMode != model->m_rcMode) equal = false; - if(this->m_bitrate!= model->m_bitrate) equal = false; - if(this->m_quantizer != model->m_quantizer) equal = false; - if(this->m_preset.compare(model->m_preset, Qt::CaseInsensitive)) equal = false; - if(this->m_tune.compare(model->m_tune, Qt::CaseInsensitive)) equal = false; - if(this->m_profile.compare(model->m_profile, Qt::CaseInsensitive)) equal = false; - if(this->m_custom_x264.compare(model->m_custom_x264, Qt::CaseInsensitive)) equal = false; - if(this->m_custom_avs2yuv.compare(model->m_custom_avs2yuv, Qt::CaseInsensitive)) equal = false; + + equal = equal && COMPARE_VAL(model, m_encoderType); + equal = equal && COMPARE_VAL(model, m_encoderArch); + equal = equal && COMPARE_VAL(model, m_encoderVariant); + equal = equal && COMPARE_VAL(model, m_rcMode); + equal = equal && COMPARE_VAL(model, m_bitrate); + equal = equal && COMPARE_VAL(model, m_quantizer); + equal = equal && COMPARE_STR(model, m_preset); + equal = equal && COMPARE_STR(model, m_tune); + equal = equal && COMPARE_STR(model, m_profile); + equal = equal && COMPARE_STR(model, m_custom_encoder); + equal = equal && COMPARE_STR(model, m_custom_avs2yuv); return equal; } @@ -94,13 +120,16 @@ bool OptionsModel::saveTemplate(OptionsModel *model, const QString &name) QSettings settings(QString("%1/templates.ini").arg(appDir), QSettings::IniFormat); settings.beginGroup(templateName); + settings.setValue("encoder_type", model->m_encoderType); + settings.setValue("encoder_arch", model->m_encoderArch); + settings.setValue("encoder_variant", model->m_encoderVariant); settings.setValue("rate_control_mode", model->m_rcMode); settings.setValue("target_bitrate", model->m_bitrate); settings.setValue("target_quantizer", model->m_quantizer); settings.setValue("preset_name", model->m_preset); settings.setValue("tuning_name", model->m_tune); settings.setValue("profile_name", model->m_profile); - settings.setValue("custom_params_x264", model->m_custom_x264); + settings.setValue("custom_params_encoder", model->m_custom_encoder); settings.setValue("custom_params_avs2yuv", model->m_custom_avs2yuv); settings.endGroup(); @@ -129,24 +158,30 @@ bool OptionsModel::loadTemplate(OptionsModel *model, const QString &name) } bool complete = true; + if(!settings.contains("encoder_type")) complete = false; + if(!settings.contains("encoder_arch")) complete = false; + if(!settings.contains("encoder_variant")) complete = false; if(!settings.contains("rate_control_mode")) complete = false; if(!settings.contains("target_bitrate")) complete = false; if(!settings.contains("target_quantizer")) complete = false; if(!settings.contains("preset_name")) complete = false; if(!settings.contains("tuning_name")) complete = false; if(!settings.contains("profile_name")) complete = false; - if(!settings.contains("custom_params_x264")) complete = false; + if(!settings.contains("custom_params_encoder")) complete = false; if(!settings.contains("custom_params_avs2yuv")) complete = false; if(complete) { + model->setEncType(static_cast(settings.value("encoder_type", model->m_encoderType).toInt())); + model->setEncArch(static_cast(settings.value("encoder_arch", model->m_encoderArch).toInt())); + model->setEncVariant(static_cast(settings.value("encoder_variant", model->m_encoderVariant).toInt())); model->setRCMode(static_cast(settings.value("rate_control_mode", model->m_rcMode).toInt())); model->setBitrate(settings.value("target_bitrate", model->m_bitrate).toUInt()); model->setQuantizer(settings.value("target_quantizer", model->m_quantizer).toDouble()); model->setPreset(settings.value("preset_name", model->m_preset).toString()); model->setTune(settings.value("tuning_name", model->m_tune).toString()); model->setProfile(settings.value("profile_name", model->m_profile).toString()); - model->setCustomX264(settings.value("custom_params_x264", model->m_custom_x264).toString()); + model->setCustomEncParams(settings.value("custom_params_x264", model->m_custom_encoder).toString()); model->setCustomAvs2YUV(settings.value("custom_params_avs2yuv", model->m_custom_avs2yuv).toString()); } diff --git a/src/model_options.h b/src/model_options.h index 548a6ec..06f9204 100644 --- a/src/model_options.h +++ b/src/model_options.h @@ -29,8 +29,27 @@ class OptionsModel { public: OptionsModel(void); + OptionsModel(const OptionsModel &rhs); ~OptionsModel(void); + enum EncType + { + EncType_X264 = 0, + EncType_X265 = 1, + }; + + enum EncArch + { + EncArch_x32 = 0, + EncArch_x64 = 1, + }; + + enum EncVariant + { + EncVariant_LoBit = 0, // 8-Bit + EncVariant_HiBit = 1, //10-Bit (x264) or 16-Bit (x265) + }; + enum RCMode { RCMode_CRF = 0, @@ -40,23 +59,29 @@ public: }; //Getter + EncType encType(void) const { return m_encoderType; } + EncArch encArch(void) const { return m_encoderArch; } + EncVariant encVariant(void) const { return m_encoderVariant; } RCMode rcMode(void) const { return m_rcMode; } unsigned int bitrate(void) const { return m_bitrate; } double quantizer(void) const { return m_quantizer; } QString preset(void) const { return m_preset; } QString tune(void) const { return m_tune; } QString profile(void) const { return m_profile; } - QString customX264(void) const { return m_custom_x264; } + QString customEncParams(void) const { return m_custom_encoder; } QString customAvs2YUV(void) const { return m_custom_avs2yuv; } //Setter + void setEncType(EncType type) { m_encoderType = qBound(EncType_X264, type, EncType_X265); } + void setEncArch(EncArch arch) { m_encoderArch = qBound(EncArch_x32, arch, EncArch_x64); } + void setEncVariant(EncVariant variant) { m_encoderVariant = qBound(EncVariant_LoBit, variant, EncVariant_HiBit); } void setRCMode(RCMode mode) { m_rcMode = qBound(RCMode_CRF, mode, RCMode_ABR); } void setBitrate(unsigned int bitrate) { m_bitrate = qBound(10U, bitrate, 800000U); } void setQuantizer(double quantizer) { m_quantizer = qBound(0.0, quantizer, 52.0); } void setPreset(const QString &preset) { m_preset = preset.trimmed(); } void setTune(const QString &tune) { m_tune = tune.trimmed(); } void setProfile(const QString &profile) { m_profile = profile.trimmed(); } - void setCustomX264(const QString &custom) { m_custom_x264 = custom.trimmed(); } + void setCustomEncParams(const QString &custom) { m_custom_encoder = custom.trimmed(); } void setCustomAvs2YUV(const QString &custom) { m_custom_avs2yuv = custom.trimmed(); } //Stuff @@ -71,12 +96,15 @@ public: static bool deleteTemplate(const QString &name); protected: + EncType m_encoderType; + EncArch m_encoderArch; + EncVariant m_encoderVariant; RCMode m_rcMode; unsigned int m_bitrate; double m_quantizer; QString m_preset; QString m_tune; QString m_profile; - QString m_custom_x264; + QString m_custom_encoder; QString m_custom_avs2yuv; }; diff --git a/src/thread_encode.cpp b/src/thread_encode.cpp index 293fe68..5e6cfed 100644 --- a/src/thread_encode.cpp +++ b/src/thread_encode.cpp @@ -249,7 +249,7 @@ void EncodeThread::encode(void) log(tr("Preset: %1").arg(m_options->preset())); log(tr("Tuning: %1").arg(m_options->tune())); log(tr("Profile: %1").arg(m_options->profile())); - log(tr("Custom: %1").arg(m_options->customX264().isEmpty() ? tr("(None)") : m_options->customX264())); + log(tr("Custom: %1").arg(m_options->customEncParams().isEmpty() ? tr("(None)") : m_options->customEncParams())); log(m_binDir); @@ -690,9 +690,9 @@ QStringList EncodeThread::buildCommandLine(bool usePipe, bool use10Bit, unsigned } } - if(!m_options->customX264().isEmpty()) + if(!m_options->customEncParams().isEmpty()) { - QStringList customArgs = splitParams(m_options->customX264()); + QStringList customArgs = splitParams(m_options->customEncParams()); if(usePipe) { QStringList::iterator i = customArgs.begin(); diff --git a/src/version.h b/src/version.h index 7a47728..68b5dc7 100644 --- a/src/version.h +++ b/src/version.h @@ -26,7 +26,7 @@ #define VER_X264_MAJOR 2 #define VER_X264_MINOR 3 #define VER_X264_PATCH 1 -#define VER_X264_BUILD 754 +#define VER_X264_BUILD 758 #define VER_X264_MINIMUM_REV 2380 #define VER_X264_CURRENT_API 142 diff --git a/src/win_addJob.cpp b/src/win_addJob.cpp index 4a66de7..e0b5777 100644 --- a/src/win_addJob.cpp +++ b/src/win_addJob.cpp @@ -76,6 +76,18 @@ WIDGET->addAction(_action); \ } +static void ENABLE_SIGNALS(Ui::AddJobDialog *ui, const bool &flag) +{ + ui->cbxRateControlMode->blockSignals(flag); + ui->spinQuantizer->blockSignals(flag); + ui->spinBitrate->blockSignals(flag); + ui->cbxPreset->blockSignals(flag); + ui->cbxTuning->blockSignals(flag); + ui->cbxProfile->blockSignals(flag); + ui->editCustomX264Params->blockSignals(flag); + ui->editCustomAvs2YUVParams->blockSignals(flag); +} + /////////////////////////////////////////////////////////////////////////////// // Validator /////////////////////////////////////////////////////////////////////////////// @@ -227,8 +239,9 @@ AddJobDialog::AddJobDialog(QWidget *parent, OptionsModel *options, RecentlyUsed //Hide optional controls ui->checkBoxApplyToAll->setVisible(false); - //Monitor RC mode combobox + //Monitor combobox changes connect(ui->cbxRateControlMode, SIGNAL(currentIndexChanged(int)), this, SLOT(modeIndexChanged(int))); + connect(ui->cbxEncoderType, SIGNAL(currentIndexChanged(int)), this, SLOT(encoderIndexChanged(int))); //Activate buttons connect(ui->buttonBrowseSource, SIGNAL(clicked()), this, SLOT(browseButtonClicked())); @@ -407,6 +420,15 @@ void AddJobDialog::dropEvent(QDropEvent *event) // Slots /////////////////////////////////////////////////////////////////////////////// +void AddJobDialog::encoderIndexChanged(int index) +{ + const bool isX265 = (index >= 1); + ui->cbxEncoderVariant->setItemText(1, isX265 ? tr("16-Bit") : tr("10-Bit")); + ui->cbxProfile->setEnabled(!isX265); + ui->labelProfile->setEnabled(!isX265); + if(isX265) ui->cbxProfile->setCurrentIndex(0); +} + void AddJobDialog::modeIndexChanged(int index) { ui->spinQuantizer->setEnabled(index == 0 || index == 1); @@ -534,6 +556,7 @@ void AddJobDialog::templateSelected(void) restoreOptions(options); } + //Force updates modeIndexChanged(ui->cbxRateControlMode->currentIndex()); } @@ -725,26 +748,6 @@ QString AddJobDialog::outputFile(void) return QDir::fromNativeSeparators(ui->editOutput->text()); } -QString AddJobDialog::preset(void) -{ - return ui->cbxPreset->itemText(ui->cbxPreset->currentIndex()); -} - -QString AddJobDialog::tuning(void) -{ - return ui->cbxTuning->itemText(ui->cbxTuning->currentIndex()); -} - -QString AddJobDialog::profile(void) -{ - return ui->cbxProfile->itemText(ui->cbxProfile->currentIndex()); -} - -QString AddJobDialog::params(void) -{ - return ui->editCustomX264Params->text().simplified(); -} - bool AddJobDialog::runImmediately(void) { return ui->checkBoxRun->isChecked(); @@ -812,26 +815,24 @@ void AddJobDialog::loadTemplateList(void) void AddJobDialog::updateComboBox(QComboBox *cbox, const QString &text) { - for(int i = 0; i < cbox->model()->rowCount(); i++) + int index = -1; + if(QAbstractItemModel *model = cbox->model()) { - if(cbox->model()->data(cbox->model()->index(i, 0, QModelIndex())).toString().compare(text, Qt::CaseInsensitive) == 0) + for(int i = 0; i < cbox->model()->rowCount(); i++) { - cbox->setCurrentIndex(i); - break; + if(model->data(model->index(i, 0, QModelIndex())).toString().compare(text, Qt::CaseInsensitive) == 0) + { + index = i; + break; + } } } + cbox->setCurrentIndex(index); } void AddJobDialog::restoreOptions(OptionsModel *options) { - ui->cbxRateControlMode->blockSignals(true); - ui->spinQuantizer->blockSignals(true); - ui->spinBitrate->blockSignals(true); - ui->cbxPreset->blockSignals(true); - ui->cbxTuning->blockSignals(true); - ui->cbxProfile->blockSignals(true); - ui->editCustomX264Params->blockSignals(true); - ui->editCustomAvs2YUVParams->blockSignals(true); + ENABLE_SIGNALS(ui, false); ui->cbxRateControlMode->setCurrentIndex(options->rcMode()); ui->spinQuantizer->setValue(options->quantizer()); @@ -839,28 +840,24 @@ void AddJobDialog::restoreOptions(OptionsModel *options) updateComboBox(ui->cbxPreset, options->preset()); updateComboBox(ui->cbxTuning, options->tune()); updateComboBox(ui->cbxProfile, options->profile()); - ui->editCustomX264Params->setText(options->customX264()); + ui->editCustomX264Params->setText(options->customEncParams()); ui->editCustomAvs2YUVParams->setText(options->customAvs2YUV()); - ui->cbxRateControlMode->blockSignals(false); - ui->spinQuantizer->blockSignals(false); - ui->spinBitrate->blockSignals(false); - ui->cbxPreset->blockSignals(false); - ui->cbxTuning->blockSignals(false); - ui->cbxProfile->blockSignals(false); - ui->editCustomX264Params->blockSignals(false); - ui->editCustomAvs2YUVParams->blockSignals(false); + ENABLE_SIGNALS(ui, true); } void AddJobDialog::saveOptions(OptionsModel *options) { + options->setEncType(static_cast(ui->cbxEncoderArch->currentIndex())); + options->setEncArch(static_cast(ui->cbxEncoderType->currentIndex())); + options->setEncVariant(static_cast(ui->cbxEncoderVariant->currentIndex())); options->setRCMode(static_cast(ui->cbxRateControlMode->currentIndex())); options->setQuantizer(ui->spinQuantizer->value()); options->setBitrate(ui->spinBitrate->value()); options->setPreset(ui->cbxPreset->model()->data(ui->cbxPreset->model()->index(ui->cbxPreset->currentIndex(), 0)).toString()); options->setTune(ui->cbxTuning->model()->data(ui->cbxTuning->model()->index(ui->cbxTuning->currentIndex(), 0)).toString()); options->setProfile(ui->cbxProfile->model()->data(ui->cbxProfile->model()->index(ui->cbxProfile->currentIndex(), 0)).toString()); - options->setCustomX264(ui->editCustomX264Params->hasAcceptableInput() ? ui->editCustomX264Params->text().simplified() : QString()); + options->setCustomEncParams(ui->editCustomX264Params->hasAcceptableInput() ? ui->editCustomX264Params->text().simplified() : QString()); options->setCustomAvs2YUV(ui->editCustomAvs2YUVParams->hasAcceptableInput() ? ui->editCustomAvs2YUVParams->text().simplified() : QString()); } diff --git a/src/win_addJob.h b/src/win_addJob.h index 40a3f7c..416d85c 100644 --- a/src/win_addJob.h +++ b/src/win_addJob.h @@ -42,10 +42,7 @@ public: QString sourceFile(void); QString outputFile(void); - QString preset(void); - QString tuning(void); - QString profile(void); - QString params(void); + bool runImmediately(void); bool applyToAll(void); void setRunImmediately(bool run); @@ -76,6 +73,7 @@ protected: virtual void dropEvent(QDropEvent *event); private slots: + void encoderIndexChanged(int index); void modeIndexChanged(int index); void browseButtonClicked(void); void configurationChanged(void);