X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fdocclipbase.cpp;h=d278eeca429e9307f13c6da6feafbe9cd5ff052c;hb=e5bed1802f629406c47711f2a6e26f7c0286b11f;hp=68ab905615a158ca3161aaaab618ad7166913b8e;hpb=5a403d4a2689486dbdef95fb4c529a44636e8753;p=kdenlive diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 68ab9056..d278eeca 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -44,11 +44,10 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin m_audioFrameCache(), m_refcount(0), m_baseTrackProducers(), + m_videoTrackProducers(), m_audioTrackProducers(), - m_videoOnlyProducer(NULL), m_snapMarkers(QList < CommentedTime >()), m_duration(), - m_audioTimer(NULL), m_thumbProd(NULL), m_audioThumbCreated(false), m_id(id), @@ -67,13 +66,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()); @@ -88,22 +93,27 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin if (!m_properties.contains("name")) m_properties.insert("name", url.fileName()); m_thumbProd = new KThumb(clipManager, url, m_id, m_properties.value("file_hash")); - if (m_clipType == AV || m_clipType == AUDIO || m_clipType == PLAYLIST) slotCreateAudioTimer(); + + // Setup timer to trigger audio thumbs creation + m_audioTimer.setSingleShot(true); + m_audioTimer.setInterval(800); + connect(&m_audioTimer, SIGNAL(timeout()), m_thumbProd, SLOT(slotCreateAudioThumbs())); + } DocClipBase::~DocClipBase() { + m_audioTimer.stop(); delete m_thumbProd; - if (m_audioTimer) { - m_audioTimer->stop(); - delete m_audioTimer; - } + m_thumbProd = NULL; + qDeleteAll(m_toDeleteProducers); + m_toDeleteProducers.clear(); qDeleteAll(m_baseTrackProducers); 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) @@ -118,22 +128,15 @@ QPoint DocClipBase::zone() const return zone; } -void DocClipBase::slotCreateAudioTimer() -{ - connect(m_thumbProd, SIGNAL(audioThumbReady(const audioByteArray&)), this , SLOT(updateAudioThumbnail(const audioByteArray&))); - m_audioTimer = new QTimer(this); - connect(m_audioTimer, SIGNAL(timeout()), this, SLOT(slotGetAudioThumbs())); -} -void DocClipBase::askForAudioThumbs() +bool DocClipBase::hasAudioThumb() const { - if (m_thumbProd && m_audioTimer) m_thumbProd->askForAudioThumbs(getId()); + if (m_clipType == AUDIO || m_clipType == AV || m_clipType == PLAYLIST) return true; + return false; } void DocClipBase::slotClearAudioCache() { - if (m_thumbProd) m_thumbProd->stopAudioThumbs(); - if (m_audioTimer != NULL) m_audioTimer->stop(); m_audioFrameCache.clear(); m_audioThumbCreated = false; } @@ -163,11 +166,6 @@ const QString &DocClipBase::getId() const return m_id; } -void DocClipBase::setId(const QString &newId) -{ - m_id = newId; -} - const CLIPTYPE & DocClipBase::clipType() const { return m_clipType; @@ -176,10 +174,7 @@ const CLIPTYPE & DocClipBase::clipType() const void DocClipBase::setClipType(CLIPTYPE type) { m_clipType = type; - m_properties.insert("type", QString::number((int) type)); - if (m_thumbProd && m_audioTimer == NULL && (m_clipType == AV || m_clipType == AUDIO || m_clipType == PLAYLIST)) - slotCreateAudioTimer(); } KUrl DocClipBase::fileURL() const @@ -246,7 +241,7 @@ qulonglong DocClipBase::fileSize() const } // virtual -QDomElement DocClipBase::toXML() const +QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const { QDomDocument doc; QDomElement clip = doc.createElement("producer"); @@ -254,6 +249,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); @@ -265,6 +261,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(); } @@ -275,17 +281,6 @@ void DocClipBase::setAudioThumbCreated(bool isDone) m_audioThumbCreated = isDone; } - -void DocClipBase::setThumbnail(const QPixmap & pixmap) -{ - m_thumbnail = pixmap; -} - -const QPixmap & DocClipBase::thumbnail() const -{ - return m_thumbnail; -} - void DocClipBase::updateAudioThumbnail(const audioByteArray& data) { //kDebug() << "CLIPBASE RECIEDVED AUDIO DATA*********************************************"; @@ -311,22 +306,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) @@ -399,10 +393,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(); @@ -411,33 +404,52 @@ 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(); } +void DocClipBase::reloadThumbProducer() +{ + if (m_thumbProd && !m_thumbProd->hasProducer()) + m_thumbProd->setProducer(getProducer()); +} + void DocClipBase::deleteProducers() { - m_thumbProd->clearProducer(); + 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(); } @@ -457,9 +469,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 @@ -494,6 +508,7 @@ void DocClipBase::setProducer(Mlt::Producer *producer, bool reset, bool readProp m_thumbProd->setProducer(producer); } else m_thumbProd->setProducer(producer); + getAudioThumbs(); } bool updated = false; if (id.contains('_')) { @@ -513,8 +528,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; @@ -610,39 +633,78 @@ 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(Mlt::Producer *source) +Mlt::Producer *DocClipBase::getCloneProducer() { - QMutexLocker locker(&m_producerMutex); - if (source == NULL) { - for (int i = 0; i < m_baseTrackProducers.count(); i++) { - if (m_baseTrackProducers.at(i) != NULL) { - source = m_baseTrackProducers.at(i); - break; + Mlt::Producer *source = NULL; + Mlt::Producer *prod = NULL; + if (m_clipType != AUDIO && m_clipType != AV && m_clipType != PLAYLIST) { + source = getProducer(); + if (!source) return NULL; + } + if (m_clipType == COLOR) { + prod = new Mlt::Producer(*(source->profile()), 0, QString("colour:" + QString(source->get("resource"))).toUtf8().constData()); + } else if (m_clipType == TEXT) { + prod = new Mlt::Producer(*(source->profile()), 0, QString("kdenlivetitle:" + QString(source->get("resource"))).toUtf8().constData()); + if (prod && prod->is_valid() && m_properties.contains("xmldata")) + prod->set("xmldata", m_properties.value("xmldata").toUtf8().constData()); + } + if (!prod) { + if (!source) { + QMutexLocker locker(&m_producerMutex); + for (int i = 0; i < m_baseTrackProducers.count(); i++) { + if (m_baseTrackProducers.at(i) != NULL) { + source = m_baseTrackProducers.at(i); + break; + } } + if (!source) return NULL; } + prod = cloneProducer(source); } - if (source) { - Mlt::Producer *prod = cloneProducer(source); - adjustProducerProperties(prod, getId() + "_monitor", false, false); - return prod; + if (prod) { + adjustProducerProperties(prod, getId() + "_", false, false); + if (!m_properties.contains("proxy_out")) { + // Adjust length in case... + 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 NULL; + return prod; } + Mlt::Producer *DocClipBase::getProducer(int track) { QMutexLocker locker(&m_producerMutex); @@ -671,8 +733,9 @@ Mlt::Producer *DocClipBase::getProducer(int track) // Could not find a valid producer for that clip, check in return NULL; } - m_baseTrackProducers[track] = cloneProducer(m_baseTrackProducers.at(i)); - adjustProducerProperties(m_baseTrackProducers.at(track), QString(getId() + '_' + QString::number(track)), false, false); + Mlt::Producer *prod = cloneProducer(m_baseTrackProducers.at(i)); + adjustProducerProperties(prod, QString(getId() + '_' + QString::number(track)), false, false); + m_baseTrackProducers[track] = prod; } return m_baseTrackProducers.at(track); } @@ -682,7 +745,11 @@ Mlt::Producer *DocClipBase::cloneProducer(Mlt::Producer *source) { Mlt::Producer *result = NULL; QString url = QString::fromUtf8(source->get("resource")); - if (KIO::NetAccess::exists(KUrl(url), KIO::NetAccess::SourceSide, 0)) { + 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()); } if (result == NULL || !result->is_valid()) { @@ -1083,20 +1150,24 @@ QMap DocClipBase::properties() const return m_properties; } -bool DocClipBase::slotGetAudioThumbs() +QMap DocClipBase::currentProperties(QMap props) { - if (m_thumbProd == NULL || isPlaceHolder()) return false; - if (!KdenliveSettings::audiothumbnails() || m_audioTimer == NULL) { - if (m_audioTimer != NULL) m_audioTimer->stop(); - return false; + QMap currentProps; + QMap::const_iterator i = props.constBegin(); + while (i != props.constEnd()) { + currentProps.insert(i.key(), m_properties.value(i.key())); + ++i; } + return currentProps; +} + +bool DocClipBase::getAudioThumbs() +{ + if (m_thumbProd == NULL || isPlaceHolder() || !KdenliveSettings::audiothumbnails()) return false; if (m_audioThumbCreated) { - m_audioTimer->stop(); return false; } - m_audioTimer->start(1500); - double lengthInFrames = duration().frames(KdenliveSettings::project_fps()); - m_thumbProd->getAudioThumbs(2, 0, lengthInFrames /*must be number of frames*/, 20); + m_audioTimer.start(); return true; } @@ -1191,18 +1262,27 @@ bool DocClipBase::hasAudioCodec(const QString &codec) const } -void DocClipBase::slotExtractImage(int frame, int frame2) +void DocClipBase::slotExtractImage(QList frames) { if (m_thumbProd == NULL) return; - m_thumbProd->extractImage(frame, frame2); + m_thumbProd->extractImage(frames); } -QPixmap DocClipBase::extractImage(int frame, int width, int height) +QImage DocClipBase::extractImage(int frame, int width, int height) { - if (m_thumbProd == NULL) return QPixmap(width, height); + if (m_thumbProd == NULL) return QImage(); QMutexLocker locker(&m_producerMutex); - QPixmap p = m_thumbProd->extractImage(frame, width, height); - return p; + return m_thumbProd->extractImage(frame, width, height); } +void DocClipBase::setAnalysisData(const QString &name, const QString &data) +{ + if (data.isEmpty()) m_analysisdata.remove(name); + else m_analysisdata.insert(name, data); +} + +QMap DocClipBase::analysisData() const +{ + return m_analysisdata; +}