]> git.sesse.net Git - kdenlive/blobdiff - src/docclipbase.cpp
Fix 1 frame offset in image / color clips, fix changing duration of image/color clips
[kdenlive] / src / docclipbase.cpp
index 693e4ecca2f2829fc62d73add95782907d46fb70..a96f7f28bfe1a29844bbdfaed7d805624ff7c8ae 100644 (file)
 
 #include <KIO/NetAccess>
 #include <KStandardDirs>
+#include <KApplication>
 #include <KDebug>
 
 #include <QCryptographicHash>
 #include <QtConcurrentRun>
 
 #include <cstdio>
+#include <kmessagebox.h>
 
 DocClipBase::DocClipBase(ClipManager *clipManager, QDomElement xml, const QString &id) :
         QObject(),
-        m_audioFrameCache(),
+        lastSeekPosition(0),
+        audioFrameCache(),
         m_refcount(0),
         m_baseTrackProducers(),
         m_videoTrackProducers(),
@@ -73,6 +76,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 +90,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()));
+        setDuration(GenTime(out - in + 1, KdenliveSettings::project_fps()));
     }
 
     if (!m_properties.contains("name")) m_properties.insert("name", url.fileName());
@@ -131,7 +140,7 @@ bool DocClipBase::hasAudioThumb() const
 
 void DocClipBase::slotClearAudioCache()
 {
-    m_audioFrameCache.clear();
+    audioFrameCache.clear();
     m_audioThumbCreated = false;
 }
 
@@ -255,6 +264,16 @@ QDomElement DocClipBase::toXML(bool hideTemporaryProperties) const
         }
         clip.setAttribute("cutzones", cuts.join(";"));
     }
+    QString adata;
+    if (!m_analysisdata.isEmpty()) {
+       QMapIterator<QString, QString> 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();
 }
@@ -268,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();
 }
@@ -276,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());
     }
@@ -1066,8 +1084,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") {
@@ -1259,10 +1279,56 @@ 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)
+void DocClipBase::setAnalysisData(const QString &name, const QString &data, int offset)
 {
     if (data.isEmpty()) m_analysisdata.remove(name);
-    else m_analysisdata.insert(name, data);
+    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 <QString, QString> DocClipBase::analysisData() const