From 9a6dc5f7c53f0af2e6148d703c00cf0e3fd438e3 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Mon, 3 Nov 2008 22:21:30 +0000 Subject: [PATCH] Some work on speed effect, should fix most of bug http://www.kdenlive.org:80/mantis/view.php?id=188 svn path=/branches/KDE4/; revision=2619 --- src/abstractclipitem.cpp | 41 +++++++++++++++--------- src/abstractclipitem.h | 6 ++-- src/changespeedcommand.cpp | 4 +-- src/clipitem.cpp | 35 +++++++++++++------- src/clipitem.h | 7 ++-- src/customtrackview.cpp | 20 ++++++------ src/customtrackview.h | 2 +- src/renderer.cpp | 65 ++++++++++++++++++++++++++++++-------- src/renderer.h | 2 +- 9 files changed, 124 insertions(+), 58 deletions(-) diff --git a/src/abstractclipitem.cpp b/src/abstractclipitem.cpp index 87419b8f..62a25fbf 100644 --- a/src/abstractclipitem.cpp +++ b/src/abstractclipitem.cpp @@ -40,7 +40,7 @@ ItemInfo AbstractClipItem::info() const { ItemInfo itemInfo; itemInfo.startPos = startPos(); itemInfo.endPos = endPos(); - itemInfo.cropStart = cropStart(); + itemInfo.cropStart = m_cropStart; itemInfo.track = track(); return itemInfo; } @@ -57,26 +57,34 @@ GenTime AbstractClipItem::cropStart() const { return m_cropStart; } +GenTime AbstractClipItem::cropDuration() const { + return m_cropDuration; +} + void AbstractClipItem::setCropStart(GenTime pos) { m_cropStart = pos; } -void AbstractClipItem::resizeStart(int posx) { +void AbstractClipItem::updateRectGeometry() { + setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); +} + +void AbstractClipItem::resizeStart(int posx, double speed) { GenTime durationDiff = GenTime(posx, m_fps) - m_startPos; if (durationDiff == GenTime()) return; - //kDebug() << "-- RESCALE: CROP=" << m_cropStart << ", DIFF = " << durationDiff; + kDebug() << "-- RESCALE: CROP=" << m_cropStart.frames(25) << " - " << cropStart().frames(25); - if (type() == AVWIDGET && m_cropStart + durationDiff < GenTime()) { - durationDiff = GenTime() - m_cropStart; + if (type() == AVWIDGET && cropStart() + durationDiff < GenTime()) { + durationDiff = GenTime() - cropStart(); } else if (durationDiff >= m_cropDuration) { durationDiff = m_cropDuration - GenTime(3, m_fps); } m_startPos += durationDiff; - if (type() == AVWIDGET) m_cropStart += durationDiff; - m_cropDuration = m_cropDuration - durationDiff; + if (type() == AVWIDGET) m_cropStart += durationDiff * speed; + m_cropDuration = m_cropDuration - durationDiff * speed; - setRect(0, 0, m_cropDuration.frames(m_fps) - 0.02, rect().height()); + setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); setPos((qreal) m_startPos.frames(m_fps), pos().y()); //setRect((double) m_startPos.frames(m_fps) * scale, rect().y(), (double) m_cropDuration.frames(m_fps) * scale, rect().height()); if (durationDiff < GenTime()) { @@ -97,17 +105,20 @@ void AbstractClipItem::resizeStart(int posx) { } } -void AbstractClipItem::resizeEnd(int posx, bool updateKeyFrames) { +void AbstractClipItem::resizeEnd(int posx, double speed, bool updateKeyFrames) { GenTime durationDiff = GenTime(posx, m_fps) - endPos(); if (durationDiff == GenTime()) return; //kDebug() << "-- RESCALE: CROP=" << m_cropStart << ", DIFF = " << durationDiff; - if (m_cropDuration + durationDiff <= GenTime()) { - durationDiff = GenTime() - (m_cropDuration - GenTime(3, m_fps)); - } else if (m_cropStart + m_cropDuration + durationDiff >= maxDuration()) { - durationDiff = maxDuration() - m_cropDuration - m_cropStart; + kDebug() << "// DUR DIFF1:" << durationDiff.frames(25) << ", ADJUSTED: " << durationDiff.frames(25) * speed << ", SPED:" << speed; + if (cropDuration() + durationDiff <= GenTime()) { + durationDiff = GenTime() - (cropDuration() - GenTime(3, m_fps)); + } else if (cropStart() + cropDuration() + durationDiff >= maxDuration()) { + kDebug() << "// MAX OVERLOAD:" << cropDuration().frames(25) << " + " << durationDiff.frames(25) << ", MAX:" << maxDuration().frames(25); + durationDiff = maxDuration() - cropDuration() - cropStart(); } - m_cropDuration += durationDiff; - setRect(0, 0, m_cropDuration.frames(m_fps) - 0.02, rect().height()); + kDebug() << "// DUR DIFF2:" << durationDiff.frames(25) << ", ADJUSTED: " << durationDiff.frames(25) * speed << ", SPED:" << speed; + m_cropDuration += durationDiff * speed; + setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); if (durationDiff > GenTime()) { QList collisionList = collidingItems(Qt::IntersectsItemBoundingRect); for (int i = 0; i < collisionList.size(); ++i) { diff --git a/src/abstractclipitem.h b/src/abstractclipitem.h index 7b7d60e8..dbc75d47 100644 --- a/src/abstractclipitem.h +++ b/src/abstractclipitem.h @@ -40,6 +40,7 @@ public: double keyFrameFactor() const; ItemInfo info() const; CustomTrackScene* projectScene(); + void updateRectGeometry(); virtual OPERATIONTYPE operationMode(QPointF pos) = 0; virtual GenTime startPos() const ; @@ -47,8 +48,9 @@ public: virtual GenTime endPos() const ; virtual int track() const ; virtual GenTime cropStart() const ; - virtual void resizeStart(int posx); - virtual void resizeEnd(int posx, bool updateKeyFrames = true); + virtual GenTime cropDuration() const ; + virtual void resizeStart(int posx, double speed = 1.0); + virtual void resizeEnd(int posx, double speed = 1.0, bool updateKeyFrames = true); virtual GenTime duration() const; virtual double fps() const; virtual GenTime maxDuration() const; diff --git a/src/changespeedcommand.cpp b/src/changespeedcommand.cpp index e7b66af7..35468c91 100644 --- a/src/changespeedcommand.cpp +++ b/src/changespeedcommand.cpp @@ -29,12 +29,12 @@ ChangeSpeedCommand::ChangeSpeedCommand(CustomTrackView *view, ItemInfo info, dou // virtual void ChangeSpeedCommand::undo() { - m_view->doChangeClipSpeed(m_clipInfo, m_old_speed, m_clipId); + m_view->doChangeClipSpeed(m_clipInfo, m_old_speed, m_new_speed, m_clipId); } // virtual void ChangeSpeedCommand::redo() { if (m_doIt) { - m_view->doChangeClipSpeed(m_clipInfo, m_new_speed, m_clipId); + m_view->doChangeClipSpeed(m_clipInfo, m_new_speed, m_old_speed, m_clipId); } m_doIt = true; } diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 188ded2f..bbd0c45d 100644 --- a/src/clipitem.cpp +++ b/src/clipitem.cpp @@ -336,7 +336,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 +362,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 +399,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(); @@ -528,7 +528,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) @@ -921,12 +921,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)));*/ @@ -934,12 +934,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)));*/ @@ -1223,13 +1224,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")); diff --git a/src/clipitem.h b/src/clipitem.h index 8a3d4a2c..a17bf785 100644 --- a/src/clipitem.h +++ b/src/clipitem.h @@ -46,8 +46,8 @@ public: const QStyleOptionGraphicsItem *option, QWidget *); virtual int type() const; - void resizeStart(int posx); - void resizeEnd(int posx, bool updateKeyFrames = true); + void resizeStart(int posx, double speed = 1.0); + void resizeEnd(int posx, double speed = 1.0, bool updateKeyFrames = true); OPERATIONTYPE operationMode(QPointF pos); const QString &clipProducer() const; int clipType() const; @@ -96,6 +96,9 @@ public: void setSpeed(const double speed); double speed() const; GenTime maxDuration() const; + GenTime cropStart() const; + GenTime endPos() const; + GenTime cropDuration() const; int hasEffect(const QString &tag, const QString &id) const; bool checkKeyFrames(); diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 087477d9..478261c6 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -1528,7 +1528,7 @@ void CustomTrackView::changeClipSpeed() { if (itemList.at(i)->type() == AVWIDGET) { ClipItem *item = static_cast (itemList.at(i)); ItemInfo info = item->info(); - int percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), 100, 1, 300); + int percent = QInputDialog::getInteger(this, i18n("Edit Clip Speed"), i18n("New speed (percents)"), item->speed() * 100, 1, 300); double speed = (double) percent / 100.0; if (item->speed() != speed) new ChangeSpeedCommand(this, info, item->speed(), speed, item->clipProducer(), true, changeSelected); @@ -1537,20 +1537,18 @@ void CustomTrackView::changeClipSpeed() { m_commandStack->push(changeSelected); } -void CustomTrackView::doChangeClipSpeed(ItemInfo info, double speed, const QString &id) { +void CustomTrackView::doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id) { + DocClipBase *baseclip = m_document->clipManager()->getClipById(id); ClipItem *item = getClipItemAt((int) info.startPos.frames(m_document->fps()) + 1, info.track); info.track = m_scene->m_tracksList.count() - item->track(); - m_document->renderer()->mltChangeClipSpeed(info, speed, baseclip->producer()); + int endPos = m_document->renderer()->mltChangeClipSpeed(info, speed, oldspeed, baseclip->producer()); + kDebug() << "//CH CLIP SPEED: " << speed << "x" << oldspeed << ", END POS: " << endPos; item->setSpeed(speed); - GenTime maxDuration = item->maxDuration(); - if (maxDuration < item->duration()) { - info = item->info(); - ItemInfo endInfo = info; - endInfo.endPos = info.startPos + maxDuration; - ResizeClipCommand *command = new ResizeClipCommand(this, info, endInfo, true); - m_commandStack->push(command); - } + item->updateRectGeometry(); + kDebug() << "// SPD CHG: " << item->cropDuration().frames(m_document->fps()) << " - " << endPos; + if (item->cropDuration().frames(m_document->fps()) > endPos) + item->AbstractClipItem::resizeEnd(info.startPos.frames(m_document->fps()) + endPos, speed); } void CustomTrackView::cutSelectedClips() { diff --git a/src/customtrackview.h b/src/customtrackview.h index 099fbb6d..30142581 100644 --- a/src/customtrackview.h +++ b/src/customtrackview.h @@ -94,7 +94,7 @@ public: void clipStart(); void clipEnd(); void changeClipSpeed(); - void doChangeClipSpeed(ItemInfo info, double speed, const QString &id); + void doChangeClipSpeed(ItemInfo info, const double speed, const double oldspeed, const QString &id); void setDocumentModified(); void setInPoint(); void setOutPoint(); diff --git a/src/renderer.cpp b/src/renderer.cpp index a46a405c..55deb9a4 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1445,7 +1445,7 @@ bool Render::mltRemoveClip(int track, GenTime position) { return true; } -int Render::mltChangeClipSpeed(ItemInfo info, double speed, Mlt::Producer *prod) { +int Render::mltChangeClipSpeed(ItemInfo info, double speed, double oldspeed, Mlt::Producer *prod) { m_isBlocked = true; int newLength = 0; Mlt::Service service(m_mltProducer->parent().get_service()); @@ -1454,7 +1454,10 @@ int Render::mltChangeClipSpeed(ItemInfo info, double speed, Mlt::Producer *prod) Mlt::Tractor tractor(service); Mlt::Producer trackProducer(tractor.track(info.track)); Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); - int clipIndex = trackPlaylist.get_clip_index_at((int) info.startPos.frames(m_fps)); + int startPos = info.startPos.frames(m_fps); + int clipIndex = trackPlaylist.get_clip_index_at(startPos); + int clipLength = trackPlaylist.clip_length(clipIndex); + Mlt::Producer clip(trackPlaylist.get_clip(clipIndex)); QString serv = clip.parent().get("mlt_service"); QString id = clip.parent().get("id"); @@ -1474,20 +1477,42 @@ int Render::mltChangeClipSpeed(ItemInfo info, double speed, Mlt::Producer *prod) delete[] tmp; m_slowmotionProducers.insert(url, slowprod); } - Mlt::Producer *cut = slowprod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1); - newLength = cut->get_length(); trackPlaylist.replace_with_blank(clipIndex); trackPlaylist.consolidate_blanks(0); - trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *cut, 1); + // Check that the blank space is long enough for our new duration + clipIndex = trackPlaylist.get_clip_index_at(startPos); + int blankEnd = trackPlaylist.clip_start(clipIndex) + trackPlaylist.clip_length(clipIndex); + Mlt::Producer *cut; + if (clipIndex + 1 < trackPlaylist.count() && (startPos + clipLength / speed > blankEnd)) { + GenTime maxLength = GenTime(blankEnd, m_fps) - info.startPos; + cut = slowprod->cut((int)(info.cropStart.frames(m_fps) / speed), (int)(info.cropStart.frames(m_fps) / speed + maxLength.frames(m_fps) - 1)); + } else cut = slowprod->cut((int)(info.cropStart.frames(m_fps) / speed), (int)((info.cropStart.frames(m_fps) + clipLength) / speed - 1)); + trackPlaylist.insert_at(startPos, *cut, 1); + clipIndex = trackPlaylist.get_clip_index_at(startPos); + newLength = trackPlaylist.clip_length(clipIndex); mlt_service_unlock(service.get_service()); } else if (speed == 1.0) { mlt_service_lock(service.get_service()); - Mlt::Producer *cut = prod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1); + trackPlaylist.replace_with_blank(clipIndex); - newLength = cut->get_length(); trackPlaylist.consolidate_blanks(0); - trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *cut, 1); + + // Check that the blank space is long enough for our new duration + clipIndex = trackPlaylist.get_clip_index_at(startPos); + int blankEnd = trackPlaylist.clip_start(clipIndex) + trackPlaylist.clip_length(clipIndex); + + Mlt::Producer *cut; + GenTime oldDuration = GenTime(clipLength, m_fps); + GenTime newDuration = oldDuration * oldspeed; + if (clipIndex + 1 < trackPlaylist.count() && (info.startPos + newDuration).frames(m_fps) > blankEnd) { + GenTime maxLength = GenTime(blankEnd, m_fps) - info.startPos; + cut = prod->cut((int)(info.cropStart.frames(m_fps)), (int)(info.cropStart.frames(m_fps) + maxLength.frames(m_fps) - 1)); + } else cut = prod->cut((int)(info.cropStart.frames(m_fps)), (int)((info.cropStart + newDuration).frames(m_fps)) - 1); + trackPlaylist.insert_at(startPos, *cut, 1); + clipIndex = trackPlaylist.get_clip_index_at(startPos); + newLength = trackPlaylist.clip_length(clipIndex); mlt_service_unlock(service.get_service()); + } else if (serv == "framebuffer") { mlt_service_lock(service.get_service()); QString url = clip.parent().get("resource"); @@ -1504,15 +1529,29 @@ int Render::mltChangeClipSpeed(ItemInfo info, double speed, Mlt::Producer *prod) delete[] tmp; m_slowmotionProducers.insert(url, slowprod); } - Mlt::Producer *cut = slowprod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1); - newLength = cut->get_length(); trackPlaylist.replace_with_blank(clipIndex); trackPlaylist.consolidate_blanks(0); - trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *cut, 1); + + GenTime oldDuration = GenTime(clipLength, m_fps); + GenTime newDuration = oldDuration * oldspeed / speed; + + // Check that the blank space is long enough for our new duration + clipIndex = trackPlaylist.get_clip_index_at(startPos); + int blankEnd = trackPlaylist.clip_start(clipIndex) + trackPlaylist.clip_length(clipIndex); + + Mlt::Producer *cut; + if (clipIndex + 1 < trackPlaylist.count() && (info.startPos + newDuration).frames(m_fps) > blankEnd) { + GenTime maxLength = GenTime(blankEnd, m_fps) - info.startPos; + cut = slowprod->cut((int)(info.cropStart.frames(m_fps)), (int)(info.cropStart.frames(m_fps) + maxLength.frames(m_fps) - 1)); + } else cut = slowprod->cut((int)(info.cropStart.frames(m_fps) / speed), (int)((info.cropStart / speed + newDuration).frames(m_fps) - 1)); + + trackPlaylist.insert_at(startPos, *cut, 1); + clipIndex = trackPlaylist.get_clip_index_at(startPos); + newLength = trackPlaylist.clip_length(clipIndex); + mlt_service_unlock(service.get_service()); - kDebug() << "AVFORMAT CLIP!!!:"; } - + if (clipIndex + 1 == trackPlaylist.count()) mltCheckLength(); m_isBlocked = false; return newLength; } diff --git a/src/renderer.h b/src/renderer.h index 1298b441..cc8cbde2 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -176,7 +176,7 @@ Q_OBJECT public: to the clip and 0.6 is the speed in percents. The newly created producer will have it's "id" parameter set to: "slowmotion:parentid:speed", where parentid is the id of the original clip in the ClipManager list and speed is the current speed */ - int mltChangeClipSpeed(ItemInfo info, double speed, Mlt::Producer *prod); + int mltChangeClipSpeed(ItemInfo info, double speed, double oldspeed, Mlt::Producer *prod); QList producersList(); -- 2.39.2