X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fdocclipbase.cpp;h=938cdb7eac00f470c70ddaef524eac27a1cb3572;hb=77c63bf4b2b052e909b1e378fd305252557cf653;hp=9b55d6b16ab75209a302b3bd320909807d055fb9;hpb=67c082885c7a6b6cd428ba8568bf5ee8b2b357a2;p=kdenlive diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 9b55d6b1..938cdb7e 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -32,16 +32,19 @@ #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(), @@ -61,10 +64,16 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin for (int i = 0; i < attributes.count(); i++) { QString name = attributes.item(i).nodeName(); if (name.startsWith("meta.attr.")) { - m_metadata.insert(name.section('.', 2, 3), attributes.item(i).nodeValue()); + m_metadata.insert(name.section('.', 2), QStringList() << attributes.item(i).nodeValue()); } else m_properties.insert(name, attributes.item(i).nodeValue()); } - + QDomNodeList metas = xml.elementsByTagName("metaproperty"); + for (int i = 0; i < metas.count(); i++) { + QDomElement e = metas.item(i).toElement(); + if (!e.isNull()) { + m_metadata.insert(e.attribute("name").section('.', 2), QStringList() << e.firstChild().nodeValue() << e.attribute("tool")); + } + } if (xml.hasAttribute("cutzones")) { QStringList cuts = xml.attribute("cutzones").split(';', QString::SkipEmptyParts); for (int i = 0; i < cuts.count(); i++) { @@ -73,6 +82,12 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin } } + 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()); @@ -81,7 +96,7 @@ DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QStrin } else { int out = xml.attribute("out").toInt(); int in = xml.attribute("in").toInt(); - setDuration(GenTime(out - in, KdenliveSettings::project_fps())); + if (out > in) setDuration(GenTime(out - in + 1, KdenliveSettings::project_fps())); } if (!m_properties.contains("name")) m_properties.insert("name", url.fileName()); @@ -131,7 +146,7 @@ bool DocClipBase::hasAudioThumb() const void DocClipBase::slotClearAudioCache() { - m_audioFrameCache.clear(); + audioFrameCache.clear(); m_audioThumbCreated = false; } @@ -246,6 +261,21 @@ QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const if (hideTemporaryProperties && i.key().startsWith('_')) continue; if (!i.value().isEmpty()) clip.setAttribute(i.key(), i.value()); } + + QMapIterator j(m_metadata); + // Metadata name can have special chars so we cannot pass it as simple attribute + while (j.hasNext()) { + j.next(); + if (!j.value().isEmpty()) { + QDomElement property = doc.createElement("metaproperty"); + property.setAttribute("name", "meta.attr." + j.key()); + QStringList values = j.value(); + QDomText value = doc.createTextNode(values.at(0)); + if (values.count() > 1) property.setAttribute("tool", values.at(1)); + property.appendChild(value); + clip.appendChild(property); + } + } doc.appendChild(clip); if (!m_cutZones.isEmpty()) { QStringList cuts; @@ -255,10 +285,71 @@ QDomElement DocClipBase::toXML(bool hideTemporaryProperties) 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(); } +const QString DocClipBase::shortInfo() const +{ + + QString info; + if (m_clipType == AV || m_clipType == VIDEO || m_clipType == IMAGE || m_clipType == PLAYLIST) { + info = m_properties.value("frame_size") + " "; + if (m_properties.contains("fps")) { + info.append(i18n("%1 fps", m_properties.value("fps").left(5))); + } + if (!info.simplified().isEmpty()) info.prepend(" - "); + } + else if (m_clipType == AUDIO) { + info = " - " + m_properties.value("frequency") + i18n("Hz"); + } + QString tip = ""; + switch (m_clipType) { + case AUDIO: + tip.append(i18n("Audio clip") + "" + info + "
" + fileURL().path()); + break; + case VIDEO: + tip.append(i18n("Mute video clip") + "" + info + "
" + fileURL().path()); + break; + case AV: + tip.append(i18n("Video clip") + "" + info + "
" + fileURL().path()); + break; + case COLOR: + tip.append(i18n("Color clip")); + break; + case IMAGE: + tip.append(i18n("Image clip") + "" + info + "
" + fileURL().path()); + break; + case TEXT: + if (!fileURL().isEmpty() && getProperty("xmldata").isEmpty()) tip.append(i18n("Template text clip") + "
" + fileURL().path()); + else tip.append(i18n("Text clip") + "
" + fileURL().path()); + break; + case SLIDESHOW: + tip.append(i18n("Slideshow clip") + "
" + fileURL().directory()); + break; + case VIRTUAL: + tip.append(i18n("Virtual clip")); + break; + case PLAYLIST: + tip.append(i18n("Playlist clip") + "" + info + "
" + fileURL().path()); + break; + default: + tip.append(i18n("Unknown clip")); + break; + } + return tip; +} + void DocClipBase::setAudioThumbCreated(bool isDone) { @@ -268,7 +359,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(); } @@ -276,7 +367,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()); } @@ -290,22 +380,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) @@ -378,10 +467,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(); @@ -390,6 +478,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(); @@ -672,6 +771,9 @@ 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; } @@ -946,7 +1048,7 @@ void DocClipBase::setProperties(QMap properties) if (refreshProducer) slotRefreshProducer(); } -void DocClipBase::setMetadata(QMap properties) +void DocClipBase::setMetadata(QMap properties, QString tool) { QMapIterator i(properties); while (i.hasNext()) { @@ -954,12 +1056,12 @@ void DocClipBase::setMetadata(QMap properties) if (i.value().isEmpty() && m_metadata.contains(i.key())) { m_metadata.remove(i.key()); } else { - m_metadata.insert(i.key(), i.value()); + m_metadata.insert(i.key(), QStringList() << i.value() << tool); } } } -QMap DocClipBase::metadata() const +QMap DocClipBase::metadata() const { return m_metadata; } @@ -1054,8 +1156,10 @@ void DocClipBase::setProperty(const QString &key, const QString &value) if (key == "resource") { getFileHash(value); if (m_thumbProd) m_thumbProd->updateClipUrl(KUrl(value), m_properties.value("file_hash")); - } else if (key == "out") setDuration(GenTime(value.toInt(), KdenliveSettings::project_fps())); //else if (key == "transparency") m_clipProducer->set("transparency", value.toInt()); + } else if (key == "out") { + setDuration(GenTime(value.toInt() + 1, KdenliveSettings::project_fps())); + } else if (key == "colour") { setProducerProperty("colour", value.toUtf8().data()); } else if (key == "templatetext") { @@ -1247,4 +1351,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(NULL, 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; +}