File indexing completed on 2024-04-21 04:51:22

0001 /*
0002     SPDX-FileCopyrightText: 2022 Julius Künzel <jk.kdedev@smartlab.uber.space>
0003 
0004     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "renderpresetdialog.h"
0008 
0009 #include "core.h"
0010 #include "kdenlivesettings.h"
0011 #include "monitor/monitormanager.h"
0012 #include "profiles/profilemodel.hpp"
0013 #include "renderpresets/renderpresetmodel.hpp"
0014 #include "renderpresets/renderpresetrepository.hpp"
0015 
0016 #include <KMessageBox>
0017 #include <QPushButton>
0018 #include <QScrollBar>
0019 
0020 // TODO replace this by std::gcd ones why require C++17 or greater
0021 static int gcd(int a, int b)
0022 {
0023     for (;;) {
0024         if (a == 0) return b;
0025         b %= a;
0026         if (b == 0) return a;
0027         a %= b;
0028     }
0029 }
0030 
0031 RenderPresetDialog::RenderPresetDialog(QWidget *parent, RenderPresetModel *preset, Mode mode)
0032     : QDialog(parent)
0033     , m_saveName(preset ? preset->name() : "")
0034     , m_monitor(nullptr)
0035     , m_fixedResRatio(1.)
0036     , m_manualPreset(false)
0037 {
0038     setupUi(this);
0039     if (preset) {
0040         m_manualPreset = preset->isManual();
0041     }
0042     m_uiParams.append({QStringLiteral("f"),
0043                        QStringLiteral("acodec"),
0044                        QStringLiteral("vcodec"),
0045                        QStringLiteral("width"),
0046                        QStringLiteral("height"),
0047                        QStringLiteral("s"),
0048                        QStringLiteral("r"),
0049                        QStringLiteral("frame_rate_num"),
0050                        QStringLiteral("frame_rate_den"),
0051                        QStringLiteral("crf"),
0052                        QStringLiteral("color_range"),
0053                        QStringLiteral("vb"),
0054                        QStringLiteral("vminrate"),
0055                        QStringLiteral("vmaxrate"),
0056                        QStringLiteral("vglobal_quality"),
0057                        QStringLiteral("vq"),
0058                        QStringLiteral("rc"),
0059                        QStringLiteral("g"),
0060                        QStringLiteral("bf"),
0061                        QStringLiteral("progressive"),
0062                        QStringLiteral("top_field_first"),
0063                        QStringLiteral("qscale"),
0064                        QStringLiteral("vbufsize"),
0065                        QStringLiteral("qmin"),
0066                        QStringLiteral("qp_i"),
0067                        QStringLiteral("qp_p"),
0068                        QStringLiteral("qp_b"),
0069                        QStringLiteral("ab"),
0070                        QStringLiteral("aq"),
0071                        QStringLiteral("compression_level"),
0072                        QStringLiteral("vbr"),
0073                        QStringLiteral("ar"),
0074                        QStringLiteral("display_aspect_num"),
0075                        QStringLiteral("display_aspect_den"),
0076                        QStringLiteral("sample_aspect_num"),
0077                        QStringLiteral("sample_aspect_den"),
0078                        QStringLiteral("aspect"),
0079                        QStringLiteral("sc_threshold"),
0080                        QStringLiteral("strict_gop"),
0081                        QStringLiteral("keyint_min"),
0082                        QStringLiteral("channels")});
0083 
0084     formatCombo->addItems(RenderPresetRepository::supportedFormats());
0085     vCodecCombo->addItems(RenderPresetRepository::vcodecs());
0086     aCodecCombo->addItems(RenderPresetRepository::acodecs());
0087 
0088     aRateControlCombo->addItem(i18n("(Not set)"));
0089     aRateControlCombo->addItem(i18n("Average Bitrate"));
0090     aRateControlCombo->addItem(i18n("CBR – Constant Bitrate"));
0091     aRateControlCombo->addItem(i18n("VBR – Variable Bitrate"));
0092 
0093     audioChannels->addItem(i18n("1 (mono)"), 1);
0094     audioChannels->addItem(i18n("2 (stereo)"), 2);
0095     audioChannels->addItem(i18n("4"), 4);
0096     audioChannels->addItem(i18n("6"), 6);
0097 
0098     QValidator *validator = new QIntValidator(this);
0099     audioSampleRate->setValidator(validator);
0100 
0101     // Add some common pixel aspect ratios:
0102     // The following code works, because setting a yet
0103     // unknown ratio will add it to the combo box.
0104     setPixelAspectRatio(1, 1);
0105     setPixelAspectRatio(10, 11);
0106     setPixelAspectRatio(12, 11);
0107     setPixelAspectRatio(59, 54);
0108     setPixelAspectRatio(4, 3);
0109     setPixelAspectRatio(64, 45);
0110     setPixelAspectRatio(11, 9);
0111     setPixelAspectRatio(118, 81);
0112 
0113     //
0114     QPushButton *helpButton = buttonBox->button(QDialogButtonBox::Help);
0115     helpButton->setText(QString());
0116     helpButton->setIcon(QIcon::fromTheme(QStringLiteral("settings-configure")));
0117     helpButton->setToolTip(i18n("Edit Render Preset"));
0118     helpButton->setCheckable(true);
0119     helpButton->setChecked(KdenliveSettings::showRenderTextParameters());
0120     parameters->setVisible(KdenliveSettings::showRenderTextParameters());
0121     connect(helpButton, &QPushButton::toggled, [this](bool checked) {
0122         parameters->setVisible(checked);
0123         KdenliveSettings::setShowRenderTextParameters(checked);
0124     });
0125 
0126     connect(vRateControlCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [this](int index) {
0127         switch (index) {
0128         case RenderPresetParams::RateControl::Average:
0129             default_vbitrate->setEnabled(true);
0130             default_vquality->setEnabled(false);
0131             vquality_label->setEnabled(false);
0132             vBuffer->setEnabled(false);
0133             break;
0134         case RenderPresetParams::RateControl::Constant:
0135             default_vbitrate->setEnabled(true);
0136             default_vquality->setEnabled(false);
0137             vquality_label->setEnabled(false);
0138             vBuffer->setEnabled(true);
0139             break;
0140         case RenderPresetParams::RateControl::Constrained:
0141             default_vbitrate->setEnabled(true);
0142             default_vquality->setEnabled(true);
0143             vquality_label->setEnabled(true);
0144             vBuffer->setEnabled(true);
0145             break;
0146         case RenderPresetParams::RateControl::Quality:
0147             default_vbitrate->setEnabled(false);
0148             default_vquality->setEnabled(true);
0149             vquality_label->setEnabled(true);
0150             vBuffer->setEnabled(false);
0151             break;
0152         default:
0153             default_vbitrate->setEnabled(false);
0154             default_vquality->setEnabled(false);
0155             vquality_label->setEnabled(false);
0156             vBuffer->setEnabled(false);
0157             break;
0158         };
0159         slotUpdateParams();
0160     });
0161 
0162     vRateControlCombo->addItem(i18n("(Not set)"));
0163     vRateControlCombo->addItem(i18n("Average Bitrate"));
0164     vRateControlCombo->addItem(i18n("CBR – Constant Bitrate"));
0165     vRateControlCombo->addItem(i18n("VBR – Variable Bitrate"));
0166     vRateControlCombo->addItem(i18n("Constrained VBR"));
0167 
0168     connect(scanningCombo, &QComboBox::currentTextChanged, this, [&]() {
0169         fieldOrderCombo->setEnabled(scanningCombo->currentIndex() != 1);
0170         cField->setEnabled(scanningCombo->currentIndex() != 1);
0171         slotUpdateParams();
0172     });
0173     connect(gopSpinner, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
0174         fixedGop->setEnabled(value > 1);
0175         bFramesSpinner->setEnabled(value > 1);
0176         bFramesLabel->setEnabled(value > 1);
0177         if (value <= 1) {
0178             fixedGop->blockSignals(true);
0179             fixedGop->setChecked(false);
0180             fixedGop->blockSignals(false);
0181             bFramesSpinner->blockSignals(true);
0182             bFramesSpinner->setValue(-1);
0183             bFramesSpinner->blockSignals(false);
0184         } else {
0185             bFramesSpinner->setMaximum(value - 1);
0186         }
0187         slotUpdateParams();
0188     });
0189 
0190     groupName->addItems(RenderPresetRepository::get()->groupNames());
0191 
0192     std::unique_ptr<ProfileModel> &projectProfile = pCore->getCurrentProfile();
0193     int parNum = projectProfile->sample_aspect_num();
0194     int parDen = projectProfile->sample_aspect_den();
0195     connect(button_manual, &QPushButton::clicked, [this, helpButton]() {
0196         if (m_manualPreset) {
0197             return;
0198         }
0199         tabWidget->setVisible(false);
0200         label_container->setEnabled(false);
0201         formatCombo->setEnabled(false);
0202         parameters->setVisible(true);
0203         parameters->setReadOnly(false);
0204         helpButton->setEnabled(false);
0205         m_manualPreset = true;
0206     });
0207     if (preset) {
0208         groupName->setCurrentText(preset->groupName());
0209         if (mode != Mode::New) {
0210             preset_name->setText(preset->name());
0211         }
0212         preset_name->setFocus();
0213         if (m_manualPreset) {
0214             tabWidget->setVisible(false);
0215             label_container->setEnabled(false);
0216             formatCombo->setEnabled(false);
0217             parameters->setVisible(true);
0218             parameters->setPlainText(preset->params().toString());
0219             parameters->setReadOnly(false);
0220             helpButton->setEnabled(false);
0221             preset_extension->setText(preset->extension());
0222         } else {
0223             formatCombo->setCurrentText(preset->getParam(QStringLiteral("f")));
0224             preset_extension->setText(preset->extension());
0225             QString width = preset->getParam(QStringLiteral("width"));
0226             QString height = preset->getParam(QStringLiteral("height"));
0227             QString size = preset->getParam(QStringLiteral("s"));
0228 
0229             if (!(width.isEmpty() && height.isEmpty())) {
0230                 resWidth->setValue(width.toInt());
0231                 resHeight->setValue(height.toInt());
0232                 cResolution->setChecked(true);
0233             } else if (!size.isEmpty()) {
0234                 QStringList list = size.split(QStringLiteral("x"));
0235                 if (list.count() == 2) {
0236                     resWidth->setValue(list.at(0).toInt());
0237                     resHeight->setValue(list.at(1).toInt());
0238                     cResolution->setChecked(true);
0239                 }
0240             } else {
0241                 resWidth->setValue(projectProfile->width());
0242                 resHeight->setValue(projectProfile->height());
0243             }
0244 
0245             // video tab
0246             if (preset->hasParam(QStringLiteral("vbufsize"))) {
0247                 bool ok = false;
0248                 int vbufsize = preset->getParam(QStringLiteral("vbufsize")).toInt(&ok);
0249                 if (ok) {
0250                     vBuffer->setValue(vbufsize / 1024 / 8);
0251                 }
0252             }
0253             QString vqParam = preset->getParam(QStringLiteral("vq"));
0254             QString vbParam = preset->getParam(QStringLiteral("vb"));
0255             if (vqParam.isEmpty()) {
0256                 vqParam = preset->getParam(QStringLiteral("vqp"));
0257             }
0258             if (vqParam.isEmpty()) {
0259                 vqParam = preset->getParam(QStringLiteral("vglobal_quality"));
0260             }
0261             if (vqParam.isEmpty()) {
0262                 vqParam = preset->getParam(QStringLiteral("qscale"));
0263             }
0264             if (vqParam.isEmpty()) {
0265                 vqParam = preset->getParam(QStringLiteral("crf"));
0266             }
0267             if (vqParam == QStringLiteral("%quality")) {
0268                 default_vquality->setValue(preset->defaultVQuality().toInt());
0269             } else {
0270                 default_vquality->setValue(vqParam.toInt());
0271             }
0272 
0273             vRateControlCombo->setCurrentIndex(preset->params().videoRateControl());
0274 
0275             if (vbParam.isEmpty()) {
0276                 vbParam = preset->getParam(QStringLiteral("vmaxrate"));
0277             }
0278             if (vbParam.contains(QStringLiteral("%bitrate"))) {
0279                 default_vbitrate->setValue(preset->defaultVBitrate().toInt());
0280             } else if (!vbParam.isEmpty()) {
0281                 default_vbitrate->setValue(vbParam.replace('k', "").replace('M', "000").toInt());
0282             }
0283 
0284             QString sampAspNum = preset->getParam(QStringLiteral("sample_aspect_num"));
0285             QString sampAspDen = preset->getParam(QStringLiteral("sample_aspect_den"));
0286             QString sampAsp = preset->getParam(QStringLiteral("aspect"));
0287 
0288             if (!(sampAspNum.isEmpty() && sampAspDen.isEmpty())) {
0289                 parNum = sampAspNum.toInt();
0290                 parDen = sampAspDen.toInt();
0291                 cPar->setChecked(true);
0292             } else if (!sampAsp.isEmpty()) {
0293                 QStringList list = sampAsp.split(QStringLiteral("/"));
0294                 if (list.count() == 2) {
0295                     parNum = list.at(0).toInt();
0296                     parDen = list.at(1).toInt();
0297                     cPar->setChecked(true);
0298                 }
0299             }
0300 
0301             if (preset->hasParam(QStringLiteral("display_aspect_num")) && preset->hasParam(QStringLiteral("display_aspect_den"))) {
0302                 displayAspectNum->setValue(preset->getParam(QStringLiteral("display_aspect_num")).toInt());
0303                 displayAspectDen->setValue(preset->getParam(QStringLiteral("display_aspect_den")).toInt());
0304                 cDar->setChecked(true);
0305             } else {
0306                 displayAspectNum->setValue(projectProfile->display_aspect_num());
0307                 displayAspectDen->setValue(projectProfile->display_aspect_den());
0308             }
0309 
0310             vCodecCombo->setCurrentText(preset->getParam(QStringLiteral("vcodec")));
0311             if (preset->hasParam(QStringLiteral("r"))) {
0312                 cFps->setChecked(true);
0313                 double val = preset->getParam(QStringLiteral("r")).toDouble();
0314                 if (val == 23.98 || val == 23.976 || val == (24000 / 1001)) {
0315                     framerateNum->setValue(24000);
0316                     framerateDen->setValue(1001);
0317                 } else if (val == 29.97 || val == (30000 / 1001)) {
0318                     framerateNum->setValue(30000);
0319                     framerateDen->setValue(1001);
0320                 } else if (val == 47.95 || val == (48000 / 1001)) {
0321                     framerateNum->setValue(48000);
0322                     framerateDen->setValue(1001);
0323                 } else if (val == 59.94 || val == (60000 / 1001)) {
0324                     framerateNum->setValue(60000);
0325                     framerateDen->setValue(1001);
0326                 } else {
0327                     framerateNum->setValue(qRound(val * 1000));
0328                     framerateDen->setValue(1000);
0329                 }
0330             } else if (preset->hasParam(QStringLiteral("frame_rate_num")) && preset->hasParam(QStringLiteral("frame_rate_den"))) {
0331                 framerateNum->setValue(preset->getParam(QStringLiteral("frame_rate_num")).toInt());
0332                 framerateDen->setValue(preset->getParam(QStringLiteral("frame_rate_den")).toInt());
0333                 cFps->setChecked(true);
0334             } else {
0335                 framerateNum->setValue(projectProfile->frame_rate_num());
0336                 framerateDen->setValue(projectProfile->frame_rate_den());
0337             }
0338             if (preset->hasParam(QStringLiteral("progressive"))) {
0339                 scanningCombo->setCurrentIndex(preset->getParam(QStringLiteral("progressive")).toInt());
0340                 cScanning->setChecked(true);
0341             }
0342             if (preset->hasParam(QStringLiteral("top_field_first"))) {
0343                 fieldOrderCombo->setCurrentIndex(preset->getParam(QStringLiteral("top_field_first")).toInt());
0344                 cField->setChecked(true);
0345             }
0346             int gopVal = -1;
0347             if (preset->hasParam(QStringLiteral("g"))) {
0348                 gopVal = preset->getParam(QStringLiteral("g")).toInt();
0349                 gopSpinner->setValue(gopVal);
0350             }
0351             if (preset->hasParam(QStringLiteral("sc_threshold")))
0352                 fixedGop->setChecked(preset->getParam(QStringLiteral("sc_threshold")).toInt() == 0);
0353             else if (preset->hasParam(QStringLiteral("keyint_min")))
0354                 fixedGop->setChecked(preset->getParam(QStringLiteral("keyint_min")).toInt() == gopVal);
0355             else if (preset->hasParam(QStringLiteral("strict_gop"))) {
0356                 fixedGop->setChecked(preset->getParam(QStringLiteral("strict_gop")).toInt() == 1);
0357             } else {
0358                 fixedGop->setChecked(false);
0359             }
0360             bFramesSpinner->setValue(preset->getParam(QStringLiteral("bf")).toInt());
0361 
0362             // audio tab
0363             if (preset->hasParam(QStringLiteral("channels"))) {
0364                 int ix = audioChannels->findData(preset->getParam(QStringLiteral("channels")).toInt());
0365                 audioChannels->setCurrentIndex(ix);
0366                 cChannels->setChecked(true);
0367             } else {
0368                 int ix = audioChannels->findData(2);
0369                 audioChannels->setCurrentIndex(ix);
0370             }
0371             aRateControlCombo->setCurrentIndex(preset->audioRateControl());
0372 
0373             if (preset->hasParam(QStringLiteral("channels"))) {
0374                 audioSampleRate->setCurrentText(preset->getParam(QStringLiteral("ar")));
0375                 cSampleR->setChecked(true);
0376             } else {
0377                 audioSampleRate->setCurrentText(QStringLiteral("44100"));
0378             }
0379 
0380             QString aqParam = preset->getParam(QStringLiteral("aq"));
0381             if (aqParam.isEmpty()) {
0382                 aqParam = preset->getParam(QStringLiteral("compression_level"));
0383             }
0384             if (aqParam.contains(QStringLiteral("%audioquality"))) {
0385                 aQuality->setValue(preset->defaultAQuality().toInt());
0386             } else {
0387                 aQuality->setValue(aqParam.toInt());
0388             }
0389             QString abParam = preset->getParam(QStringLiteral("ab"));
0390             if (abParam.contains(QStringLiteral("%audiobitrate"))) {
0391                 aBitrate->setValue(preset->defaultABitrate().toInt());
0392             } else {
0393                 aBitrate->setValue(abParam.replace('k', "").replace('M', "000").toInt());
0394             }
0395 
0396             aCodecCombo->setCurrentText(preset->getParam(QStringLiteral("acodec")));
0397 
0398             // general tab
0399             speeds_list->setText(preset->speeds().join('\n'));
0400             additionalParams->setPlainText(preset->params(m_uiParams).toString());
0401         }
0402     } else {
0403         resHeight->setValue(projectProfile->height());
0404         resWidth->setValue(projectProfile->width());
0405         framerateNum->setValue(projectProfile->frame_rate_num());
0406         framerateDen->setValue(projectProfile->frame_rate_den());
0407         parNum = projectProfile->sample_aspect_num();
0408         parDen = projectProfile->sample_aspect_den();
0409         displayAspectNum->setValue(projectProfile->display_aspect_num());
0410         displayAspectDen->setValue(projectProfile->display_aspect_den());
0411         scanningCombo->setCurrentIndex(projectProfile->progressive() ? 1 : 0);
0412     }
0413 
0414     setPixelAspectRatio(parNum, parDen);
0415 
0416     if (groupName->currentText().isEmpty()) {
0417         groupName->setCurrentText(i18nc("Group Name", "Custom"));
0418     }
0419 
0420     if (mode == Mode::Edit) {
0421         setWindowTitle(i18n("Edit Render Preset"));
0422     }
0423 
0424     connect(preset_name, &QLineEdit::textChanged, this, [&](const QString &text) { buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty()); });
0425 
0426     connect(buttonBox, &QDialogButtonBox::accepted, this, [&, preset, mode]() {
0427         QString oldName;
0428         if (preset) {
0429             oldName = preset->name();
0430         }
0431         QString newPresetName = preset_name->text().simplified();
0432         if (newPresetName.isEmpty()) {
0433             KMessageBox::error(this, i18n("The preset name can't be empty"));
0434             return;
0435         }
0436         QString newGroupName = groupName->currentText().simplified();
0437         if (newGroupName.isEmpty()) {
0438             newGroupName = i18nc("Group Name", "Custom");
0439         }
0440         QString speeds_list_str = speeds_list->toPlainText().replace('\n', ';').simplified();
0441 
0442         std::unique_ptr<RenderPresetModel> newPreset(new RenderPresetModel(newPresetName, newGroupName, parameters->toPlainText().simplified(),
0443                                                                            preset_extension->text().simplified(), QString::number(default_vbitrate->value()),
0444                                                                            QString::number(default_vquality->value()), QString::number(aBitrate->value()),
0445                                                                            QString::number(aQuality->value()), speeds_list_str, m_manualPreset));
0446 
0447         m_saveName = RenderPresetRepository::get()->savePreset(newPreset.get(), mode == Mode::Edit);
0448         if ((mode == Mode::Edit) && !m_saveName.isEmpty() && (oldName != m_saveName)) {
0449             RenderPresetRepository::get()->deletePreset(oldName);
0450         }
0451         accept();
0452     });
0453 
0454     connect(formatCombo, &QComboBox::currentTextChanged, [this](const QString &format) {
0455         if (format == QLatin1String("matroska")) {
0456             preset_extension->setText(QStringLiteral("mkv"));
0457         } else {
0458             preset_extension->setText(format);
0459         }
0460         slotUpdateParams();
0461     });
0462     connect(vCodecCombo, &QComboBox::currentTextChanged, this, &RenderPresetDialog::slotUpdateParams);
0463 
0464     connect(fieldOrderCombo, &QComboBox::currentTextChanged, this, &RenderPresetDialog::slotUpdateParams);
0465     connect(aCodecCombo, &QComboBox::currentTextChanged, this, &RenderPresetDialog::slotUpdateParams);
0466     connect(linkResoultion, &QToolButton::clicked, this, [&]() { m_fixedResRatio = double(resWidth->value()) / double(resHeight->value()); });
0467     connect(resWidth, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
0468         if (linkResoultion->isChecked()) {
0469             resHeight->blockSignals(true);
0470             resHeight->setValue(qRound(value / m_fixedResRatio));
0471             resHeight->blockSignals(false);
0472         }
0473         updateDisplayAspectRatio();
0474     });
0475     connect(resHeight, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
0476         if (linkResoultion->isChecked()) {
0477             resWidth->blockSignals(true);
0478             resWidth->setValue(qRound(value * m_fixedResRatio));
0479             resWidth->blockSignals(false);
0480         }
0481         updateDisplayAspectRatio();
0482     });
0483     connect(parCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RenderPresetDialog::updateDisplayAspectRatio);
0484     auto update_par = [&]() {
0485         int parNum = displayAspectNum->value() * resHeight->value();
0486         int parDen = displayAspectDen->value() * resWidth->value();
0487         setPixelAspectRatio(parNum, parDen);
0488         slotUpdateParams();
0489     };
0490     connect(displayAspectNum, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, update_par);
0491     connect(displayAspectDen, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, update_par);
0492     connect(framerateNum, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
0493         if (value == 0) {
0494             framerateDen->blockSignals(true);
0495             framerateDen->setValue(0);
0496             framerateDen->blockSignals(false);
0497         }
0498         slotUpdateParams();
0499     });
0500     connect(framerateDen, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
0501         if (value == 0) {
0502             framerateNum->blockSignals(true);
0503             framerateNum->setValue(0);
0504             framerateNum->blockSignals(false);
0505         }
0506         slotUpdateParams();
0507     });
0508     connect(fixedGop, &QCheckBox::stateChanged, this, &RenderPresetDialog::slotUpdateParams);
0509     connect(bFramesSpinner, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RenderPresetDialog::slotUpdateParams);
0510     connect(additionalParams, &QPlainTextEdit::textChanged, this, &RenderPresetDialog::slotUpdateParams);
0511 
0512     connect(aRateControlCombo, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RenderPresetDialog::slotUpdateParams);
0513     connect(aBitrate, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RenderPresetDialog::slotUpdateParams);
0514     connect(aQuality, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RenderPresetDialog::slotUpdateParams);
0515     connect(audioChannels, &QComboBox::currentTextChanged, this, &RenderPresetDialog::slotUpdateParams);
0516     connect(audioSampleRate, &QComboBox::currentTextChanged, this, &RenderPresetDialog::slotUpdateParams);
0517 
0518     linkResoultion->setChecked(true);
0519     slotUpdateParams();
0520     connect(cResolution, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0521     connect(cPar, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0522     connect(cDar, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0523     connect(cFps, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0524     connect(cScanning, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0525     connect(cField, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0526     connect(cChannels, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0527     connect(cSampleR, &QCheckBox::toggled, this, &RenderPresetDialog::slotUpdateParams);
0528 
0529     for (QSpinBox *sp : findChildren<QSpinBox *>()) {
0530         sp->installEventFilter(this);
0531         sp->setFocusPolicy(Qt::StrongFocus);
0532     }
0533     for (QComboBox *sp : findChildren<QComboBox *>()) {
0534         sp->installEventFilter(this);
0535         sp->setFocusPolicy(Qt::StrongFocus);
0536     }
0537 
0538     // TODO
0539     if (false && m_monitor == nullptr) {
0540         // QString profile = DvdWizardVob::getDvdProfile(format);
0541         /*m_monitor = new Monitor(Kdenlive::RenderMonitor, pCore->monitorManager(), this);
0542         m_monitor->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
0543         mainBox->addWidget(m_monitor);
0544         pCore->monitorManager()->appendMonitor(m_monitor);
0545         // m_monitor->setCustomProfile(profile, m_tc);
0546         pCore->monitorManager()->activateMonitor(Kdenlive::RenderMonitor);
0547         m_monitor->start();*/
0548     }
0549 }
0550 
0551 RenderPresetDialog::~RenderPresetDialog()
0552 {
0553     if (m_monitor) {
0554         m_monitor->stop();
0555         pCore->monitorManager()->removeMonitor(m_monitor);
0556         delete m_monitor;
0557     }
0558 }
0559 
0560 bool RenderPresetDialog::eventFilter(QObject *o, QEvent *e)
0561 {
0562     if (e->type() == QEvent::Wheel && (qobject_cast<QComboBox *>(o) || qobject_cast<QAbstractSpinBox *>(o))) {
0563         if (scrollArea->verticalScrollBar()->isVisible() && !qobject_cast<QWidget *>(o)->hasFocus()) {
0564             e->ignore();
0565             return true;
0566         } else {
0567             e->accept();
0568             return false;
0569         }
0570     }
0571     return QWidget::eventFilter(o, e);
0572 }
0573 
0574 void RenderPresetDialog::slotUpdateParams()
0575 {
0576     if (m_manualPreset) {
0577         return;
0578     }
0579     QStringList params;
0580     QString vcodec = vCodecCombo->currentText();
0581     params.append(QStringLiteral("f=%1").arg(formatCombo->currentText()));
0582     // video tab
0583     params.append(QStringLiteral("vcodec=%1").arg(vcodec));
0584     if (cResolution->isChecked()) {
0585         if (resWidth->value() > 0) {
0586             params.append(QStringLiteral("width=%1").arg(resWidth->value()));
0587         }
0588         if (resHeight->value() > 0) {
0589             params.append(QStringLiteral("height=%1").arg(resHeight->value()));
0590         }
0591     }
0592     if (cPar->isChecked()) {
0593         QStringList par = parCombo->currentData().toString().split(QStringLiteral(":"));
0594         if (par.length() >= 2 && par.at(0).toInt() > 0 && par.at(1).toInt() > 0) {
0595             params.append(QStringLiteral("sample_aspect_num=%1 sample_aspect_den=%2").arg(par.at(0).toInt()).arg(par.at(1).toInt()));
0596         }
0597     }
0598     if (cDar->isChecked() && displayAspectNum->value() > 0 && displayAspectDen->value() > 0) {
0599         params.append(QStringLiteral("display_aspect_num=%1 display_aspect_den=%2").arg(displayAspectNum->value()).arg(displayAspectDen->value()));
0600     }
0601 
0602     if (cFps->isChecked() && framerateNum->value() > 0 && framerateDen->value() > 0) {
0603         params.append(QStringLiteral("frame_rate_num=%1").arg(framerateNum->value()));
0604         params.append(QStringLiteral("frame_rate_den=%1").arg(framerateDen->value()));
0605         frameRateDisplay->setText(QString::number(double(framerateNum->value()) / double(framerateDen->value()), 'g', 10));
0606         frameRateDisplay->show();
0607     } else {
0608         frameRateDisplay->hide();
0609     }
0610 
0611     // Adjust scanning
0612     if (cScanning->isChecked()) {
0613         params.append(QStringLiteral("progressive=%1").arg(scanningCombo->currentIndex()));
0614         if (cField->isChecked() && scanningCombo->currentIndex() == 0) {
0615             params.append(QStringLiteral("top_field_first=%1").arg(fieldOrderCombo->currentIndex()));
0616         }
0617     }
0618     if (vcodec == "libx265") {
0619         // Most x265 parameters must be supplied through x265-params.
0620         switch (vRateControlCombo->currentIndex()) {
0621         case RenderPresetParams::RateControl::Average:
0622             params.append(QStringLiteral("vb=%bitrate+'k'"));
0623             break;
0624         case RenderPresetParams::RateControl::Constant: {
0625             // x265 does not expect bitrate suffixes and requires Kb/s
0626             params.append(QStringLiteral("vb=%bitrate"));
0627             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0628             break;
0629         }
0630         case RenderPresetParams::RateControl::Quality: {
0631             params.append(QStringLiteral("crf=%quality"));
0632             break;
0633         }
0634         case RenderPresetParams::RateControl::Constrained: {
0635             params.append(QStringLiteral("crf=%quality"));
0636             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0637             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0638             break;
0639         }
0640         }
0641         if (fixedGop->isEnabled() && fixedGop->isChecked()) {
0642             params.append(QStringLiteral("sc_threshold=0"));
0643         }
0644     } else if (vcodec.contains("nvenc")) {
0645         switch (vRateControlCombo->currentIndex()) {
0646         case RenderPresetParams::RateControl::Average:
0647             params.append(QStringLiteral("vb=%bitrate+'k'"));
0648             break;
0649         case RenderPresetParams::RateControl::Constant: {
0650             params.append(QStringLiteral("cbr=1 "));
0651             params.append(QStringLiteral("vb=%bitrate+'k'"));
0652             params.append(QStringLiteral("vminrate=%bitrate+'k'"));
0653             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0654             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0655             break;
0656         }
0657         case RenderPresetParams::RateControl::Quality: {
0658             params.append(QStringLiteral("rc=constqp"));
0659             params.append(QStringLiteral("vqp=%quality"));
0660             params.append(QStringLiteral("vq=%quality"));
0661             break;
0662         }
0663         case RenderPresetParams::RateControl::Constrained: {
0664             params.append(QStringLiteral("qmin=%quality"));
0665             params.append(QStringLiteral("vb=%cvbr")); // setIfNotSet(p, "vb", qRound(cvbr));
0666             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0667             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0668             break;
0669         }
0670         }
0671         /*if (ui->dualPassCheckbox->isChecked())
0672             setIfNotSet(p, "v2pass", 1);
0673         */
0674         if (fixedGop->isEnabled() && fixedGop->isChecked()) {
0675             params.append(QStringLiteral("sc_threshold=0 strict_gop=1"));
0676         }
0677     } else if (vcodec.endsWith("_amf")) {
0678         switch (vRateControlCombo->currentIndex()) {
0679         case RenderPresetParams::RateControl::Average:
0680             params.append(QStringLiteral("vb=%bitrate+'k'"));
0681             break;
0682         case RenderPresetParams::RateControl::Constant: {
0683             params.append(QStringLiteral("rc=cbr "));
0684             params.append(QStringLiteral("vb=%bitrate+'k'"));
0685             params.append(QStringLiteral("vminrate=%bitrate+'k'"));
0686             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0687             params.append(QStringLiteral("vbufsize=%1 ").arg(vBuffer->value() * 8 * 1024));
0688             break;
0689         }
0690         case RenderPresetParams::RateControl::Quality: {
0691             params.append(QStringLiteral("rc=cqp"));
0692             params.append(QStringLiteral("qp_i=%quality"));
0693             params.append(QStringLiteral("qp_p=%quality"));
0694             params.append(QStringLiteral("qp_b=%quality"));
0695             params.append(QStringLiteral("vq=%quality"));
0696             break;
0697         }
0698         case RenderPresetParams::RateControl::Constrained: {
0699             params.append(QStringLiteral("rc=vbr_peak"));
0700             params.append(QStringLiteral("qmin=%quality"));
0701             params.append(QStringLiteral("vb=%cvbr")); // setIfNotSet(p, "vb", qRound(cvbr));
0702             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0703             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0704             break;
0705         }
0706         }
0707         /*if (ui->dualPassCheckbox->isChecked())
0708             setIfNotSet(p, "v2pass", 1);
0709             */
0710         if (fixedGop->isEnabled() && fixedGop->isChecked()) {
0711             params.append(QStringLiteral("sc_threshold=0 strict_gop=1"));
0712         }
0713     } else {
0714         switch (vRateControlCombo->currentIndex()) {
0715         case RenderPresetParams::RateControl::Average:
0716             params.append(QStringLiteral("vb=%bitrate+'k'"));
0717             break;
0718         case RenderPresetParams::RateControl::Constant: {
0719             // const QString& b = ui->videoBitrateCombo->currentText();
0720             params.append(QStringLiteral("vb=%bitrate+'k'"));
0721             params.append(QStringLiteral("vminrate=%bitrate+'k'"));
0722             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0723             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0724             break;
0725         }
0726         case RenderPresetParams::RateControl::Quality: {
0727             if (vcodec.startsWith("libx264")) {
0728                 params.append(QStringLiteral("crf=%quality"));
0729             } else if (vcodec.startsWith("libvpx") || vcodec.startsWith("libaom-")) {
0730                 params.append(QStringLiteral("crf=%quality"));
0731                 params.append(QStringLiteral("vb=0")); // VP9 needs this to prevent constrained quality mode.
0732             } else if (vcodec.endsWith("_vaapi")) {
0733                 params.append(QStringLiteral("vglobal_quality=%quality"));
0734                 params.append(QStringLiteral("vq=%quality"));
0735             } else {
0736                 params.append(QStringLiteral("qscale=%quality"));
0737             }
0738             break;
0739         }
0740         case RenderPresetParams::RateControl::Constrained: {
0741             if (vcodec.startsWith("libx264") || vcodec.startsWith("libvpx") || vcodec.startsWith("libaom-")) {
0742                 params.append(QStringLiteral("crf=%quality"));
0743             } else if (vcodec.endsWith("_qsv") || vcodec.endsWith("_videotoolbox")) {
0744                 params.append(QStringLiteral("vb=%cvbr")); // setIfNotSet(p, "vb", qRound(cvbr));
0745             } else if (vcodec.endsWith("_vaapi")) {
0746                 params.append(QStringLiteral("vb=%bitrate+'k'"));
0747                 params.append(QStringLiteral("vglobal_quality=%quality"));
0748                 params.append(QStringLiteral("vq=%quality"));
0749             } else {
0750                 params.append(QStringLiteral("qscale=%quality"));
0751             }
0752             params.append(QStringLiteral("vmaxrate=%bitrate+'k'"));
0753             params.append(QStringLiteral("vbufsize=%1").arg(vBuffer->value() * 8 * 1024));
0754             break;
0755         }
0756         }
0757         if (fixedGop->isEnabled() && fixedGop->isChecked()) {
0758             if (vcodec.startsWith("libvpx") || vcodec.startsWith("libaom-")) {
0759                 params.append(QStringLiteral("keyint_min=%1").arg(gopSpinner->value()));
0760             } else {
0761                 params.append(QStringLiteral("sc_threshold=0"));
0762             }
0763         }
0764         /*
0765         if (vcodec.endsWith("_videotoolbox")) {
0766             setIfNotSet(p, "pix_fmt", "nv12");
0767         } else if (vcodec.endsWith("_vaapi")) {
0768             setIfNotSet(p, "vprofile", "main");
0769             setIfNotSet(p, "connection_type", "x11");
0770         }*/
0771     }
0772     if (gopSpinner->value() > 0) {
0773         params.append(QStringLiteral("g=%1").arg(gopSpinner->value()));
0774         if (bFramesSpinner->value() >= 0) {
0775             params.append(QStringLiteral("bf=%1").arg(bFramesSpinner->value()));
0776         }
0777     }
0778 
0779     // audio tab
0780     QString acodec = aCodecCombo->currentText();
0781     params.append(QStringLiteral("acodec=%1").arg(acodec));
0782 
0783     if (cChannels->isChecked() && audioChannels->currentData().toInt() > 0) {
0784         params.append(QStringLiteral("channels=%1").arg(audioChannels->currentData().toInt()));
0785     }
0786     if (cSampleR->isChecked() && audioSampleRate->currentText().toInt() > 0) {
0787         params.append(QStringLiteral("ar=%1").arg(audioSampleRate->currentText().toInt()));
0788     }
0789     if (acodec.startsWith(QStringLiteral("pcm_"))) {
0790         aRateControlCombo->setEnabled(false);
0791         aBitrate->setEnabled(false);
0792         aQuality->setEnabled(false);
0793     } else {
0794         aRateControlCombo->setEnabled(true);
0795         switch (aRateControlCombo->currentIndex()) {
0796         case RenderPresetParams::RateControl::Unknown:
0797             aBitrate->setEnabled(false);
0798             aQuality->setEnabled(false);
0799             break;
0800         case RenderPresetParams::RateControl::Average:
0801         case RenderPresetParams::RateControl::Constant:
0802             aBitrate->setEnabled(true);
0803             aQuality->setEnabled(false);
0804             break;
0805         case RenderPresetParams::RateControl::Quality:
0806         default:
0807             aBitrate->setEnabled(false);
0808             aQuality->setEnabled(true);
0809             break;
0810         };
0811         switch (aRateControlCombo->currentIndex()) {
0812         case RenderPresetParams::RateControl::Average:
0813         case RenderPresetParams::RateControl::Constant: {
0814             params.append(QStringLiteral("ab=%audiobitrate+'k'"));
0815             if (acodec == "libopus") {
0816                 if (aRateControlCombo->currentIndex() == RenderPresetParams::RateControl::Constant) {
0817                     params.append(QStringLiteral("vbr=off"));
0818                 } else {
0819                     params.append(QStringLiteral("vbr=constrained"));
0820                 }
0821             }
0822             break;
0823         }
0824         case RenderPresetParams::RateControl::Quality: {
0825             if (acodec == "libopus") {
0826                 params.append(QStringLiteral("vbr=on"));
0827                 params.append(QStringLiteral("compression_level=%audioquality"));
0828             } else {
0829                 params.append(QStringLiteral("aq=%audioquality"));
0830             }
0831         }
0832         default:
0833             break;
0834         }
0835     }
0836 
0837     QString addionalParams = additionalParams->toPlainText().simplified();
0838 
0839     QStringList removed;
0840     for (const auto &p : qAsConst(m_uiParams)) {
0841         QString store = addionalParams;
0842         if (store != addionalParams.remove(QRegularExpression(QStringLiteral("((^|\\s)%1=\\S*)").arg(p)))) {
0843             removed.append(p);
0844         }
0845     }
0846     if (!removed.isEmpty()) {
0847         overrideParamsWarning->setText(
0848             xi18nc("@info",
0849                    "The following parameters will not have an effect, because they get overwritten by the equivalent user interface options: <icode>%1</icode>",
0850                    removed.join(", ")));
0851         overrideParamsWarning->show();
0852     } else {
0853         overrideParamsWarning->hide();
0854     }
0855     addionalParams = addionalParams.simplified().prepend(params.join(QStringLiteral(" ")) + QStringLiteral(" "));
0856     parameters->setPlainText(addionalParams.simplified());
0857 }
0858 
0859 void RenderPresetDialog::setPixelAspectRatio(int num, int den)
0860 {
0861     parCombo->blockSignals(true);
0862     if (num < 1) num = 1;
0863     if (den < 1) den = 1;
0864     int gcdV = gcd(num, den);
0865     QString data = QStringLiteral("%1:%2").arg(num / gcdV).arg(den / gcdV);
0866     int ix = parCombo->findData(data);
0867     if (ix < 0) {
0868         parCombo->addItem(QStringLiteral("%L1 (%2:%3)").arg(double(num) / double(den), 0, 'g', 8).arg(num / gcdV).arg(den / gcdV), data);
0869         ix = parCombo->count() - 1;
0870     }
0871     parCombo->setCurrentIndex(ix);
0872     parCombo->blockSignals(false);
0873 }
0874 
0875 void RenderPresetDialog::updateDisplayAspectRatio()
0876 {
0877     displayAspectNum->blockSignals(true);
0878     displayAspectDen->blockSignals(true);
0879     QStringList par = parCombo->currentData().toString().split(QStringLiteral(":"));
0880     int parNum = resWidth->value();
0881     int parDen = resHeight->value();
0882     if (par.length() >= 2 && par.at(0).toInt() > 0 && par.at(1).toInt() > 0) {
0883         parNum *= par.at(0).toInt();
0884         parDen *= par.at(1).toInt();
0885     }
0886     int gcdV = gcd(parNum, parDen);
0887     displayAspectNum->setValue(parNum / gcdV);
0888     displayAspectDen->setValue(parDen / gcdV);
0889     displayAspectNum->blockSignals(false);
0890     displayAspectDen->blockSignals(false);
0891     slotUpdateParams();
0892 };
0893 
0894 QString RenderPresetDialog::saveName()
0895 {
0896     return m_saveName;
0897 }