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 }