File indexing completed on 2024-04-21 04:52:01

0001 /*
0002    SPDX-FileCopyrightText: 2017 Nicolas Carion
0003    SPDX-FileCopyrightText: 2022 Julius Künzel <jk.kdedev@smartlab.uber.space>
0004    SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005    This file is part of Kdenlive. See www.kdenlive.org.
0006 */
0007 
0008 #include "renderpresetmodel.hpp"
0009 #include "core.h"
0010 #include "kdenlive_debug.h"
0011 #include "kdenlivesettings.h"
0012 #include "profiles/profilemodel.hpp"
0013 #include "profiles/profilerepository.hpp"
0014 #include "renderpresetrepository.hpp"
0015 
0016 #include <mlt++/MltRepository.h>
0017 
0018 #include <KLocalizedString>
0019 #include <KMessageWidget>
0020 #include <QDir>
0021 #include <QFile>
0022 #include <QRegularExpression>
0023 #include <memory>
0024 
0025 QString RenderPresetParams::toString()
0026 {
0027     QString string;
0028     RenderPresetParams::const_iterator i = this->constBegin();
0029     while (i != this->constEnd()) {
0030         string.append(QStringLiteral("%1=%2 ").arg(i.key(), i.value()));
0031         ++i;
0032     }
0033     return string.simplified();
0034 }
0035 
0036 void RenderPresetParams::insertFromString(const QString &params, bool overwrite)
0037 {
0038     // split only at white spaces followed by a new parameter
0039     // to avoid splitting values that contain whitespaces
0040     static const QRegularExpression regexp(R"(\s+(?=\S*=))");
0041 
0042     QStringList paramList = params.split(regexp, Qt::SkipEmptyParts);
0043     for (QString param : paramList) {
0044         if (!param.contains(QLatin1Char('='))) {
0045             // invalid param, skip
0046             continue;
0047         }
0048         const QString key = param.section(QLatin1Char('='), 0, 0);
0049         const QString value = param.section(QLatin1Char('='), 1);
0050         if (contains(key) && !overwrite) {
0051             // don't overwrite existing params
0052             continue;
0053         }
0054         insert(key, value);
0055     }
0056 }
0057 
0058 void RenderPresetParams::replacePlaceholder(const QString &placeholder, const QString &newValue)
0059 {
0060     RenderPresetParams newParams;
0061     RenderPresetParams::const_iterator i = this->constBegin();
0062     while (i != this->constEnd()) {
0063         QString value = i.value();
0064         newParams.insert(i.key(), value.replace(placeholder, newValue));
0065         ++i;
0066     }
0067 
0068     clear();
0069     QMap<QString, QString>::const_iterator j = newParams.constBegin();
0070     while (j != newParams.constEnd()) {
0071         insert(j.key(), j.value());
0072         ++j;
0073     }
0074 }
0075 
0076 void RenderPresetParams::refreshX265Params()
0077 {
0078     if (!isX265()) {
0079         remove(QStringLiteral("x265-params"));
0080         return;
0081     }
0082     QStringList x265Params;
0083     if (contains(QStringLiteral("crf"))) {
0084         x265Params.append(QStringLiteral("crf=%1").arg(value(QStringLiteral("crf"))));
0085     }
0086     if (videoRateControl() == RenderPresetParams::Constant && contains(QStringLiteral("vb"))) {
0087         QString vb = value(QStringLiteral("vb"));
0088         QString newVal;
0089         if (vb == QStringLiteral("%bitrate") || vb == QStringLiteral("%bitrate+'k")) {
0090             newVal = QStringLiteral("%bitrate");
0091         } else {
0092             newVal = vb.replace('k', QLatin1String("")).replace('M', QStringLiteral("000"));
0093         }
0094         x265Params.append(QStringLiteral("bitrate=%1").arg(newVal));
0095         x265Params.append(QStringLiteral("vbv-maxrate=%1").arg(newVal));
0096     } else if (videoRateControl() == RenderPresetParams::Constrained && contains(QStringLiteral("vmaxrate"))) {
0097         QString vmax = value(QStringLiteral("vmaxrate"));
0098         QString newVal;
0099         if (vmax == QStringLiteral("%bitrate") || vmax == QStringLiteral("%bitrate+'k")) {
0100             newVal = QStringLiteral("%bitrate");
0101         } else {
0102             newVal = vmax.replace('k', QLatin1String("")).replace('M', QStringLiteral("000"));
0103         }
0104         x265Params.append(QStringLiteral("vbv-maxrate=%1").arg(newVal));
0105     }
0106     if (contains(QStringLiteral("vbufsize"))) {
0107         int val = value(QStringLiteral("vbufsize")).toInt();
0108         x265Params.append(QStringLiteral("vbv-bufsize=%1").arg(val / 1024));
0109     }
0110     if (contains(QStringLiteral("bf"))) {
0111         x265Params.append(QStringLiteral("bframes=%1").arg(value(QStringLiteral("bf"))));
0112     }
0113     if (contains(QStringLiteral("g"))) {
0114         x265Params.append(QStringLiteral("keyint=%1").arg(value(QStringLiteral("g"))));
0115     }
0116     if (contains(QStringLiteral("top_field_first")) && value(QStringLiteral("progressive")).toInt() == 0) {
0117         int val = value(QStringLiteral("top_field_first")).toInt();
0118         x265Params.append(QStringLiteral("interlace=%1").arg(val == 1 ? QStringLiteral("tff") : QStringLiteral("bff")));
0119     }
0120     if (contains(QStringLiteral("sc_threshold")) && value(QStringLiteral("sc_threshold")).toInt() == 0) {
0121         x265Params.append(QStringLiteral("scenecut=0"));
0122     }
0123     if (contains(QStringLiteral("x265-params"))) {
0124         x265Params.append(value(QStringLiteral("x265-params")));
0125     }
0126 
0127     if (x265Params.isEmpty()) {
0128         remove(QStringLiteral("x265-params"));
0129     } else {
0130         insert(QStringLiteral("x265-params"), x265Params.join(QStringLiteral(":")));
0131     }
0132 }
0133 
0134 RenderPresetParams::RateControl RenderPresetParams::videoRateControl() const
0135 {
0136     QString vbufsize = value(QStringLiteral("vbufsize"));
0137     QString vcodec = value(QStringLiteral("vcodec"));
0138     if (contains(QStringLiteral("crf"))) {
0139         return !vbufsize.isEmpty() ? (vcodec.endsWith("_videotoolbox") ? RateControl::Average : RateControl::Quality) : RateControl::Constrained;
0140     }
0141     if (contains(QStringLiteral("vq")) || contains(QStringLiteral("vqp")) || contains(QStringLiteral("vglobal_quality")) ||
0142         contains(QStringLiteral("qscale"))) {
0143         return vbufsize.isEmpty() ? RateControl::Quality : RateControl::Constrained;
0144     } else if (!vbufsize.isEmpty()) {
0145         return RateControl::Constant;
0146     }
0147     QString param = value(QStringLiteral("vb"));
0148     param = param.replace('+', "").replace('k', "").replace('k', "").replace('M', "000");
0149     if (!param.isEmpty()) {
0150         return (param.contains(QStringLiteral("%bitrate")) || param.toInt() > 0) ? RateControl::Average : RateControl::Quality;
0151     }
0152     return RateControl::Unknown;
0153 }
0154 
0155 bool RenderPresetParams::hasAlpha()
0156 {
0157     QStringList alphaFormats = {QLatin1String("argb"), QLatin1String("abgr"), QLatin1String("bgra"), QLatin1String("rgba"),
0158                                 QLatin1String("gbra"), QLatin1String("yuva"), QLatin1String("ya"),   QLatin1String("yuva")};
0159     const QString selected = value(QStringLiteral("pix_fmt"));
0160     for (auto &f : alphaFormats) {
0161         if (selected.startsWith(f)) {
0162             return true;
0163         }
0164     }
0165     return false;
0166 }
0167 
0168 bool RenderPresetParams::isImageSequence()
0169 {
0170     return value(QStringLiteral("properties")).startsWith("stills/");
0171 }
0172 
0173 bool RenderPresetParams::isX265()
0174 {
0175     return value(QStringLiteral("vcodec")).toLower() == QStringLiteral("libx265");
0176 }
0177 
0178 RenderPresetModel::RenderPresetModel(QDomElement preset, const QString &presetFile, bool editable, const QString &groupName, const QString &renderer)
0179     : m_presetFile(presetFile)
0180     , m_editable(editable)
0181     , m_name(preset.attribute(QStringLiteral("name")))
0182     , m_note()
0183     , m_standard(preset.attribute(QStringLiteral("standard")))
0184     , m_params()
0185     , m_groupName(preset.attribute(QStringLiteral("category"), groupName))
0186     , m_renderer(renderer)
0187     , m_url(preset.attribute(QStringLiteral("url")))
0188     , m_speeds(preset.attribute(QStringLiteral("speeds")))
0189     , m_defaultSpeedIndex(preset.attribute(QStringLiteral("defaultspeedindex"), QStringLiteral("-1")).toInt())
0190     , m_topFieldFirst(preset.attribute(QStringLiteral("top_field_first")))
0191 {
0192     if (m_groupName.isEmpty()) {
0193         m_groupName = i18nc("Category Name", "Custom");
0194     }
0195 
0196     m_extension = preset.attribute(QStringLiteral("extension"));
0197     m_manual = preset.attribute(QStringLiteral("manual")) == QLatin1String("1");
0198 
0199     QTextDocument docConvert;
0200     docConvert.setHtml(preset.attribute(QStringLiteral("args")));
0201     // setParams after we know the extension to make setting the format automatically work
0202     setParams(docConvert.toPlainText().simplified());
0203 
0204     if (m_defaultSpeedIndex < 0) {
0205         m_defaultSpeedIndex = (speeds().count() - 1) * 0.75;
0206     }
0207 
0208     m_vQualities = preset.attribute(QStringLiteral("qualities"));
0209     m_defaultVQuality = preset.attribute(QStringLiteral("defaultquality"));
0210     m_vBitrates = preset.attribute(QStringLiteral("bitrates"));
0211     m_defaultVBitrate = preset.attribute(QStringLiteral("defaultbitrate"));
0212 
0213     m_aQualities = preset.attribute(QStringLiteral("audioqualities"));
0214     m_defaultAQuality = preset.attribute(QStringLiteral("defaultaudioquality"));
0215     m_aBitrates = preset.attribute(QStringLiteral("audiobitrates"));
0216     m_defaultABitrate = preset.attribute(QStringLiteral("defaultaudiobitrate"));
0217 
0218     checkPreset();
0219 }
0220 
0221 RenderPresetModel::RenderPresetModel(const QString &groupName, const QString &path, QString presetName, const QString &params, bool codecInName)
0222     : m_editable(false)
0223     , m_manual(false)
0224     , m_params()
0225     , m_groupName(groupName)
0226     , m_renderer(QStringLiteral("avformat"))
0227     , m_defaultSpeedIndex(-1)
0228 {
0229     KConfig config(path, KConfig::SimpleConfig);
0230     KConfigGroup group = config.group(QByteArray());
0231     QString vcodec = group.readEntry("vcodec");
0232     QString acodec = group.readEntry("acodec");
0233     m_extension = group.readEntry("meta.preset.extension");
0234     // setParams after we know the extension to make setting the format automatically work
0235     setParams(params);
0236     m_note = group.readEntry("meta.preset.note");
0237 
0238     if (codecInName && (!vcodec.isEmpty() || !acodec.isEmpty())) {
0239         presetName.append(" (");
0240         if (!vcodec.isEmpty()) {
0241             presetName.append(vcodec);
0242             if (!acodec.isEmpty()) {
0243                 presetName.append("+" + acodec);
0244             }
0245         } else if (!acodec.isEmpty()) {
0246             presetName.append(acodec);
0247         }
0248         presetName.append(QLatin1Char(')'));
0249     }
0250     m_name = presetName;
0251     checkPreset();
0252 }
0253 
0254 RenderPresetModel::RenderPresetModel(const QString &name, const QString &groupName, const QString &params, const QString &extension,
0255                                      const QString &defaultVBitrate, const QString &defaultVQuality, const QString &defaultABitrate,
0256                                      const QString &defaultAQuality, const QString &speedsString, bool manualPreset)
0257     : m_presetFile()
0258     , m_editable()
0259     , m_name(name)
0260     , m_note()
0261     , m_standard()
0262     , m_extension(extension)
0263     , m_groupName(groupName)
0264     , m_renderer(QStringLiteral("avformat"))
0265     , m_url()
0266     , m_speeds(speedsString)
0267     , m_topFieldFirst()
0268     , m_vBitrates()
0269     , m_defaultVBitrate(defaultVBitrate)
0270     , m_vQualities()
0271     , m_defaultVQuality(defaultVQuality)
0272     , m_aBitrates()
0273     , m_defaultABitrate(defaultABitrate)
0274     , m_aQualities()
0275     , m_defaultAQuality(defaultAQuality)
0276 {
0277     setParams(params);
0278     if (m_groupName.isEmpty()) {
0279         m_groupName = i18nc("Category Name", "Custom");
0280     }
0281 
0282     m_defaultSpeedIndex = (speeds().count() - 1) * 0.75;
0283     m_manual = manualPreset;
0284 
0285     checkPreset();
0286 }
0287 
0288 void RenderPresetModel::checkPreset()
0289 {
0290     QStringList acodecs = RenderPresetRepository::acodecs();
0291     QStringList vcodecs = RenderPresetRepository::vcodecs();
0292     QStringList supportedFormats = RenderPresetRepository::supportedFormats();
0293 
0294     bool replaceVorbisCodec = acodecs.contains(QStringLiteral("libvorbis"));
0295     bool replaceLibfaacCodec = acodecs.contains(QStringLiteral("libfaac"));
0296 
0297     if (replaceVorbisCodec && (m_params.value(QStringLiteral("acodec")) == QStringLiteral("vorbis"))) {
0298         // replace vorbis with libvorbis
0299         m_params[QStringLiteral("acodec")] = QLatin1String("libvorbis");
0300     }
0301     if (replaceLibfaacCodec && (m_params.value(QStringLiteral("acodec")) == QStringLiteral("aac"))) {
0302         // replace aac with libfaac
0303         m_params[QStringLiteral("acodec")] = QLatin1String("libfaac");
0304     }
0305 
0306     // We borrow a reference to the profile's pointer to query it more easily
0307     std::unique_ptr<ProfileModel> &profile = pCore->getCurrentProfile();
0308     double project_framerate = double(profile->frame_rate_num()) / profile->frame_rate_den();
0309 
0310     if (m_standard.isEmpty() ||
0311         (m_standard.contains(QStringLiteral("PAL"), Qt::CaseInsensitive) && profile->frame_rate_num() == 25 && profile->frame_rate_den() == 1) ||
0312         (m_standard.contains(QStringLiteral("NTSC"), Qt::CaseInsensitive) && profile->frame_rate_num() == 30000 && profile->frame_rate_den() == 1001)) {
0313         // Standard OK
0314     } else {
0315         m_errors = i18n("Standard (%1) not compatible with project profile (%2)", m_standard, project_framerate);
0316         return;
0317     }
0318 
0319     if (hasParam(QStringLiteral("mlt_profile"))) {
0320         QString profile_str = getParam(QStringLiteral("mlt_profile"));
0321         std::unique_ptr<ProfileModel> &target_profile = ProfileRepository::get()->getProfile(profile_str);
0322         if (target_profile->frame_rate_den() > 0) {
0323             double profile_rate = double(target_profile->frame_rate_num()) / target_profile->frame_rate_den();
0324             if (int(1000.0 * profile_rate) != int(1000.0 * project_framerate)) {
0325                 m_errors = i18n("Frame rate (%1) not compatible with project profile (%2)", profile_rate, project_framerate);
0326                 return;
0327             }
0328         }
0329     }
0330 
0331     if (hasParam(QStringLiteral("properties"))) {
0332         // This is a native MLT render profile, check the file for codec
0333         QString presetName = getParam(QStringLiteral("properties"));
0334         presetName.prepend(QStringLiteral("consumer/avformat/"));
0335         std::unique_ptr<Mlt::Properties> presets(pCore->getMltRepository()->presets());
0336         std::unique_ptr<Mlt::Properties> preset(new Mlt::Properties(mlt_properties(presets->get_data(presetName.toUtf8().constData()))));
0337         const QString format = QString(preset->get("f")).toLower();
0338         if (!format.isEmpty() && !supportedFormats.contains(format)) {
0339             m_errors = i18n("Unsupported video format: %1", format);
0340             return;
0341         }
0342         const QString vcodec = QString(preset->get("vcodec")).toLower();
0343         if (!vcodec.isEmpty() && !vcodecs.contains(vcodec)) {
0344             m_errors = i18n("Unsupported video codec: %1", vcodec);
0345             return;
0346         }
0347         const QString acodec = QString(preset->get("acodec")).toLower();
0348         if (!acodec.isEmpty() && !acodecs.contains(acodec)) {
0349             m_errors = i18n("Unsupported audio codec: %1", acodec);
0350             return;
0351         }
0352     }
0353 
0354     // Make sure the selected preset uses an installed avformat codec / format
0355     QString format;
0356     format = getParam(QStringLiteral("f")).toLower();
0357     if (!format.isEmpty() && !supportedFormats.contains(format)) {
0358         m_errors = i18n("Unsupported video format: %1", format);
0359         return;
0360     }
0361 
0362     // check for missing audio codecs
0363     format = getParam(QStringLiteral("acodec")).toLower();
0364     if (!format.isEmpty() && !acodecs.contains(format)) {
0365         m_errors = i18n("Unsupported audio codec: %1", format);
0366         return;
0367     }
0368     // check for missing video codecs
0369     format = getParam(QStringLiteral("vcodec")).toLower();
0370     if (!format.isEmpty() && !vcodecs.contains(format)) {
0371         m_errors = i18n("Unsupported video codec: %1", format);
0372         return;
0373     }
0374 
0375     if (hasParam(QStringLiteral("profile"))) {
0376         m_warnings = i18n("This render preset uses a 'profile' parameter.<br />Unless you know what you are doing you will probably "
0377                           "have to change it to 'mlt_profile'.");
0378         return;
0379     }
0380 }
0381 
0382 QDomElement RenderPresetModel::toXml()
0383 {
0384     QDomDocument doc;
0385     QDomElement profileElement = doc.createElement(QStringLiteral("profile"));
0386     doc.appendChild(profileElement);
0387 
0388     profileElement.setAttribute(QStringLiteral("name"), m_name);
0389     profileElement.setAttribute(QStringLiteral("category"), m_groupName);
0390     if (!m_extension.isEmpty()) {
0391         profileElement.setAttribute(QStringLiteral("extension"), m_extension);
0392     }
0393     if (m_manual) {
0394         profileElement.setAttribute(QStringLiteral("manual"), QStringLiteral("1"));
0395     }
0396     profileElement.setAttribute(QStringLiteral("args"), m_params.toString());
0397     if (!m_defaultVBitrate.isEmpty()) {
0398         profileElement.setAttribute(QStringLiteral("defaultbitrate"), m_defaultVBitrate);
0399     }
0400     if (!m_vBitrates.isEmpty()) {
0401         profileElement.setAttribute(QStringLiteral("bitrates"), m_vBitrates);
0402     }
0403     if (!m_defaultVQuality.isEmpty()) {
0404         profileElement.setAttribute(QStringLiteral("defaultquality"), m_defaultVQuality);
0405     }
0406     if (!m_vQualities.isEmpty()) {
0407         profileElement.setAttribute(QStringLiteral("qualities"), m_vQualities);
0408     }
0409     if (!m_defaultABitrate.isEmpty()) {
0410         profileElement.setAttribute(QStringLiteral("defaultaudiobitrate"), m_defaultABitrate);
0411     }
0412     if (!m_aBitrates.isEmpty()) {
0413         profileElement.setAttribute(QStringLiteral("audiobitrates"), m_aBitrates);
0414     }
0415     if (!m_defaultAQuality.isEmpty()) {
0416         profileElement.setAttribute(QStringLiteral("defaultaudioquality"), m_defaultAQuality);
0417     }
0418     if (!m_aQualities.isEmpty()) {
0419         profileElement.setAttribute(QStringLiteral("audioqualities"), m_aQualities);
0420     }
0421     if (!m_speeds.isEmpty()) {
0422         // profile has a variable speed
0423         profileElement.setAttribute(QStringLiteral("speeds"), m_speeds);
0424         if (m_defaultSpeedIndex > 0) {
0425             profileElement.setAttribute(QStringLiteral("defaultspeedindex"), m_defaultSpeedIndex);
0426         }
0427     }
0428     return doc.documentElement();
0429 }
0430 
0431 void RenderPresetModel::setParams(const QString &params)
0432 {
0433     m_params.clear();
0434     m_params.insertFromString(params, true);
0435 
0436     if (!hasParam(QStringLiteral("f")) && !m_extension.isEmpty() && RenderPresetRepository::supportedFormats().contains(m_extension)) {
0437         m_params.insert(QStringLiteral("f"), m_extension);
0438     }
0439 }
0440 
0441 RenderPresetParams RenderPresetModel::params(QStringList removeParams) const
0442 {
0443     RenderPresetParams newParams = m_params;
0444     for (QString toRemove : removeParams) {
0445         newParams.remove(toRemove);
0446     }
0447     return newParams;
0448 }
0449 
0450 QStringList RenderPresetModel::defaultValues() const
0451 {
0452     QString defaultSpeedParams;
0453     QStringList presetSpeeds = speeds();
0454     if (!presetSpeeds.isEmpty() && m_defaultSpeedIndex < presetSpeeds.count()) {
0455         defaultSpeedParams = presetSpeeds.at(m_defaultSpeedIndex);
0456     }
0457     return {defaultSpeedParams, m_defaultABitrate, m_defaultAQuality, m_defaultVBitrate, m_defaultVQuality};
0458 }
0459 
0460 QString RenderPresetModel::extension() const
0461 {
0462     if (!m_extension.isEmpty()) {
0463         return m_extension;
0464     }
0465     return getParam(QStringLiteral("f"));
0466 };
0467 
0468 QStringList RenderPresetModel::audioBitrates() const
0469 {
0470     return m_aBitrates.split(QLatin1Char(','), Qt::SkipEmptyParts);
0471 }
0472 
0473 QString RenderPresetModel::defaultABitrate() const
0474 {
0475     return m_defaultABitrate;
0476 }
0477 
0478 QStringList RenderPresetModel::audioQualities() const
0479 {
0480     if (!m_aQualities.isEmpty()) {
0481         return m_aQualities.split(QLatin1Char(','), Qt::SkipEmptyParts);
0482     } else {
0483         // ATTENTION: historically qualities are sorted from best to worse for some reason
0484         QString acodec = getParam(QStringLiteral("acodec")).toLower();
0485         if (acodec == "libmp3lame") {
0486             return {"0", "9"};
0487         } else if (acodec == "libvorbis" || acodec == "vorbis" || acodec == "libopus") {
0488             return {"10", "0"};
0489         } else {
0490             return {"500", "0"};
0491         }
0492     }
0493 }
0494 
0495 QString RenderPresetModel::defaultAQuality() const
0496 {
0497     return m_defaultAQuality;
0498 }
0499 
0500 QStringList RenderPresetModel::videoBitrates() const
0501 {
0502     return m_vBitrates.split(QLatin1Char(','), Qt::SkipEmptyParts);
0503 }
0504 
0505 QString RenderPresetModel::defaultVBitrate() const
0506 {
0507     return m_defaultVBitrate;
0508 }
0509 
0510 QStringList RenderPresetModel::videoQualities() const
0511 {
0512     if (!m_vQualities.isEmpty()) {
0513         return m_vQualities.split(QLatin1Char(','), Qt::SkipEmptyParts);
0514     } else {
0515         // ATTENTION: historically qualities are sorted from best to worse for some reason
0516         QString vcodec = getParam(QStringLiteral("vcodec")).toLower();
0517         if (vcodec == "libx265" || vcodec.contains("nvenc") || vcodec.endsWith("_amf") || vcodec.startsWith("libx264") || vcodec.endsWith("_vaapi") ||
0518             vcodec.endsWith("_qsv")) {
0519             return {"0", "51"};
0520         } else if (vcodec.startsWith("libvpx") || vcodec.startsWith("libaom-")) {
0521             return {"0", "63"};
0522         } else if (vcodec.startsWith("libwebp")) {
0523             return {"100", "0"};
0524         } else {
0525             return {"1", "31"};
0526         }
0527     }
0528 }
0529 
0530 QString RenderPresetModel::defaultVQuality() const
0531 {
0532     return m_defaultVQuality;
0533 }
0534 
0535 bool RenderPresetModel::editable() const
0536 {
0537     return m_editable;
0538 }
0539 
0540 QStringList RenderPresetModel::speeds() const
0541 {
0542     return m_speeds.split(QLatin1Char(';'), Qt::SkipEmptyParts);
0543 }
0544 
0545 QString RenderPresetModel::getParam(const QString &name) const
0546 {
0547     return params().value(name);
0548 }
0549 
0550 bool RenderPresetModel::isManual() const
0551 {
0552     return m_manual;
0553 }
0554 
0555 bool RenderPresetModel::hasParam(const QString &name) const
0556 {
0557     // return params().contains(name);
0558     return !getParam(name).isEmpty();
0559 }
0560 
0561 RenderPresetParams::RateControl RenderPresetModel::audioRateControl() const
0562 {
0563     QString value = getParam(QStringLiteral("vbr"));
0564     if (!value.isEmpty()) {
0565         // libopus rate mode
0566         if (value == QStringLiteral("off")) {
0567             return RenderPresetParams::Constant;
0568         }
0569         if (value == QStringLiteral("constrained")) {
0570             return RenderPresetParams::Average;
0571         }
0572         return RenderPresetParams::Quality;
0573     }
0574     if (hasParam(QStringLiteral("aq")) || hasParam(QStringLiteral("compression_level"))) {
0575         return RenderPresetParams::Quality;
0576     }
0577     if (hasParam(QStringLiteral("ab"))) {
0578         return RenderPresetParams::Constant;
0579     }
0580     return RenderPresetParams::Unknown;
0581 }
0582 
0583 RenderPresetModel::InstallType RenderPresetModel::installType() const
0584 {
0585     if (m_editable) {
0586         if (m_presetFile.endsWith(QLatin1String("customprofiles.xml"))) {
0587             return InstallType::Custom;
0588         } else {
0589             return InstallType::Download;
0590         }
0591     }
0592     return InstallType::BuildIn;
0593 }
0594 
0595 bool RenderPresetModel::hasFixedSize() const
0596 {
0597     // TODO
0598     return hasParam(QStringLiteral("s")) || m_params.contains(QLatin1String("%dv_standard"));
0599 }
0600 
0601 QString RenderPresetModel::error() const
0602 {
0603     return m_errors;
0604 }
0605 
0606 QString RenderPresetModel::warning() const
0607 {
0608     return m_warnings;
0609 }
0610 
0611 int RenderPresetModel::estimateFileSize(int length)
0612 {
0613     Q_UNUSED(length)
0614     // TODO
0615     /*RateControl vrc = videoRateControl();
0616     if (vrc == Average || vrc == Constant) {
0617 
0618         return m_defaultVBitrate.toInt() * length;
0619     }*/
0620     return -1;
0621 }