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

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "binplaylist.hpp"
0007 #include "abstractprojectitem.h"
0008 #include "bin/model/markerlistmodel.hpp"
0009 #include "core.h"
0010 #include "profiles/profilemodel.hpp"
0011 #include "projectclip.h"
0012 #include <mlt++/Mlt.h>
0013 
0014 QString BinPlaylist::binPlaylistId = QString("main_bin");
0015 
0016 BinPlaylist::BinPlaylist(const QUuid &uuid)
0017     : m_binPlaylist(new Mlt::Playlist(pCore->getProjectProfile()))
0018     , m_uuid(uuid)
0019 {
0020     m_binPlaylist->set("id", binPlaylistId.toUtf8().constData());
0021 }
0022 
0023 BinPlaylist::~BinPlaylist()
0024 {
0025     Q_ASSERT(m_binPlaylist->count() == 0);
0026 }
0027 
0028 void BinPlaylist::manageBinItemInsertion(const std::shared_ptr<AbstractProjectItem> &binElem)
0029 {
0030     QString id = binElem->clipId();
0031     switch (binElem->itemType()) {
0032     case AbstractProjectItem::FolderItem: {
0033         // When a folder is inserted, we have to store its path into the properties
0034         if (binElem->parent()) {
0035             QString propertyName = "kdenlive:folder." + binElem->parent()->clipId() + QLatin1Char('.') + id;
0036             m_binPlaylist->set(propertyName.toUtf8().constData(), binElem->name().toUtf8().constData());
0037         }
0038         break;
0039     }
0040     case AbstractProjectItem::ClipItem: {
0041         Q_ASSERT(m_allClips.count(id) == 0);
0042         auto clip = std::static_pointer_cast<ProjectClip>(binElem);
0043         if (clip->isValid()) {
0044             if (clip->clipType() == ClipType::Timeline) {
0045                 const QUuid uuid = clip->getSequenceUuid();
0046                 m_sequenceClips.insert(uuid, id);
0047                 m_binPlaylist->append(clip->originalProducer()->parent());
0048             } else {
0049                 m_binPlaylist->append(*clip->originalProducer().get());
0050             }
0051         } else {
0052             // if clip is not loaded yet, we insert a dummy producer
0053             Mlt::Producer dummy(pCore->getProjectProfile(), "color", "blue");
0054             dummy.set("kdenlive:id", id.toUtf8().constData());
0055             m_binPlaylist->append(dummy);
0056         }
0057         m_allClips.insert(id);
0058         connect(clip.get(), &ProjectClip::producerChanged, this, &BinPlaylist::changeProducer);
0059         break;
0060     }
0061     default:
0062         break;
0063     }
0064 }
0065 
0066 const QString BinPlaylist::getSequenceId(const QUuid &uuid)
0067 {
0068     if (m_sequenceClips.contains(uuid)) {
0069         return m_sequenceClips.value(uuid);
0070     }
0071     return QString();
0072 }
0073 
0074 bool BinPlaylist::hasSequenceId(const QUuid &uuid) const
0075 {
0076     return m_sequenceClips.contains(uuid);
0077 }
0078 
0079 QMap<QUuid, QString> BinPlaylist::getAllSequenceClips() const
0080 {
0081     return m_sequenceClips;
0082 }
0083 
0084 void BinPlaylist::manageBinItemDeletion(AbstractProjectItem *binElem)
0085 {
0086     QString id = binElem->clipId();
0087     switch (binElem->itemType()) {
0088     case AbstractProjectItem::FolderItem: {
0089         // When a folder is removed, we clear the path info
0090         if (!binElem->lastParentId().isEmpty()) {
0091             QString propertyName = "kdenlive:folder." + binElem->lastParentId() + QLatin1Char('.') + binElem->clipId();
0092             m_binPlaylist->set(propertyName.toUtf8().constData(), nullptr);
0093         }
0094         break;
0095     }
0096     case AbstractProjectItem::ClipItem: {
0097         Q_ASSERT(m_allClips.count(id) > 0);
0098         m_allClips.erase(id);
0099         removeBinClip(id);
0100         break;
0101     }
0102     default:
0103         break;
0104     }
0105 }
0106 
0107 void BinPlaylist::removeBinClip(const QString &id)
0108 {
0109     // we iterate on the clips of the timeline to find the correct one
0110     bool ok = false;
0111     int size = m_binPlaylist->count();
0112     for (int i = 0; !ok && i < size; i++) {
0113         QScopedPointer<Mlt::Producer> prod(m_binPlaylist->get_clip(i));
0114         QString prodId(prod->parent().get("kdenlive:id"));
0115         if (prodId == id) {
0116             m_binPlaylist->remove(i);
0117             ok = true;
0118         }
0119     }
0120     Q_ASSERT(ok);
0121 }
0122 
0123 void BinPlaylist::changeProducer(const QString &id, Mlt::Producer producer)
0124 {
0125     Q_ASSERT(m_allClips.count(id) > 0);
0126     removeBinClip(id);
0127     m_binPlaylist->append(producer);
0128 }
0129 
0130 void BinPlaylist::setRetainIn(Mlt::Tractor *modelTractor)
0131 {
0132     QString retain = QStringLiteral("xml_retain %1").arg(binPlaylistId);
0133     modelTractor->set(retain.toUtf8().constData(), m_binPlaylist->get_service(), 0);
0134 }
0135 
0136 void BinPlaylist::saveDocumentProperties(const QMap<QString, QString> &props, const QMap<QString, QString> &metadata)
0137 {
0138     // Clear previous properties
0139     Mlt::Properties playlistProps(m_binPlaylist->get_properties());
0140     Mlt::Properties docProperties;
0141     docProperties.pass_values(playlistProps, "kdenlive:docproperties.");
0142     for (int i = 0; i < docProperties.count(); i++) {
0143         QString propName = QStringLiteral("kdenlive:docproperties.%1").arg(docProperties.get_name(i));
0144         playlistProps.set(propName.toUtf8().constData(), nullptr);
0145     }
0146 
0147     // Clear previous metadata
0148     Mlt::Properties docMetadata;
0149     docMetadata.pass_values(playlistProps, "kdenlive:docmetadata.");
0150     for (int i = 0; i < docMetadata.count(); i++) {
0151         QString propName = QStringLiteral("kdenlive:docmetadata.%1").arg(docMetadata.get_name(i));
0152         playlistProps.set(propName.toUtf8().constData(), nullptr);
0153     }
0154     QMapIterator<QString, QString> i(props);
0155     while (i.hasNext()) {
0156         i.next();
0157         playlistProps.set(("kdenlive:docproperties." + i.key()).toUtf8().constData(), i.value().toUtf8().constData());
0158     }
0159 
0160     QMapIterator<QString, QString> j(metadata);
0161     while (j.hasNext()) {
0162         j.next();
0163         playlistProps.set(("kdenlive:docmetadata." + j.key()).toUtf8().constData(), j.value().toUtf8().constData());
0164     }
0165 }
0166 
0167 void BinPlaylist::saveProperty(const QString &name, const QString &value)
0168 {
0169     m_binPlaylist->set(name.toUtf8().constData(), value.toUtf8().constData());
0170 }
0171 
0172 QMap<QString, QString> BinPlaylist::getProxies(const QString &root)
0173 {
0174     QMap<QString, QString> proxies;
0175     int size = m_binPlaylist->count();
0176     for (int i = 0; i < size; i++) {
0177         QScopedPointer<Mlt::Producer> prod(m_binPlaylist->get_clip(i));
0178         if (!prod->is_valid() || prod->is_blank()) {
0179             continue;
0180         }
0181         QString proxy = prod->parent().get("kdenlive:proxy");
0182         if (proxy.length() > 2) {
0183             if (QFileInfo(proxy).isRelative()) {
0184                 proxy.prepend(root);
0185             }
0186             QString sourceUrl(prod->parent().get("kdenlive:originalurl"));
0187             if (QFileInfo(sourceUrl).isRelative()) {
0188                 sourceUrl.prepend(root);
0189             }
0190             proxies.insert(proxy, sourceUrl);
0191         }
0192     }
0193     return proxies;
0194 }
0195 
0196 int BinPlaylist::count() const
0197 {
0198     return m_binPlaylist->count();
0199 }
0200 
0201 void BinPlaylist::manageBinFolderRename(const std::shared_ptr<AbstractProjectItem> &binElem)
0202 {
0203     QString id = binElem->clipId();
0204     if (binElem->itemType() != AbstractProjectItem::FolderItem) {
0205         qDebug() << "// ITEM IS NOT A FOLDER; ABORT RENAME";
0206     }
0207     // When a folder is inserted, we have to store its path into the properties
0208     if (binElem->parent()) {
0209         QString propertyName = "kdenlive:folder." + binElem->parent()->clipId() + QLatin1Char('.') + id;
0210         m_binPlaylist->set(propertyName.toUtf8().constData(), binElem->name().toUtf8().constData());
0211     }
0212 }
0213 
0214 const QStringList BinPlaylist::getAllMltIds()
0215 {
0216     QStringList allIds;
0217     int size = m_binPlaylist->count();
0218     for (int i = 0; i < size; i++) {
0219         QScopedPointer<Mlt::Producer> prod(m_binPlaylist->get_clip(i));
0220         allIds << QString(prod->parent().get("id"));
0221     }
0222     return allIds;
0223 }