Commit 380e508f authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Fix duplicate producers created on library import, patch by Harald Albrecht

REVIEW: 129034
parent e6561652
......@@ -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
......
......@@ -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);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment