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

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "transitionsrepository.hpp"
0007 #include "core.h"
0008 #include "kdenlivesettings.h"
0009 #include "xml/xml.hpp"
0010 #include <QFile>
0011 #include <QStandardPaths>
0012 
0013 #include "profiles/profilemodel.hpp"
0014 #include <mlt++/Mlt.h>
0015 
0016 std::unique_ptr<TransitionsRepository> TransitionsRepository::instance;
0017 std::once_flag TransitionsRepository::m_onceFlag;
0018 
0019 TransitionsRepository::TransitionsRepository()
0020     : AbstractAssetsRepository<AssetListType::AssetType>()
0021 {
0022     init();
0023     QStringList invalidTransition;
0024     for (const QString &effect : KdenliveSettings::favorite_transitions()) {
0025         if (!exists(effect)) {
0026             invalidTransition << effect;
0027         }
0028     }
0029     if (!invalidTransition.isEmpty()) {
0030         pCore->displayMessage(i18n("Some of your favorite compositions are invalid and were removed: %1", invalidTransition.join(QLatin1Char(','))),
0031                               ErrorMessage);
0032         QStringList newFavorites = KdenliveSettings::favorite_transitions();
0033         for (const QString &effect : qAsConst(invalidTransition)) {
0034             newFavorites.removeAll(effect);
0035         }
0036         KdenliveSettings::setFavorite_transitions(newFavorites);
0037     }
0038 }
0039 
0040 Mlt::Properties *TransitionsRepository::retrieveListFromMlt() const
0041 {
0042     return pCore->getMltRepository()->transitions();
0043 }
0044 
0045 Mlt::Properties *TransitionsRepository::getMetadata(const QString &assetId) const
0046 {
0047     return pCore->getMltRepository()->metadata(mlt_service_transition_type, assetId.toLatin1().data());
0048 }
0049 
0050 void TransitionsRepository::parseCustomAssetFile(const QString &file_name, std::unordered_map<QString, Info> &customAssets) const
0051 {
0052     QDomDocument doc;
0053     if (!Xml::docContentFromFile(doc, file_name, false)) {
0054         return;
0055     }
0056 
0057     QDomElement base = doc.documentElement();
0058     QDomNodeList transitions = doc.elementsByTagName(QStringLiteral("transition"));
0059 
0060     int nbr_transition = transitions.count();
0061     if (nbr_transition == 0) {
0062         qWarning() << "broken transition" << file_name;
0063         return;
0064     }
0065 
0066     for (int i = 0; i < nbr_transition; ++i) {
0067         QDomNode currentNode = transitions.item(i);
0068         if (currentNode.isNull()) {
0069             continue;
0070         }
0071         Info result;
0072         bool ok = parseInfoFromXml(currentNode.toElement(), result);
0073         if (!ok) {
0074             continue;
0075         }
0076         if (customAssets.count(result.id) > 0) {
0077             // qDebug() << "duplicate transition" << result.id;
0078         }
0079         result.xml = currentNode.toElement();
0080         QString type = result.xml.attribute(QStringLiteral("type"), QString());
0081         if (type == QLatin1String("hidden")) {
0082             result.type = AssetListType::AssetType::Hidden;
0083         } else if (type == QLatin1String("short")) {
0084             result.type = AssetListType::AssetType::VideoShortComposition;
0085         }
0086         if (getSingleTrackTransitions().contains(result.id)) {
0087             if (type == QLatin1String("audio")) {
0088                 result.type = AssetListType::AssetType::AudioTransition;
0089             } else {
0090                 result.type = AssetListType::AssetType::VideoTransition;
0091             }
0092         }
0093         customAssets[result.id] = result;
0094     }
0095 }
0096 
0097 std::unique_ptr<TransitionsRepository> &TransitionsRepository::get()
0098 {
0099     std::call_once(m_onceFlag, [] { instance.reset(new TransitionsRepository()); });
0100     return instance;
0101 }
0102 
0103 QStringList TransitionsRepository::assetDirs() const
0104 {
0105     return QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("transitions"), QStandardPaths::LocateDirectory);
0106 }
0107 
0108 void TransitionsRepository::parseType(Mlt::Properties *metadata, Info &res)
0109 {
0110     Mlt::Properties tags(mlt_properties(metadata->get_data("tags")));
0111     bool audio = QString(tags.get(0)) == QLatin1String("Audio");
0112 
0113     if (getSingleTrackTransitions().contains(res.id)) {
0114         if (audio) {
0115             res.type = AssetListType::AssetType::AudioTransition;
0116         } else {
0117             res.type = AssetListType::AssetType::VideoTransition;
0118         }
0119     } else {
0120         if (audio) {
0121             res.type = AssetListType::AssetType::AudioComposition;
0122         } else {
0123             res.type = AssetListType::AssetType::VideoComposition;
0124         }
0125     }
0126 }
0127 
0128 QSet<QString> TransitionsRepository::getSingleTrackTransitions()
0129 {
0130     // Disabled until same track transitions is implemented
0131     return {QStringLiteral("slide"), QStringLiteral("dissolve"), QStringLiteral("wipe"), QStringLiteral("mix")};
0132 }
0133 
0134 QString TransitionsRepository::assetBlackListPath() const
0135 {
0136     return QStringLiteral(":data/blacklisted_transitions.txt");
0137 }
0138 
0139 QString TransitionsRepository::assetPreferredListPath() const
0140 {
0141     // Transitions do not have "Main" filter implemented, so we return an empty
0142     // string instead of path to a file with that list
0143     return QLatin1String("");
0144 }
0145 
0146 std::unique_ptr<Mlt::Transition> TransitionsRepository::getTransition(const QString &transitionId) const
0147 {
0148     Q_ASSERT(exists(transitionId));
0149     QString service_name = m_assets.at(transitionId).mltId;
0150     // We create the Mlt element from its name
0151     auto transition = std::make_unique<Mlt::Transition>(pCore->getProjectProfile(), service_name.toUtf8().constData());
0152     transition->set("kdenlive_id", transitionId.toUtf8().constData());
0153     return transition;
0154 }
0155 
0156 bool TransitionsRepository::isAudio(const QString &transitionId) const
0157 {
0158     auto type = getType(transitionId);
0159     return type == AssetListType::AssetType::AudioComposition || type == AssetListType::AssetType::AudioTransition;
0160 }
0161 
0162 bool TransitionsRepository::isComposition(const QString &transitionId) const
0163 {
0164     auto type = getType(transitionId);
0165     return type == AssetListType::AssetType::AudioComposition || type == AssetListType::AssetType::VideoComposition ||
0166            type == AssetListType::AssetType::VideoShortComposition;
0167 }
0168 
0169 const QString TransitionsRepository::getCompositingTransition()
0170 {
0171     if (KdenliveSettings::gpu_accel()) {
0172         return QStringLiteral("movit.overlay");
0173     }
0174     if (KdenliveSettings::preferredcomposite() != i18n("auto") && exists(KdenliveSettings::preferredcomposite())) {
0175         return KdenliveSettings::preferredcomposite();
0176     }
0177     QStringList trackComposites = KdenliveSettings::compositingList();
0178     while (!trackComposites.isEmpty()) {
0179         const QString &cmp = trackComposites.takeFirst();
0180         if (exists(cmp)) {
0181             qDebug() << ":::: USING TRACK COMPOSITING: " << cmp;
0182             return cmp;
0183         }
0184     }
0185     qWarning() << "no compositing found";
0186     return QString();
0187 }