summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <jb@kdenlive.org>2016-09-27 21:28:23 (GMT)
committerJean-Baptiste Mardelle <jb@kdenlive.org>2016-09-27 21:28:23 (GMT)
commit380e508f3e5712b75aebc22ae8dceb92efcf3a9f (patch)
tree775af0b0d439763d9e7153fc095cc8ab2adaecee
parente6561652db31de58ea4570da0edb4af3e7a02379 (diff)
Fix duplicate producers created on library import, patch by Harald Albrecht
REVIEW: 129034
-rw-r--r--src/bin/bin.cpp51
-rw-r--r--src/timeline/customtrackview.cpp58
2 files changed, 79 insertions, 30 deletions
diff --git a/src/bin/bin.cpp b/src/bin/bin.cpp
index 4dd3b5c..b8d744a 100644
--- a/src/bin/bin.cpp
+++ b/src/bin/bin.cpp
@@ -64,6 +64,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QDebug>
#include <QtConcurrent>
#include <QUndoCommand>
+#include <QCryptographicHash>
MyListView::MyListView(QWidget * parent) : QListView(parent)
@@ -2547,7 +2548,12 @@ void Bin::slotExpandUrl(ItemInfo info, QUrl url, QUndoCommand *command)
delete command;
return;
}
+ // Maps playlist producer IDs to (project) bin producer IDs.
QMap <QString, QString> idMap;
+ // Maps hash IDs to (project) first playlist producer instance ID. This is
+ // necessary to detect duplicate producer serializations produced by MLT.
+ // This covers, for instance, images and titles.
+ QMap <QString, QString> hashToIdMap;
QDir mltRoot(doc.documentElement().attribute(QStringLiteral("root")));
for (int i = 0; i < producers.count(); i++) {
QDomElement prod = producers.at(i).toElement();
@@ -2557,14 +2563,57 @@ void Bin::slotExpandUrl(ItemInfo info, QUrl url, QUndoCommand *command)
// slowmotion producer
if (originalId.contains(QLatin1Char(':'))) originalId = originalId.section(QLatin1Char(':'), 1, 1);
+ // We already have seen and mapped this producer.
if (idMap.contains(originalId)) continue;
+
+ // Check for duplicate producers, based on hash value of producer.
+ // Be careful as to the kdenlive:file_hash! It is not unique for
+ // title clips, nor color clips. Also not sure about image sequences.
+ // So we use mlt service-specific hashes to identify duplicate producers.
+ QString hash;
+ QString mltService = EffectsList::property(prod, QStringLiteral("mlt_service"));
+ if (mltService == QLatin1String("pixbuf")
+ || mltService == QLatin1String("kdenlivetitle")
+ || mltService == QLatin1String("color")
+ || mltService == QLatin1String("colour")) {
+ hash = mltService + QStringLiteral(":")
+ + EffectsList::property(prod, QStringLiteral("kdenlive:clipname")) + QStringLiteral(":")
+ + EffectsList::property(prod, QStringLiteral("kdenlive:folderid")) + QStringLiteral(":");
+ if (mltService == QLatin1String("kdenlivetitle")) {
+ // Calculate hash based on title contents.
+ hash.append(QString(QCryptographicHash::hash(EffectsList::property(prod, QStringLiteral("xmldata")).toUtf8(),
+ QCryptographicHash::Md5
+ ).toHex()));
+ } else if (mltService == QLatin1String("pixbuf")
+ || mltService == QLatin1String("color")
+ || mltService == QLatin1String("colour")) {
+ hash.append(EffectsList::property(prod, QStringLiteral("resource")));
+ }
+
+ QString singletonId = hashToIdMap.value(hash, QString());
+ if (singletonId.length()) {
+ // map duplicate producer ID to single bin clip producer ID.
+ qDebug() << "found duplicate producer:" << hash << ", reusing newID:" << singletonId;
+ idMap.insert(originalId, singletonId);
+ continue;
+ }
+ }
+
+ // First occurence of a producer, so allocate new bin clip producer ID.
QString newId = QString::number(getFreeClipId());
idMap.insert(originalId, newId);
qDebug() << "originalId: " << originalId << ", newId: " << newId;
+
+ // Ensure to register new bin clip producer ID in hash hashmap for
+ // those clips that MLT likes to serialize multiple times. This is
+ // indicated by having a hash "value" unqual "". See also above.
+ if (hash.length()) {
+ hashToIdMap.insert(hash, newId);
+ }
+
// Add clip
QDomElement clone = prod.cloneNode(true).toElement();
EffectsList::setProperty(clone, QStringLiteral("kdenlive:folderid"), folderId);
- QString mltService = EffectsList::property(clone, QStringLiteral("mlt_service"));
// Do we have a producer that uses a resource property that contains a path?
if (mltService == QLatin1String("avformat-novalidate") // av clip
|| mltService == QLatin1String("avformat") // av clip
diff --git a/src/timeline/customtrackview.cpp b/src/timeline/customtrackview.cpp
index b5b2bec..f538195 100644
--- a/src/timeline/customtrackview.cpp
+++ b/src/timeline/customtrackview.cpp
@@ -8194,27 +8194,28 @@ bool CustomTrackView::hasSelection() const
void CustomTrackView::exportTimelineSelection(QString path)
{
if (!m_selectionGroup && !m_dragItem) {
- qDebug()<<"/// ARGH, NO SELECTION GRP";
- return;
+ qDebug()<<"/// ARGH, NO SELECTION GRP";
+ emit displayMessage(i18n("No clips and transitions selected in timeline for exporting."), ErrorMessage);
+ return;
}
if (path.isEmpty()) {
QString clipFolder = KRecentDirs::dir(QStringLiteral(":KdenliveClipFolder"));
if (clipFolder.isEmpty()) {
clipFolder = QDir::homePath();
}
- path = QFileDialog::getSaveFileName(this, i18n("Save Zone"), clipFolder, i18n("MLT playlist (*.mlt)"));
+ path = QFileDialog::getSaveFileName(this, i18n("Save Timeline Selection"), clipFolder, i18n("MLT playlist (*.mlt)"));
if (path.isEmpty()) return;
}
QList<QGraphicsItem *> children;
QRectF bounding;
if (m_selectionGroup) {
- children = m_selectionGroup->childItems();
- bounding = m_selectionGroup->sceneBoundingRect();
+ children = m_selectionGroup->childItems();
+ bounding = m_selectionGroup->sceneBoundingRect();
}
else {
- // only one clip selected
- children << m_dragItem;
- bounding = m_dragItem->sceneBoundingRect();
+ // only one clip selected
+ children << m_dragItem;
+ bounding = m_dragItem->sceneBoundingRect();
}
int firstTrack = getTrackFromPos(bounding.bottom());
int lastTrack = getTrackFromPos(bounding.top());
@@ -8222,34 +8223,33 @@ void CustomTrackView::exportTimelineSelection(QString path)
Mlt::Tractor *newTractor = new Mlt::Tractor(*(m_document->renderer()->getProducer()->profile()));
Mlt::Field *field = newTractor->field();
for (int i = firstTrack; i <= lastTrack; i++) {
- QScopedPointer<Mlt::Playlist> newTrackPlaylist(new Mlt::Playlist(*newTractor->profile()));
- newTractor->set_track(*newTrackPlaylist, i - firstTrack);
+ QScopedPointer<Mlt::Playlist> newTrackPlaylist(new Mlt::Playlist(*newTractor->profile()));
+ newTractor->set_track(*newTrackPlaylist, i - firstTrack);
}
int startOffest = m_projectDuration;
// Find first frame of selection
for (int i = 0; i < children.count(); ++i) {
- QGraphicsItem *item = children.at(i);
- if (item->type() != TransitionWidget && item->type() != AVWidget) {
- continue;
- }
- AbstractClipItem *it = static_cast<AbstractClipItem *>(item);
- if (!it) continue;
- int pos = it->startPos().frames(m_document->fps());
- if (pos < startOffest) startOffest = pos;
+ QGraphicsItem *item = children.at(i);
+ if (item->type() != TransitionWidget && item->type() != AVWidget) {
+ continue;
+ }
+ AbstractClipItem *it = static_cast<AbstractClipItem *>(item);
+ if (!it) continue;
+ int pos = it->startPos().frames(m_document->fps());
+ if (pos < startOffest) startOffest = pos;
}
for (int i = 0; i < children.count(); ++i) {
- QGraphicsItem *item = children.at(i);
- if (item->type() == AVWidget) {
+ QGraphicsItem *item = children.at(i);
+ if (item->type() == AVWidget) {
ClipItem *clip = static_cast<ClipItem*>(item);
- int track = clip->track() - firstTrack;
- m_timeline->duplicateClipOnPlaylist(clip->track(), clip->startPos().seconds(), startOffest, newTractor->track(track));
- }
- else if (item->type() == TransitionWidget) {
- Transition *tr = static_cast<Transition*>(item);
- int a_track = qBound(0, tr->transitionEndTrack() - firstTrack, lastTrack - firstTrack + 1);
- int b_track = qBound(0, tr->track() - firstTrack, lastTrack - firstTrack + 1);;
- m_timeline->transitionHandler->duplicateTransitionOnPlaylist(tr->startPos().frames(m_document->fps()) - startOffest, tr->endPos().frames(m_document->fps()) - startOffest, tr->transitionTag(), tr->toXML(), a_track, b_track, field);
- }
+ int track = clip->track() - firstTrack;
+ m_timeline->duplicateClipOnPlaylist(clip->track(), clip->startPos().seconds(), startOffest, newTractor->track(track));
+ } else if (item->type() == TransitionWidget) {
+ Transition *tr = static_cast<Transition*>(item);
+ int a_track = qBound(0, tr->transitionEndTrack() - firstTrack, lastTrack - firstTrack + 1);
+ int b_track = qBound(0, tr->track() - firstTrack, lastTrack - firstTrack + 1);;
+ m_timeline->transitionHandler->duplicateTransitionOnPlaylist(tr->startPos().frames(m_document->fps()) - startOffest, tr->endPos().frames(m_document->fps()) - startOffest, tr->transitionTag(), tr->toXML(), a_track, b_track, field);
+ }
}
Mlt::Consumer xmlConsumer(*newTractor->profile(), ("xml:" + path).toUtf8().constData());
xmlConsumer.set("terminate_on_pause", 1);