]> git.sesse.net Git - kdenlive/blobdiff - src/clipitem.cpp
Cache timeline thumbnails for faster project opening, should solve:
[kdenlive] / src / clipitem.cpp
index 264d9309095fcd8d7c073616934007ca5d1203a0..b270a8c7c0f878b8e671708437baceab76586142 100644 (file)
@@ -42,8 +42,9 @@
 
 ClipItem::ClipItem(DocClipBase *clip, ItemInfo info, double fps, bool generateThumbs)
         : AbstractClipItem(info, QRectF(), fps), m_clip(clip), m_resizeMode(NONE), m_grabPoint(0), m_maxTrack(0), m_hasThumbs(false), startThumbTimer(NULL), endThumbTimer(NULL), audioThumbWasDrawn(false), m_opacity(1.0), m_timeLine(0), m_startThumbRequested(false), m_endThumbRequested(false), m_startFade(0), m_endFade(0), m_hover(false), m_selectedEffect(-1), m_speed(1.0), framePixelWidth(0), m_startPix(QPixmap()), m_endPix(QPixmap()) {
-    setRect(0, 0, (info.endPos - info.startPos).frames(fps) - 0.02, (qreal)(KdenliveSettings::trackheight() - 2));
-    setPos((qreal) info.startPos.frames(fps), (qreal)(info.track * KdenliveSettings::trackheight()) + 1);
+    setZValue(1);
+    setRect(0, 0, (info.endPos - info.startPos).frames(fps) - 0.02, (double)(KdenliveSettings::trackheight() - 2));
+    setPos(info.startPos.frames(fps), (double)(info.track * KdenliveSettings::trackheight()) + 1);
 
     m_clipName = clip->name();
     m_producer = clip->getId();
@@ -148,6 +149,20 @@ void ClipItem::initEffect(QDomElement effect) {
             }
         }
     }
+
+    if (effect.attribute("tag") == "volume") {
+        if (effect.attribute("id") == "fadeout") {
+            int end = (duration() + cropStart()).frames(m_fps);
+            int start = end - EffectsList::parameter(effect, "in").toInt();
+            EffectsList::setParameter(effect, "in", QString::number(start));
+            EffectsList::setParameter(effect, "out", QString::number(end));
+        } else if (effect.attribute("id") == "fadein") {
+            int start = cropStart().frames(m_fps);
+            int end = start + EffectsList::parameter(effect, "out").toInt();
+            EffectsList::setParameter(effect, "in", QString::number(start));
+            EffectsList::setParameter(effect, "out", QString::number(end));
+        }
+    }
 }
 
 bool ClipItem::checkKeyFrames() {
@@ -336,7 +351,7 @@ void ClipItem::slotFetchThumbs() {
     if (m_endPix.isNull() && m_startPix.isNull()) {
         m_startThumbRequested = true;
         m_endThumbRequested = true;
-        emit getThumb((int)m_cropStart.frames(m_fps), (int)(m_cropStart + m_cropDuration).frames(m_fps) - 1);
+        emit getThumb((int)cropStart().frames(m_fps), (int)(cropStart() + cropDuration()).frames(m_fps) - 1);
     } else {
         if (m_endPix.isNull()) {
             slotGetEndThumb();
@@ -362,14 +377,14 @@ void ClipItem::slotFetchThumbs() {
 
 void ClipItem::slotGetStartThumb() {
     m_startThumbRequested = true;
-    emit getThumb((int)m_cropStart.frames(m_fps), -1);
+    emit getThumb((int)cropStart().frames(m_fps), -1);
     //videoThumbProducer.setThumbFrames(m_clip->producer(), (int)m_cropStart.frames(m_fps),  - 1);
     //videoThumbProducer.start(QThread::LowestPriority);
 }
 
 void ClipItem::slotGetEndThumb() {
     m_endThumbRequested = true;
-    emit getThumb(-1, (int)(m_cropStart + m_cropDuration).frames(m_fps) - 1);
+    emit getThumb(-1, (int)(cropStart() + cropDuration()).frames(m_fps) - 1);
     //videoThumbProducer.setThumbFrames(m_clip->producer(), -1, (int)(m_cropStart + m_cropDuration).frames(m_fps) - 1);
     //videoThumbProducer.start(QThread::LowestPriority);
 }
@@ -399,12 +414,12 @@ void ClipItem::slotThumbReady(int frame, QPixmap pix) {
     if (scene() == NULL) return;
     QRectF r = sceneBoundingRect();
     double width = m_startPix.width() / projectScene()->scale();
-    if (m_startThumbRequested && frame == m_cropStart.frames(m_fps)) {
+    if (m_startThumbRequested && frame == cropStart().frames(m_fps)) {
         m_startPix = pix;
         m_startThumbRequested = false;
         double height = r.height();
         update(r.x(), r.y(), width, height);
-    } else if (m_endThumbRequested && frame == (m_cropStart + m_cropDuration).frames(m_fps) - 1) {
+    } else if (m_endThumbRequested && frame == (cropStart() + cropDuration()).frames(m_fps) - 1) {
         m_endPix = pix;
         m_endThumbRequested = false;
         double height = r.height();
@@ -412,14 +427,22 @@ void ClipItem::slotThumbReady(int frame, QPixmap pix) {
     }
 }
 
-void ClipItem::slotSetStartThumb(QPixmap pix) {
+void ClipItem::slotSetStartThumb(const QPixmap pix) {
     m_startPix = pix;
 }
 
-void ClipItem::slotSetEndThumb(QPixmap pix) {
+void ClipItem::slotSetEndThumb(const QPixmap pix) {
     m_endPix = pix;
 }
 
+QPixmap ClipItem::startThumb() const {
+    return m_startPix;
+}
+
+QPixmap ClipItem::endThumb() const {
+    return m_endPix;
+}
+
 void ClipItem::slotGotAudioData() {
     audioThumbReady = true;
     if (m_clipType == AV) {
@@ -489,7 +512,7 @@ void ClipItem::paint(QPainter *painter,
     //QPainterPath roundRectPathUpper = upperRectPart(br), roundRectPathLower = lowerRectPart(br);
     painter->setClipRect(exposed);
 
-    // build path around clip
+    //build path around clip
     //QPainterPath resultClipPath = roundRectPathUpper.united(roundRectPathLower);
     //painter->fillPath(resultClipPath, paintColor);
     painter->fillRect(br, paintColor);
@@ -528,7 +551,7 @@ void ClipItem::paint(QPainter *painter,
     }
 
     // draw audio thumbnails
-    if (KdenliveSettings::audiothumbnails() && ((m_clipType == AV && exposed.bottom() > (itemHeight / 2)) || m_clipType == AUDIO) && audioThumbReady) {
+    if (KdenliveSettings::audiothumbnails() && m_speed == 1.0 && ((m_clipType == AV && exposed.bottom() > (itemHeight / 2)) || m_clipType == AUDIO) && audioThumbReady) {
 
         double startpixel = exposed.left();
         if (startpixel < 0)
@@ -556,7 +579,9 @@ void ClipItem::paint(QPainter *painter,
         const int mappedEndPixel =  painter->matrix().map(QPointF(endpixel + cropLeft, 0)).x() - clipStart;
         cropLeft = cropLeft * scale;
 
-        emit prepareAudioThumb(scale, mappedStartPixel, mappedEndPixel, channels);
+        if (channels >= 1) {
+            emit prepareAudioThumb(scale, mappedStartPixel, mappedEndPixel, channels);
+        }
 
         for (int startCache = mappedStartPixel - (mappedStartPixel) % 100; startCache < mappedEndPixel; startCache += 100) {
             if (audioThumbCachePic.contains(startCache) && !audioThumbCachePic[startCache].isNull())
@@ -791,6 +816,12 @@ void ClipItem::slotPrepareAudioThumb(double pixelForOneFrame, int startpixel, in
         pixpainter.setPen(audiopen);
         //pixpainter.setRenderHint(QPainter::Antialiasing,true);
         //pixpainter.drawLine(0,0,100,re.height());
+        // Bail out, if caller provided invalid data
+        if (channels <= 0) {
+            kWarning() << "Unable to draw image with " << channels << "number of channels";
+            return;
+        }
+
         int channelHeight = audioThumbCachePic[startCache].height() / channels;
 
         for (int i = 0;i < channels;i++) {
@@ -856,21 +887,23 @@ uint ClipItem::fadeOut() const {
 
 
 void ClipItem::setFadeIn(int pos) {
+    if (pos == m_startFade) return;
     int oldIn = m_startFade;
     if (pos < 0) pos = 0;
-    if (pos > m_cropDuration.frames(m_fps)) pos = (int)(m_cropDuration.frames(m_fps) / 2);
+    if (pos > m_cropDuration.frames(m_fps)) pos = (int)(m_cropDuration.frames(m_fps));
     m_startFade = pos;
     QRectF rect = boundingRect();
     update(rect.x(), rect.y(), qMax(oldIn, pos), rect.height());
 }
 
 void ClipItem::setFadeOut(int pos) {
+    if (pos == m_endFade) return;
     int oldOut = m_endFade;
     if (pos < 0) pos = 0;
-    if (pos > m_cropDuration.frames(m_fps)) pos = (int)(m_cropDuration.frames(m_fps) / 2);
+    if (pos > m_cropDuration.frames(m_fps)) pos = (int)(m_cropDuration.frames(m_fps));
     m_endFade = pos;
     QRectF rect = boundingRect();
-    update(rect.x() + rect.width() - qMax(oldOut, pos), rect.y(), pos, rect.height());
+    update(rect.x() + rect.width() - qMax(oldOut, pos), rect.y(), qMax(oldOut, pos), rect.height());
 
 }
 
@@ -913,12 +946,12 @@ void ClipItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
     update(r.right() - width, r.y() + height, width, height);
 }
 
-void ClipItem::resizeStart(int posx) {
+void ClipItem::resizeStart(int posx, double speed) {
     const int min = (startPos() - cropStart()).frames(m_fps);
     if (posx < min) posx = min;
     if (posx == startPos().frames(m_fps)) return;
     const int previous = cropStart().frames(m_fps);
-    AbstractClipItem::resizeStart(posx);
+    AbstractClipItem::resizeStart(posx, m_speed);
     checkEffectsKeyframesPos(previous, cropStart().frames(m_fps), true);
     if (m_hasThumbs && KdenliveSettings::videothumbnails()) {
         /*connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));*/
@@ -926,12 +959,13 @@ void ClipItem::resizeStart(int posx) {
     }
 }
 
-void ClipItem::resizeEnd(int posx, bool updateKeyFrames) {
+void ClipItem::resizeEnd(int posx, double speed, bool updateKeyFrames) {
     const int max = (startPos() - cropStart() + maxDuration()).frames(m_fps) + 1;
     if (posx > max) posx = max;
     if (posx == endPos().frames(m_fps)) return;
+    //kDebug() << "// NEW POS: " << posx << ", OLD END: " << endPos().frames(m_fps);
     const int previous = (cropStart() + duration()).frames(m_fps);
-    AbstractClipItem::resizeEnd(posx);
+    AbstractClipItem::resizeEnd(posx, m_speed);
     if (updateKeyFrames) checkEffectsKeyframesPos(previous, (cropStart() + duration()).frames(m_fps), false);
     if (m_hasThumbs && KdenliveSettings::videothumbnails()) {
         /*connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int, QPixmap)), this, SLOT(slotThumbReady(int, QPixmap)));*/
@@ -975,18 +1009,17 @@ void ClipItem::checkEffectsKeyframesPos(const int previous, const int current, b
     if (m_selectedEffect >= 0) setSelectedEffect(m_selectedEffect);
 }
 
-
 //virtual
 QVariant ClipItem::itemChange(GraphicsItemChange change, const QVariant &value) {
     if (change == ItemPositionChange && scene()) {
         // calculate new position.
-        if (group() != 0) return pos();
+        if (group()) return pos();
         QPointF newPos = value.toPointF();
-        //kDebug() << "/// MOVING CLIP ITEM.------------";
+        kDebug() << "/// MOVING CLIP ITEM.------------\n++++++++++";
         int xpos = projectScene()->getSnapPointForPos((int) newPos.x(), KdenliveSettings::snaptopoints());
         xpos = qMax(xpos, 0);
         newPos.setX(xpos);
-        int newTrack = (newPos.y() + KdenliveSettings::trackheight() / 2) / KdenliveSettings::trackheight();
+        int newTrack = newPos.y() / KdenliveSettings::trackheight();
         newTrack = qMin(newTrack, projectScene()->tracksCount() - 1);
         newTrack = qMax(newTrack, 0);
         newPos.setY((int)(newTrack  * KdenliveSettings::trackheight() + 1));
@@ -1067,7 +1100,7 @@ QDomElement ClipItem::effectAt(int ix) {
 }
 
 void ClipItem::setEffectAt(int ix, QDomElement effect) {
-    kDebug() << "CHange EFFECT AT: " << ix << ", CURR: " << m_effectList.at(ix).attribute("tag") << ", NEW: " << effect.attribute("tag");
+    kDebug() << "CHange EFFECT AT: " << ix << ", CURR: " << m_effectList.at(ix).attribute("tag") << ", NEW: " << effect.attribute("tag");
     effect.setAttribute("kdenlive_ix", ix + 1);
     m_effectList.insert(ix, effect);
     m_effectList.removeAt(ix + 1);
@@ -1215,13 +1248,25 @@ void ClipItem::setSpeed(const double speed) {
     m_speed = speed;
     if (m_speed == 1.0) m_clipName = baseClip()->name();
     else m_clipName = baseClip()->name() + " - " + QString::number(speed * 100, 'f', 0) + "%";
-    update();
+    //update();
 }
 
 GenTime ClipItem::maxDuration() const {
     return m_maxDuration / m_speed;
 }
 
+GenTime ClipItem::cropStart() const {
+    return m_cropStart / m_speed;
+}
+
+GenTime ClipItem::cropDuration() const {
+    return m_cropDuration / m_speed;
+}
+
+GenTime ClipItem::endPos() const {
+    return m_startPos + cropDuration();
+}
+
 //virtual
 void ClipItem::dropEvent(QGraphicsSceneDragDropEvent * event) {
     QString effects = QString(event->mimeData()->data("kdenlive/effectslist"));