X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fdocclipbase.cpp;h=daeb6a57d8a313489b683941fe530d637737bf6b;hb=5eaf1ee0d7dd737ab4bd544e2c4f7467a2e0ea9a;hp=96241c952f51b025845b259b69cf9693e69c693f;hpb=7d708fd156c646b36c91cffaed60e5cf777f95d9;p=kdenlive diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 96241c95..daeb6a57 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -32,20 +32,23 @@ #include #include +#include #include #include #include #include +#include DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) : QObject(), - m_audioFrameCache(), + lastSeekPosition(0), + audioFrameCache(), m_refcount(0), m_baseTrackProducers(), + m_videoTrackProducers(), m_audioTrackProducers(), - m_videoOnlyProducer(NULL), m_snapMarkers(QList < CommentedTime >()), m_duration(), m_thumbProd(NULL), @@ -66,13 +69,19 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin } if (xml.hasAttribute("cutzones")) { - QStringList cuts = xml.attribute("cutzones").split(";", QString::SkipEmptyParts); + QStringList cuts = xml.attribute("cutzones").split(';', QString::SkipEmptyParts); for (int i = 0; i < cuts.count(); i++) { QString z = cuts.at(i); addCutZone(z.section('-', 0, 0).toInt(), z.section('-', 1, 1).toInt(), z.section('-', 2, 2)); } } + if (xml.hasAttribute("analysisdata")) { + QStringList adata = xml.attribute("analysisdata").split('#', QString::SkipEmptyParts); + for (int i = 0; i < adata.count(); i++) + m_analysisdata.insert(adata.at(i).section('?', 0, 0), adata.at(i).section('?', 1, 1)); + } + KUrl url = KUrl(xml.attribute("resource")); if (!m_properties.contains("file_hash") && !url.isEmpty()) getFileHash(url.path()); @@ -106,8 +115,8 @@ DocClipBase::~DocClipBase() m_baseTrackProducers.clear(); qDeleteAll(m_audioTrackProducers); m_audioTrackProducers.clear(); - delete m_videoOnlyProducer; - m_videoOnlyProducer = NULL; + qDeleteAll(m_videoTrackProducers); + m_videoTrackProducers.clear(); } void DocClipBase::setZone(QPoint zone) @@ -131,7 +140,7 @@ bool DocClipBase::hasAudioThumb() const void DocClipBase::slotClearAudioCache() { - m_audioFrameCache.clear(); + audioFrameCache.clear(); m_audioThumbCreated = false; } @@ -235,7 +244,7 @@ qulonglong DocClipBase::fileSize() const } // virtual -QDomElement DocClipBase::toXML() const +QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const { QDomDocument doc; QDomElement clip = doc.createElement("producer"); @@ -243,6 +252,7 @@ QDomElement DocClipBase::toXML() const QMapIterator i(m_properties); while (i.hasNext()) { i.next(); + if (hideTemporaryProperties && i.key().startsWith('_')) continue; if (!i.value().isEmpty()) clip.setAttribute(i.key(), i.value()); } doc.appendChild(clip); @@ -254,6 +264,16 @@ QDomElement DocClipBase::toXML() const } clip.setAttribute("cutzones", cuts.join(";")); } + QString adata; + if (!m_analysisdata.isEmpty()) { + QMapIterator i(m_analysisdata); + while (i.hasNext()) { + i.next(); + //WARNING: a ? and # separator is not a good idea + adata.append(i.key() + "?" + i.value() + "#"); + } + } + clip.setAttribute("analysisdata", adata); //kDebug() << "/// CLIP XML: " << doc.toString(); return doc.documentElement(); } @@ -267,7 +287,7 @@ void DocClipBase::setAudioThumbCreated(bool isDone) void DocClipBase::updateAudioThumbnail(const audioByteArray& data) { //kDebug() << "CLIPBASE RECIEDVED AUDIO DATA*********************************************"; - m_audioFrameCache = data; + audioFrameCache = data; m_audioThumbCreated = true; emit gotAudioData(); } @@ -275,7 +295,6 @@ void DocClipBase::updateAudioThumbnail(const audioByteArray& data) QList < GenTime > DocClipBase::snapMarkers() const { QList < GenTime > markers; - for (int count = 0; count < m_snapMarkers.count(); ++count) { markers.append(m_snapMarkers.at(count).time()); } @@ -289,22 +308,21 @@ QList < CommentedTime > DocClipBase::commentedSnapMarkers() const } -void DocClipBase::addSnapMarker(const GenTime & time, QString comment) +void DocClipBase::addSnapMarker(const CommentedTime marker) { QList < CommentedTime >::Iterator it = m_snapMarkers.begin(); for (it = m_snapMarkers.begin(); it != m_snapMarkers.end(); ++it) { - if ((*it).time() >= time) + if ((*it).time() >= marker.time()) break; } - if ((it != m_snapMarkers.end()) && ((*it).time() == time)) { - (*it).setComment(comment); + if ((it != m_snapMarkers.end()) && ((*it).time() == marker.time())) { + (*it).setComment(marker.comment()); + (*it).setMarkerType(marker.markerType()); //kError() << "trying to add Snap Marker that already exists, this will cause inconsistancies with undo/redo"; } else { - CommentedTime t(time, comment); - m_snapMarkers.insert(it, t); + m_snapMarkers.insert(it, marker); } - } void DocClipBase::editSnapMarker(const GenTime & time, QString comment) @@ -377,10 +395,9 @@ GenTime DocClipBase::findNextSnapMarker(const GenTime & currTime) return duration(); } -QString DocClipBase::markerComment(GenTime t) +QString DocClipBase::markerComment(GenTime t) const { - QList < CommentedTime >::Iterator itt = m_snapMarkers.begin(); - + QList < CommentedTime >::ConstIterator itt = m_snapMarkers.begin(); while (itt != m_snapMarkers.end()) { if ((*itt).time() == t) return (*itt).comment(); @@ -389,6 +406,17 @@ QString DocClipBase::markerComment(GenTime t) return QString(); } +CommentedTime DocClipBase::markerAt(GenTime t) const +{ + QList < CommentedTime >::ConstIterator itt = m_snapMarkers.begin(); + while (itt != m_snapMarkers.end()) { + if ((*itt).time() == t) + return (*itt); + ++itt; + } + return CommentedTime(); +} + void DocClipBase::clearThumbProducer() { if (m_thumbProd) m_thumbProd->clearProducer(); @@ -404,24 +432,26 @@ void DocClipBase::deleteProducers() { if (m_thumbProd) m_thumbProd->clearProducer(); - if (numReferences() > 0) { + if (numReferences() > 0 && (!m_baseTrackProducers.isEmpty() || !m_videoTrackProducers.isEmpty() || !m_audioTrackProducers.isEmpty())) { // Clip is used in timeline, delay producers deletion - if (m_videoOnlyProducer) m_toDeleteProducers.append(m_videoOnlyProducer); for (int i = 0; i < m_baseTrackProducers.count(); i++) { m_toDeleteProducers.append(m_baseTrackProducers.at(i)); } + for (int i = 0; i < m_videoTrackProducers.count(); i++) { + m_toDeleteProducers.append(m_videoTrackProducers.at(i)); + } for (int i = 0; i < m_audioTrackProducers.count(); i++) { m_toDeleteProducers.append(m_audioTrackProducers.at(i)); } } else { - delete m_videoOnlyProducer; qDeleteAll(m_baseTrackProducers); + qDeleteAll(m_videoTrackProducers); qDeleteAll(m_audioTrackProducers); m_replaceMutex.unlock(); } - m_videoOnlyProducer = NULL; m_baseTrackProducers.clear(); + m_videoTrackProducers.clear(); m_audioTrackProducers.clear(); } @@ -441,9 +471,11 @@ void DocClipBase::cleanupProducers() } }*/ - qDeleteAll(m_toDeleteProducers); - m_toDeleteProducers.clear(); - m_replaceMutex.unlock(); + if (!isClean()) { + qDeleteAll(m_toDeleteProducers); + m_toDeleteProducers.clear(); + m_replaceMutex.unlock(); + } } bool DocClipBase::isClean() const @@ -498,8 +530,16 @@ void DocClipBase::setProducer(Mlt::Producer *producer, bool reset, bool readProp else delete producer; return; } else if (id.endsWith("video")) { - if (m_videoOnlyProducer == NULL) { - m_videoOnlyProducer = producer; + int pos = 0; + // Keep compatibility with older projects where video only producers were not track specific + if (id.contains('_')) pos = id.section('_', 0, 0).toInt(); + if (pos >= m_videoTrackProducers.count()) { + while (m_videoTrackProducers.count() - 1 < pos) { + m_videoTrackProducers.append(NULL); + } + } + if (m_videoTrackProducers.at(pos) == NULL) { + m_videoTrackProducers[pos] = producer; updated = true; } else delete producer; @@ -595,18 +635,33 @@ void DocClipBase::adjustProducerProperties(Mlt::Producer *prod, const QString &i } -Mlt::Producer *DocClipBase::videoProducer() +Mlt::Producer *DocClipBase::videoProducer(int track) { QMutexLocker locker(&m_producerMutex); - if (m_videoOnlyProducer == NULL) { + if (m_videoTrackProducers.count() <= track) { + while (m_videoTrackProducers.count() - 1 < track) { + m_videoTrackProducers.append(NULL); + } + } + if (m_videoTrackProducers.at(track) == NULL) { int i; - for (i = 0; i < m_baseTrackProducers.count(); i++) - if (m_baseTrackProducers.at(i) != NULL) break; - if (i >= m_baseTrackProducers.count()) return NULL; - m_videoOnlyProducer = cloneProducer(m_baseTrackProducers.at(i)); - adjustProducerProperties(m_videoOnlyProducer, QString(getId() + "_video"), true, false); + for (i = 0; i < m_videoTrackProducers.count(); i++) + if (m_videoTrackProducers.at(i) != NULL) break; + Mlt::Producer *base; + if (i >= m_videoTrackProducers.count()) { + // Could not find a valid producer for that clip + locker.unlock(); + base = getProducer(); + if (base == NULL) { + return NULL; + } + locker.relock(); + } + else base = m_videoTrackProducers.at(i); + m_videoTrackProducers[track] = cloneProducer(base); + adjustProducerProperties(m_videoTrackProducers.at(track), QString(getId() + '_' + QString::number(track) + "_video"), true, false); } - return m_videoOnlyProducer; + return m_videoTrackProducers.at(track); } Mlt::Producer *DocClipBase::getCloneProducer() @@ -644,10 +699,14 @@ Mlt::Producer *DocClipBase::getCloneProducer() if (m_properties.contains("duration")) prod->set("length", m_properties.value("duration").toInt()); if (m_properties.contains("out"))prod->set("out", m_properties.value("out").toInt()); } + if (m_clipType == AUDIO) { + prod->set("_audioclip", 1); + } } return prod; } + Mlt::Producer *DocClipBase::getProducer(int track) { QMutexLocker locker(&m_producerMutex); @@ -688,6 +747,10 @@ Mlt::Producer *DocClipBase::cloneProducer(Mlt::Producer *source) { Mlt::Producer *result = NULL; QString url = QString::fromUtf8(source->get("resource")); + if (url == "" || url == "" || url == "") { + // Xml producer sometimes loses the correct url + url = m_properties.value("resource"); + } if (m_clipType == SLIDESHOW || KIO::NetAccess::exists(KUrl(url), KIO::NetAccess::SourceSide, 0)) { result = new Mlt::Producer(*(source->profile()), url.toUtf8().constData()); } @@ -1214,4 +1277,60 @@ QImage DocClipBase::extractImage(int frame, int width, int height) return m_thumbProd->extractImage(frame, width, height); } +void DocClipBase::setAnalysisData(const QString &name, const QString &data, int offset) +{ + if (data.isEmpty()) m_analysisdata.remove(name); + else { + if (m_analysisdata.contains(name)) { + if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("Clip already contains analysis data %1", name), QString(), KGuiItem(i18n("Merge")), KGuiItem(i18n("Add"))) == KMessageBox::Yes) { + // Merge data + Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile(); + Mlt::Geometry geometry(m_analysisdata.value(name).toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::Geometry newGeometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::GeometryItem item; + int pos = 0; + while (!newGeometry.next_key(&item, pos)) { + pos = item.frame(); + item.frame(pos + offset); + pos++; + geometry.insert(item); + } + m_analysisdata.insert(name, geometry.serialise()); + } + else { + // Add data with another name + int i = 1; + QString newname = name + " " + QString::number(i); + while (m_analysisdata.contains(newname)) { + i++; + newname = name + " " + QString::number(i); + } + m_analysisdata.insert(newname, geometryWithOffset(data, offset)); + } + } + else m_analysisdata.insert(name, geometryWithOffset(data, offset)); + } +} + +const QString DocClipBase::geometryWithOffset(QString data, int offset) +{ + if (offset == 0) return data; + Mlt::Profile *profile = m_baseTrackProducers.at(0)->profile(); + Mlt::Geometry geometry(data.toUtf8().data(), m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::Geometry newgeometry("", m_properties.value("duration").toInt(), profile->width(), profile->height()); + Mlt::GeometryItem item; + int pos = 0; + while (!geometry.next_key(&item, pos)) { + pos = item.frame(); + item.frame(pos + offset); + pos++; + newgeometry.insert(item); + } + return newgeometry.serialise(); +} + +QMap DocClipBase::analysisData() const +{ + return m_analysisdata; +}