File indexing completed on 2024-05-19 04:55:45

0001 /*
0002     SPDX-FileCopyrightText: 2022 Julius Künzel <jk.kdedev@smartlab.uber.space>
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 #include "test_utils.hpp"
0006 // test specific headers
0007 #include "doc/kdenlivedoc.h"
0008 #include "render/renderrequest.h"
0009 #include "renderpresets/renderpresetmodel.hpp"
0010 #include "renderpresets/renderpresetrepository.hpp"
0011 
0012 TEST_CASE("Basic tests of the render preset model", "[RenderPresets]")
0013 {
0014 
0015     RenderPresetRepository::m_acodecsList = QStringList(QStringLiteral("libvorbis"));
0016     RenderPresetRepository::m_vcodecsList = QStringList(QStringLiteral("libvpx"));
0017     RenderPresetRepository::m_supportedFormats = QStringList(QStringLiteral("mp4"));
0018 
0019     SECTION("Test getters")
0020     {
0021         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("GettersTest"), QStringLiteral("Test"), QString(), QStringLiteral("mp4"),
0022                                                                        QString(), QString(), QString(), QString(), QString(), false));
0023         CHECK(model->name() == QStringLiteral("GettersTest"));
0024         CHECK(model->groupName() == QStringLiteral("Test"));
0025         CHECK(model->extension() == QStringLiteral("mp4"));
0026         // we did not set the format parameter, test if it was automatically
0027         // set based on the extension
0028         CHECK(model->getParam("f") == QStringLiteral("mp4"));
0029     }
0030 
0031     SECTION("Test parameter parsing")
0032     {
0033         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("ParamTest"), QStringLiteral("Test"),
0034                                                                        QStringLiteral("one=first two=second value three=third four=4"), QString(), QString(),
0035                                                                        QString(), QString(), QString(), QString(), false));
0036         // test hasParam
0037         CHECK(model->hasParam("one"));
0038         CHECK(model->hasParam("two"));
0039         CHECK(model->hasParam("three"));
0040         CHECK(model->hasParam("four"));
0041         CHECK_FALSE(model->hasParam("fifth"));
0042         CHECK_FALSE(model->hasParam("first"));
0043         CHECK_FALSE(model->hasParam("second"));
0044         CHECK_FALSE(model->hasParam("value"));
0045         CHECK_FALSE(model->hasParam("third"));
0046         CHECK_FALSE(model->hasParam("4"));
0047         CHECK_FALSE(model->hasParam("e"));
0048 
0049         // test getParam
0050         CHECK(model->getParam("one") == QStringLiteral("first"));
0051         CHECK(model->getParam("two") == QStringLiteral("second value"));
0052         CHECK(model->getParam("three") == QStringLiteral("third"));
0053         CHECK(model->getParam("four") == QStringLiteral("4"));
0054 
0055         CHECK(model->params().toString().length() == QString("one=first two=second value three=third four=4").length());
0056         CHECK(model->params().size() == 4);
0057         CHECK(model->params().contains("one"));
0058         CHECK(model->params().contains("two"));
0059         CHECK(model->params().contains("three"));
0060         CHECK(model->params().contains("four"));
0061 
0062         // test removing a normal parameter in the middle
0063         CHECK(model->params({QStringLiteral("three")}).toString().length() == QString("one=first two=second value four=4").length());
0064         CHECK(model->params({QStringLiteral("three")}).size() == 3);
0065         CHECK_FALSE(model->params({QStringLiteral("three")}).contains("three"));
0066 
0067         // test removing a parameter at the first position
0068         CHECK(model->params({QStringLiteral("one")}).toString().length() == QString("two=second value three=third four=4").length());
0069         CHECK(model->params({QStringLiteral("one")}).size() == 3);
0070         CHECK_FALSE(model->params({QStringLiteral("one")}).contains("one"));
0071 
0072         // test removing a parameter at the last position
0073         CHECK(model->params({QStringLiteral("four")}).toString().length() == QString("one=first two=second value three=third").length());
0074         CHECK(model->params({QStringLiteral("four")}).size() == 3);
0075         CHECK_FALSE(model->params({QStringLiteral("four")}).contains("four"));
0076 
0077         // test removing a non-existing parameter
0078         CHECK(model->params({QStringLiteral("fifth")}).toString().length() == QString("one=first two=second value three=third four=4").length());
0079         CHECK(model->params({QStringLiteral("fifth")}).size() == 4);
0080         CHECK_FALSE(model->params({QStringLiteral("fifth")}).contains("fifth"));
0081 
0082         // test removing a handing a value should do nothing
0083         CHECK(model->params({QStringLiteral("first")}).toString().length() == QString("one=first two=second value three=third four=4").length());
0084         CHECK(model->params({QStringLiteral("first")}).size() == 4);
0085         CHECK_FALSE(model->params({QStringLiteral("first")}).contains("first"));
0086 
0087         // test removing multiple parameters
0088         CHECK(model->params({QStringLiteral("one"), QStringLiteral("three")}).toString().length() == QString("two=second value four=4").length());
0089         CHECK(model->params({QStringLiteral("one"), QStringLiteral("three")}).size() == 2);
0090         CHECK_FALSE(model->params({QStringLiteral("one"), QStringLiteral("three")}).contains("one"));
0091         CHECK_FALSE(model->params({QStringLiteral("one"), QStringLiteral("three")}).contains("three"));
0092 
0093         // test removing a parameter with space in value
0094         CHECK(model->params({QStringLiteral("two")}).toString().length() == QString("one=first three=third four=4").length());
0095         CHECK(model->params({QStringLiteral("two")}).size() == 3);
0096         CHECK_FALSE(model->params({QStringLiteral("two")}).contains("two"));
0097     }
0098 
0099     SECTION("Test profile with no parameters")
0100     {
0101         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("EmptyParamTest"), QStringLiteral("Test"), QString(), QString(),
0102                                                                        QString(), QString(), QString(), QString(), QString(), false));
0103 
0104         // check there are really no parameters
0105         CHECK(model->params().toString().length() == 0);
0106         CHECK(model->params().size() == 0);
0107     }
0108 
0109     SECTION("Test unknown rate control")
0110     {
0111         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("UnknownRate"), QStringLiteral("Test"), QString(), QStringLiteral("mp4"),
0112                                                                        QString(), QString(), QString(), QString(), QString(), false));
0113         CHECK(model->params().videoRateControl() == RenderPresetParams::RateControl::Unknown);
0114     }
0115 
0116     /*SECTION("Test constant rate control")
0117     {
0118         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("Constant"), QStringLiteral("Test"), QStringLiteral(""),
0119     QStringLiteral("mp4"), QString(), QString(), QString(), QString(), QString(), false)); CHECK(model->videoRateControl() ==
0120     RenderPresetModel::RateControl::Constant);
0121     }
0122 
0123     SECTION("Test average rate control")
0124     {
0125         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("Constant"), QStringLiteral("Test"), QStringLiteral(""),
0126     QStringLiteral("mp4"), QString(), QString(), QString(), QString(), QString(), false)); CHECK(model->videoRateControl() ==
0127     RenderPresetModel::RateControl::Average);
0128     }
0129 
0130     SECTION("Test quality rate control")
0131     {
0132         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("Constant"), QStringLiteral("Test"), QStringLiteral(""),
0133     QStringLiteral("mp4"), QString(), QString(), QString(), QString(), QString(), false)); CHECK(model->videoRateControl() ==
0134     RenderPresetModel::RateControl::Quality);
0135     }*/
0136 
0137     SECTION("Test error")
0138     {
0139         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("ErrorTest"), QStringLiteral("Test"),
0140                                                                        QStringLiteral("acodec=doesnotexist"), QStringLiteral("mp4"), QString(), QString(),
0141                                                                        QString(), QString(), QString(), false));
0142 
0143         // we have a unknown audio codec, the error message should not be empty
0144         CHECK_FALSE(model->error().isEmpty());
0145     }
0146 
0147     SECTION("Test replace placeholders")
0148     {
0149         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("ParamTest"), QStringLiteral("Test"),
0150                                                                        QStringLiteral("one=%hello two=this%isaphval value three=%isaph four=4"), QString(),
0151                                                                        QString(), QString(), QString(), QString(), QString(), false));
0152 
0153         RenderPresetParams params = model->params();
0154         CHECK_FALSE(params.toString().contains(QStringLiteral("one=world")));
0155         CHECK_FALSE(params.toString().contains(QStringLiteral("two=thismynewval value")));
0156         CHECK_FALSE(params.toString().contains(QStringLiteral("three=mynew")));
0157 
0158         params.replacePlaceholder(QStringLiteral("%hello"), QStringLiteral("world"));
0159         CHECK(params.toString().contains(QStringLiteral("one=world")));
0160 
0161         params.replacePlaceholder(QStringLiteral("%isaph"), QStringLiteral("mynew"));
0162         CHECK(params.toString().contains(QStringLiteral("two=thismynewval value")));
0163         CHECK(params.toString().contains(QStringLiteral("three=mynew")));
0164     }
0165 
0166     SECTION("Test alpha detection placeholders")
0167     {
0168         std::unique_ptr<RenderPresetModel> model(new RenderPresetModel(QStringLiteral("AlphaTest"), QStringLiteral("Test"), QStringLiteral(""), QString(),
0169                                                                        QString(), QString(), QString(), QString(), QString(), false));
0170         CHECK_FALSE(model->params().hasAlpha());
0171 
0172         model.reset(new RenderPresetModel(QStringLiteral("AlphaTest"), QStringLiteral("Test"), QStringLiteral("pix_fmt=rgba"), QString(), QString(), QString(),
0173                                           QString(), QString(), QString(), false));
0174         CHECK(model->params().hasAlpha());
0175     }
0176 
0177     SECTION("Test x265 param")
0178     {
0179         std::unique_ptr<RenderPresetModel> model(
0180             new RenderPresetModel(QStringLiteral("AlphaTest"), QStringLiteral("Test"),
0181                                   QStringLiteral("properties=x265-medium f=mp4 vcodec=libx265 crf=%quality acodec=aac ab=%audiobitrate+'k'"), QString(),
0182                                   QString(), QString(), QString(), QString(), QString(), false));
0183 
0184         RenderPresetParams params = model->params();
0185 
0186         // we did not calulate the x265 params yet, so we expect to not have them
0187         CHECK_FALSE(params.contains(QStringLiteral("x265-params")));
0188 
0189         params.refreshX265Params();
0190         // now that we calculated them we expect them to exist
0191         CHECK(params.contains(QStringLiteral("x265-params")));
0192 
0193         params.insert(QStringLiteral("vcodec"), QStringLiteral("libx264"));
0194         params.refreshX265Params();
0195         // for a non-x265 codec they should not be there
0196         CHECK_FALSE(params.contains(QStringLiteral("x265-params")));
0197 
0198         params.insert(QStringLiteral("vcodec"), QStringLiteral("libx265"));
0199         params.refreshX265Params();
0200         // we set x265 codec again so the params should be back
0201         CHECK(params.contains(QStringLiteral("x265-params")));
0202     }
0203 }
0204 
0205 TEST_CASE("Tests of the render functions to use guides for sections", "[RenderRequestGuides]")
0206 {
0207     std::shared_ptr<DocUndoStack> undoStack = std::make_shared<DocUndoStack>(nullptr);
0208     std::shared_ptr<MarkerListModel> markerModel(new MarkerListModel(QString(), undoStack));
0209     markerModel->loadCategories(KdenliveDoc::getDefaultGuideCategories());
0210 
0211     int guideCategory = 3;
0212 
0213     // create some guides at different positions and in different categories
0214     markerModel->addMarker(GenTime(35, pCore->getCurrentFps()), QStringLiteral("test marker"), 1);
0215     markerModel->addMarker(GenTime(70, pCore->getCurrentFps()), QStringLiteral("test marker"), guideCategory);
0216     markerModel->addMarker(GenTime(25, pCore->getCurrentFps()), QStringLiteral("test marker"), guideCategory);
0217 
0218     // set the bounding range
0219     int in = 0;
0220     int out = 100;
0221 
0222     RenderRequest *r = new RenderRequest();
0223     r->m_boundingIn = in;
0224     r->m_boundingOut = out;
0225 
0226     std::vector<RenderRequest::RenderSection> sections;
0227 
0228     SECTION("Single Guide")
0229     {
0230         // Category 1 contains only one guide and hence should have 2 sections
0231         r->setGuideParams(markerModel, true, 1);
0232         sections = r->getGuideSections();
0233         CHECK(sections.size() == 2);
0234     }
0235 
0236     SECTION("No markers at all")
0237     {
0238         // Category 0 has no guides and should return no sections at all
0239         r->setGuideParams(markerModel, true, 0);
0240         sections = r->getGuideSections();
0241         CHECK(sections.size() == 0);
0242     }
0243 
0244     SECTION("Multiple Guides")
0245     {
0246         r->setGuideParams(markerModel, true, guideCategory);
0247         sections = r->getGuideSections();
0248         CHECK(sections.size() == 3);
0249 
0250         // Add one more marker and check this leads to one more section
0251         markerModel->addMarker(GenTime(51, pCore->getCurrentFps()), QStringLiteral("test marker"), guideCategory);
0252         sections = r->getGuideSections();
0253         CHECK(sections.size() == 4);
0254 
0255         // The size should not change if we add a guide at the start, because there should always be a section from the start.
0256         // Our guide should only replace the automatically generated section which in our case should only affect the name.
0257         markerModel->addMarker(GenTime(0, pCore->getCurrentFps()), QStringLiteral("test marker"), guideCategory);
0258         sections = r->getGuideSections();
0259         CHECK(sections.size() == 4);
0260 
0261         // check in and out points
0262         CHECK(sections.at(0).in == in);
0263         CHECK(sections.at(0).out == 24);
0264         CHECK(sections.at(1).in == 25);
0265         CHECK(sections.at(1).out == 50);
0266         CHECK(sections.at(2).in == 51);
0267         CHECK(sections.at(2).out == 69);
0268         CHECK(sections.at(3).in == 70);
0269         CHECK(sections.at(3).out == out);
0270 
0271         // check no section name appears twice, eventhough we have guides with the same name
0272         QStringList names;
0273         for (const auto &section : sections) {
0274             names << section.name;
0275         }
0276         CHECK(names.removeDuplicates() == 0);
0277 
0278         // change the bounding range
0279         in = 10;
0280         out = 60;
0281         r->m_boundingIn = in;
0282         r->m_boundingOut = out;
0283 
0284         sections = r->getGuideSections();
0285         CHECK(sections.size() == 3);
0286 
0287         // check in and out points
0288         CHECK(sections.at(0).in == in);
0289         CHECK(sections.at(0).out == 24);
0290         CHECK(sections.at(1).in == 25);
0291         CHECK(sections.at(1).out == 50);
0292         CHECK(sections.at(2).in == 51);
0293         CHECK(sections.at(2).out == out);
0294     }
0295 }