[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdenlive/Applications/16.12] src: Fix many issues with volume keyframes
From:       Jean-Baptiste Mardelle <jb () kdenlive ! org>
Date:       2016-11-30 23:06:22
Message-ID: E1cCDxG-00087z-TS () code ! kde ! org
[Download RAW message or body]

Git commit b348355e43285c37456bfc2625a055811b790b8f by Jean-Baptiste Mardelle.
Committed on 30/11/2016 at 23:05.
Pushed by mardelle into branch 'Applications/16.12'.

Fix many issues with volume keyframes

M  +1    -1    src/doc/documentvalidator.cpp
M  +5    -5    src/effectstack/widgets/animationwidget.cpp
M  +1    -1    src/effectstack/widgets/animationwidget.h
M  +11   -9    src/mltcontroller/effectscontroller.cpp
M  +6    -5    src/timeline/abstractclipitem.cpp
M  +3    -5    src/timeline/clipitem.cpp
M  +1    -2    src/timeline/customtrackview.cpp
M  +1    -2    src/timeline/effectmanager.cpp
M  +62   -7    src/timeline/keyframeview.cpp
M  +2    -0    src/timeline/keyframeview.h
M  +3    -3    src/timeline/track.cpp

https://commits.kde.org/kdenlive/b348355e43285c37456bfc2625a055811b790b8f

diff --git a/src/doc/documentvalidator.cpp b/src/doc/documentvalidator.cpp
index 595f76f..7e524d6 100644
--- a/src/doc/documentvalidator.cpp
+++ b/src/doc/documentvalidator.cpp
@@ -1497,7 +1497,7 @@ bool DocumentValidator::upgrade(double version, const double \
currentVersion)  }
                     }
                     EffectsList::setProperty(eff, conversionParams.at(2), \
                parsedValues.join(";"));
-                    EffectsList::setProperty(eff, \
QStringLiteral("kdenlive:sync_in_out"), QStringLiteral("1")); +                    \
//EffectsList::setProperty(eff, QStringLiteral("kdenlive:sync_in_out"), \
QStringLiteral("1"));  eff.setAttribute(QStringLiteral("out"), out);
                 }
             }
diff --git a/src/effectstack/widgets/animationwidget.cpp \
b/src/effectstack/widgets/animationwidget.cpp index 71ab9d2..aaffa78 100644
--- a/src/effectstack/widgets/animationwidget.cpp
+++ b/src/effectstack/widgets/animationwidget.cpp
@@ -232,9 +232,9 @@ void AnimationWidget::finishSetup()
 }
 
 //static
-QString AnimationWidget::getDefaultKeyframes(const QString &defaultValue, bool \
linearOnly) +QString AnimationWidget::getDefaultKeyframes(int start, const QString \
&defaultValue, bool linearOnly)  {
-    QString keyframes = QStringLiteral("0");
+    QString keyframes = QString::number(start);
     if (linearOnly) {
         keyframes.append(QStringLiteral("="));
     } else {
@@ -671,7 +671,7 @@ void AnimationWidget::addParameter(const QDomElement &e)
         keyframes = e.attribute(QStringLiteral("value"));
     }
     if (keyframes.isEmpty()) {
-        keyframes = getDefaultKeyframes(e.attribute(QStringLiteral("default")));
+        keyframes = getDefaultKeyframes(m_inPoint, \
e.attribute(QStringLiteral("default")));  if (keyframes.contains('%')) {
             keyframes = \
EffectsController::getStringRectEval(m_monitor->profileInfo(), keyframes);  }
@@ -1012,7 +1012,7 @@ void AnimationWidget::loadPresets(QString currentText)
     QMap <QString, QVariant> defaultEntry;
     QStringList paramNames = m_doubleWidgets.keys();
     for (int i = 0; i < paramNames.count(); i++) {
-        defaultEntry.insert(paramNames.at(i), \
getDefaultKeyframes(m_params.at(i).attribute(QStringLiteral("default")))); +        \
defaultEntry.insert(paramNames.at(i), getDefaultKeyframes(m_inPoint, \
m_params.at(i).attribute(QStringLiteral("default"))));  }
     m_presetCombo->addItem(i18n("Default"), defaultEntry);
     loadPreset(dir.absoluteFilePath(m_xml.attribute(QStringLiteral("type"))));
@@ -1304,7 +1304,7 @@ void AnimationWidget::reload(const QString &tag, const QString \
&data)  if (!m_rectParameter.isEmpty() && tag != m_rectParameter) {
         // reset geometry keyframes
         // simple anim parameter, get default value
-        QString def = getDefaultKeyframes(defaultValue(m_rectParameter));
+        QString def = getDefaultKeyframes(m_inPoint, defaultValue(m_rectParameter));
         // Clear current keyframes
         m_animProperties.set(m_rectParameter.toUtf8().constData(), \
def.toUtf8().constData());  // Add default keyframes
diff --git a/src/effectstack/widgets/animationwidget.h \
b/src/effectstack/widgets/animationwidget.h index 4e13503..869dae5 100644
--- a/src/effectstack/widgets/animationwidget.h
+++ b/src/effectstack/widgets/animationwidget.h
@@ -51,7 +51,7 @@ public:
     void updateTimecodeFormat();
     void addParameter(const QDomElement &e);
     const QMap <QString, QString> getAnimation();
-    static QString getDefaultKeyframes(const QString &defaultValue, bool linearOnly \
= false); +    static QString getDefaultKeyframes(int start, const QString \
&defaultValue, bool linearOnly = false);  void setActiveKeyframe(int frame);
     void finishSetup();
     /** @brief Returns true if currently active param is name */
diff --git a/src/mltcontroller/effectscontroller.cpp \
b/src/mltcontroller/effectscontroller.cpp index 2bc2ec9..026092f 100644
--- a/src/mltcontroller/effectscontroller.cpp
+++ b/src/mltcontroller/effectscontroller.cpp
@@ -103,8 +103,9 @@ EffectsParameterList EffectsController::getEffectArgs(const \
                ProfileInfo &info, c
     parameters.addParam(QStringLiteral("tag"), \
                effect.attribute(QStringLiteral("tag")));
     //if (effect.hasAttribute("region")) parameters.addParam("region", \
                effect.attribute("region"));
     parameters.addParam(QStringLiteral("kdenlive_ix"), \
                effect.attribute(QStringLiteral("kdenlive_ix")));
-    if (effect.hasAttribute(QStringLiteral("sync_in_out")))
+    if (effect.hasAttribute(QStringLiteral("sync_in_out"))) {
         parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), \
effect.attribute(QStringLiteral("sync_in_out"))); +    }
     parameters.addParam(QStringLiteral("kdenlive_info"), \
                effect.attribute(QStringLiteral("kdenlive_info")));
     parameters.addParam(QStringLiteral("id"), \
                effect.attribute(QStringLiteral("id")));
     if (effect.hasAttribute(QStringLiteral("src"))) \
parameters.addParam(QStringLiteral("src"), effect.attribute(QStringLiteral("src"))); \
@@ -137,10 +138,11 @@ void \
EffectsController::adjustEffectParameters(EffectsParameterList &parameters,  for (int \
i = 0; i < params.count(); ++i) {  QDomElement e = params.item(i).toElement();
         QString paramname = prefix + e.attribute(QStringLiteral("name"));
-        if (e.attribute(QStringLiteral("type")) == QLatin1String("animated") || \
(e.attribute(QStringLiteral("type")) == QLatin1String("geometry") && \
!e.hasAttribute(QStringLiteral("fixed")))) { +        /*if \
(e.attribute(QStringLiteral("type")) == QLatin1String("animated") || \
(e.attribute(QStringLiteral("type")) == QLatin1String("geometry") && \
                !e.hasAttribute(QStringLiteral("fixed")))) {
             // effects with geometry param need in / out synced with the clip, \
                request it...
-            //parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), \
                QStringLiteral("1"));
-        }
+            parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), \
QStringLiteral("1")); +            qDebug()<<" ** * ADDIN EFFECT ANIM SYN TRUE";
+        }*/
         if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) {
             parameters.addParam(paramname, e.attribute(QStringLiteral("value")));
         } else if (e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe")) { @@ -229,7 +231,7 @@ void \
EffectsController::initTrackEffect(ProfileInfo pInfo, QDomElement effect)  bool \
                hasValue = e.hasAttribute(QStringLiteral("value"));
         // Check if this effect has a variable parameter, init effects default value
         if ((type == QLatin1String("animatedrect") || type == \
                QLatin1String("geometry")) && !hasValue) {
-            QString kfr = \
AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default")), type == \
QLatin1String("geometry")); +            QString kfr = \
AnimationWidget::getDefaultKeyframes(0, e.attribute(QStringLiteral("default")), type \
== QLatin1String("geometry"));  if (kfr.contains("%")) {
                 kfr = EffectsController::getStringRectEval(pInfo, kfr);
             }
@@ -244,7 +246,7 @@ void EffectsController::initTrackEffect(ProfileInfo pInfo, \
                QDomElement effect)
             } else e.setAttribute(QStringLiteral("value"), evaluatedValue);
         } else {
             if (type == QLatin1String("animated") && !hasValue) {
-                e.setAttribute(QStringLiteral("value"), \
AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default")))); +      \
e.setAttribute(QStringLiteral("value"), AnimationWidget::getDefaultKeyframes(0, \
e.attribute(QStringLiteral("default"))));  }
             else if (!hasValue) {
                 e.setAttribute(QStringLiteral("value"), \
e.attribute(QStringLiteral("default"))); @@ -273,7 +275,7 @@ void \
EffectsController::initEffect(ItemInfo info, ProfileInfo pInfo, EffectsList  bool \
                hasValue = e.hasAttribute(QStringLiteral("value"));
         // Check if this effect has a variable parameter, init effects default value
         if ((type == QLatin1String("animatedrect") || type == \
                QLatin1String("geometry")) && !hasValue) {
-            QString kfr = \
AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default")), type == \
QLatin1String("geometry")); +            QString kfr = \
AnimationWidget::getDefaultKeyframes(info.cropStart.frames(fps), \
e.attribute(QStringLiteral("default")), type == QLatin1String("geometry"));  if \
(kfr.contains("%")) {  kfr = EffectsController::getStringRectEval(pInfo, kfr);
             }
@@ -288,7 +290,7 @@ void EffectsController::initEffect(ItemInfo info, ProfileInfo \
                pInfo, EffectsList
             } else e.setAttribute(QStringLiteral("value"), evaluatedValue);
         } else {
             if (type == QLatin1String("animated") && !hasValue) {
-                e.setAttribute(QStringLiteral("value"), \
AnimationWidget::getDefaultKeyframes(e.attribute(QStringLiteral("default")))); +      \
e.setAttribute(QStringLiteral("value"), \
AnimationWidget::getDefaultKeyframes(info.cropStart.frames(fps), \
e.attribute(QStringLiteral("default"))));  }
             else if (!hasValue) {
                 e.setAttribute(QStringLiteral("value"), \
e.attribute(QStringLiteral("default"))); @@ -312,7 +314,7 @@ void \
EffectsController::initEffect(ItemInfo info, ProfileInfo pInfo, EffectsList  }
         }
 
-        if (type.startsWith(QStringLiteral("animated"))  || (type == \
QLatin1String("geometry") && !e.hasAttribute(QStringLiteral("fixed")))) { +        if \
(EffectsList::parameter(effect, QStringLiteral("kdenlive:sync_in_out")) == \
QLatin1String("1")  || (type == QLatin1String("geometry") && \
                !e.hasAttribute(QStringLiteral("fixed")))) {
             // Effects with a geometry parameter need to sync in / out with parent \
                clip
             effect.setAttribute(QStringLiteral("in"), QString::number((int) \
                info.cropStart.frames(fps)));
             effect.setAttribute(QStringLiteral("out"), QString::number((int) \
                (info.cropStart + info.cropDuration).frames(fps) - 1));
diff --git a/src/timeline/abstractclipitem.cpp b/src/timeline/abstractclipitem.cpp
index 09c318e..4f4a876 100644
--- a/src/timeline/abstractclipitem.cpp
+++ b/src/timeline/abstractclipitem.cpp
@@ -200,7 +200,6 @@ void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, \
bool /*emitChang  }
     m_info.startPos += durationDiff;
     m_keyframeView.setOffset(durationDiff.frames(m_fps));
-
     // set to true if crop from start is negative (possible for color clips, images \
as they have no size limit)  bool negCropStart = false;
     if (type() == AVWidget) {
@@ -616,7 +615,7 @@ QString AbstractClipItem::resizeAnimations(QDomElement effect, \
                int previousDurat
                 effect.setAttribute(QStringLiteral("out"), QString::number(start + \
duration));  }
             else {
-                keyframes = KeyframeView::cutAnimation(animation, cropstart, \
duration, previousDuration, false); +                keyframes = \
KeyframeView::addBorderKeyframes(animation, cropstart, duration);  }
             // TODO: in case of multiple animated params, use _intimeline to detect \
active one  e.setAttribute(QStringLiteral("value"), keyframes);
@@ -628,10 +627,12 @@ QString AbstractClipItem::resizeAnimations(QDomElement effect, \
int previousDurat  bool AbstractClipItem::switchKeyframes(QDomElement param, int in, \
int oldin, int out, int oldout)  {
     QString animation = param.attribute(QStringLiteral("value"));
-    if (in != oldin)
+    if (in != oldin) {
         animation = KeyframeView::switchAnimation(animation, in, oldin, out, oldout, \
                param.attribute(QStringLiteral("type")) == \
                QLatin1String("animatedrect"));
-    if (out != oldout)
-        animation = KeyframeView::switchAnimation(animation, out - 1, oldout - 1, \
out, oldout, param.attribute(QStringLiteral("type")) == \
QLatin1String("animatedrect")); +    }
+    if (out != oldout) {
+        animation = KeyframeView::switchAnimation(animation, out, oldout, out, \
oldout, param.attribute(QStringLiteral("type")) == QLatin1String("animatedrect")); +  \
}  if (animation != param.attribute(QStringLiteral("value"))) {
         param.setAttribute(QStringLiteral("value"), animation);
         return true;
diff --git a/src/timeline/clipitem.cpp b/src/timeline/clipitem.cpp
index 579a7d8..687b978 100644
--- a/src/timeline/clipitem.cpp
+++ b/src/timeline/clipitem.cpp
@@ -1453,7 +1453,7 @@ EffectsParameterList ClipItem::addEffect(ProfileInfo info, \
                QDomElement effect, b
             else if (e.attribute(QStringLiteral("type")) == \
                QLatin1String("animated")) {
                 parameters.addParam(e.attribute(QStringLiteral("name")), \
e.attribute(QStringLiteral("value")));  // Effects with a animated parameter need to \
                sync in / out with parent clip
-                if (!e.hasAttribute(QStringLiteral("sync_in_out")) || \
e.attribute(QStringLiteral("sync_in_out")) ==  QLatin1String("1")) { +                \
if (e.attribute(QStringLiteral("sync_in_out")) ==  QLatin1String("1")) {  \
needInOutSync = true;  }
             } else if (e.attribute(QStringLiteral("type")) == \
QLatin1String("simplekeyframe")) { @@ -1808,10 +1808,9 @@ QMap<int, QDomElement> \
                ClipItem::adjustEffectsToDuration(const ItemInfo &oldInfo
                 if (effect.attribute(QStringLiteral("sync_in_out")) == \
                QLatin1String("1")) {
                     effect.setAttribute(QStringLiteral("in"), \
                cropStart().frames(m_fps));
                     effect.setAttribute(QStringLiteral("out"), (cropStart() + \
                cropDuration()).frames(m_fps) - 1);
-                } else {
-                    // Check if we have keyframes at in/out points
-                    updateAnimatedKeyframes(i, param, oldInfo);
                 }
+                // Check if we have keyframes at in/out points
+                updateAnimatedKeyframes(i, param, oldInfo);
 		effects[i] = effect.cloneNode().toElement();
             } else if (type == QLatin1String("roto-spline")) {
                 if (!effects.contains(i))
@@ -1856,7 +1855,6 @@ bool ClipItem::updateNormalKeyframes(QDomElement parameter, \
                const ItemInfo &oldI
         keyframes[keyframepos] = locale.toDouble(keyframe.section('=', 1, 1));
     }
 
-
     QMap<int, double>::iterator i = keyframes.end();
     int lastPos = -1;
     double lastValue = 0;
diff --git a/src/timeline/customtrackview.cpp b/src/timeline/customtrackview.cpp
index 6700af7..71736aa 100644
--- a/src/timeline/customtrackview.cpp
+++ b/src/timeline/customtrackview.cpp
@@ -1380,7 +1380,7 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
         ClipItem * item = static_cast <ClipItem *>(m_dragItem);
         QDomElement oldEffect = item->selectedEffect().cloneNode().toElement();
         if (single == 1) {
-            item->insertKeyframe(m_document->getProfileInfo(), \
item->getEffectAtIndex(item->selectedEffectIndex()), \
(item->cropDuration()).frames(m_document->fps()) - 1, -1, true); +            \
item->insertKeyframe(m_document->getProfileInfo(), \
item->getEffectAtIndex(item->selectedEffectIndex()), (item->cropStart() + \
item->cropDuration()).frames(m_document->fps()) - 1, -1, true);  }
         //QString previous = item->keyframes(item->selectedEffectIndex());
         item->insertKeyframe(m_document->getProfileInfo(), \
item->getEffectAtIndex(item->selectedEffectIndex()), \
keyFramePos.frames(m_document->fps()), val); @@ -1906,7 +1906,6 @@ bool \
CustomTrackView::itemCollision(AbstractClipItem *item, const ItemInfo &newP  
 void CustomTrackView::slotRefreshEffects(ClipItem *clip)
 {
-    // Does not seem used anywhere...
     int track = clip->track();
     GenTime pos = clip->startPos();
     if (!m_timeline->track(track)->removeEffect(pos.seconds(), -1, false)) {
diff --git a/src/timeline/effectmanager.cpp b/src/timeline/effectmanager.cpp
index 75d38d2..bcfb84b 100644
--- a/src/timeline/effectmanager.cpp
+++ b/src/timeline/effectmanager.cpp
@@ -316,8 +316,7 @@ bool EffectManager::editEffect(EffectsParameterList params, int \
                duration, bool r
         if (params.paramValue(QStringLiteral("kdenlive:sync_in_out")) == \
QLatin1String("1")) {  // This effect must sync in / out with parent clip
             //params.removeParam(QStringLiteral("sync_in_out"));
-            Mlt::Producer prod(m_producer);
-            filter->set_in_and_out(prod.get_in(), prod.get_out());
+            filter->set_in_and_out(m_producer.get_int("in"), \
m_producer.get_int("out"));  } else {
             // Reset in/out properties
             filter->set("in", (char*)NULL);
diff --git a/src/timeline/keyframeview.cpp b/src/timeline/keyframeview.cpp
index 93b5028..30586c7 100644
--- a/src/timeline/keyframeview.cpp
+++ b/src/timeline/keyframeview.cpp
@@ -23,7 +23,6 @@ along with this program.  If not, see \
<http://www.gnu.org/licenses/>.  #include <QPainter>
 #include <QAction>
 #include <QApplication>
-
 #include "klocalizedstring.h"
 
 #include "keyframeview.h"
@@ -142,14 +141,28 @@ void KeyframeView::drawKeyFrames(QRectF br, int length, bool \
                active, QPainter *p
         Mlt::Animation drawAnim = \
m_keyProperties.get_animation(paramName.toUtf8().constData());  if \
(!drawAnim.is_valid()) continue;  QPainterPath path;
-        int frame = drawAnim.key_get_frame(0);
+        // Find first key before our clip start, get frame for rect left first
+        int firstKF = qMax(0, drawAnim.previous_key(-m_offset));
+        int lastKF = drawAnim.next_key(duration - m_offset);
+        if (lastKF < duration - m_offset) {
+            lastKF = duration - m_offset;
+        }
+        int frame = firstKF;
         double value = \
m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - \
                m_offset);
         QPointF start = keyframePoint(br, frame + m_offset, value, info.factor, \
info.min, info.max);  path.moveTo(br.x(), br.bottom());
         path.lineTo(br.x(), start.y());
         path.lineTo(start);
+        int currentFrame;
         painter->setPen(paramName == m_inTimeline ? QColor(Qt::white) : Qt::NoPen);
         for(int i = 0; i < drawAnim.key_count(); ++i) {
+            currentFrame = drawAnim.key_get_frame(i);
+            if (currentFrame < firstKF) {
+                continue;
+            }
+            if (currentFrame > lastKF) {
+                break;
+            }
             if (active && paramName == m_inTimeline) {
                 painter->setBrush((drawAnim.key_get_frame(i) == activeKeyframe) ? \
                QColor(Qt::red) : QColor(Qt::blue));
                 painter->drawEllipse(QRectF(transformation.map(start) - h/2, \
transformation.map(start) + h / 2)); @@ -170,10 +183,10 @@ void \
KeyframeView::drawKeyFrames(QRectF br, int length, bool active, QPainter *p  case \
mlt_keyframe_smooth:  frame = drawAnim.key_get_frame(qMax(i - 1, 0));
                         value = \
m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - \
                m_offset);
-                        QPointF pre = keyframePoint(br, frame, value, info.factor, \
info.min, info.max); +                        QPointF pre = keyframePoint(br, frame + \
                m_offset, value, info.factor, info.min, info.max);
                         frame = drawAnim.key_get_frame(qMin(i + 2, \
                drawAnim.key_count() - 1));
                         value = \
m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - \
                m_offset);
-                        QPointF post = keyframePoint(br, frame, value, info.factor, \
info.min, info.max); +                        QPointF post = keyframePoint(br, frame \
+ m_offset, value, info.factor, info.min, info.max);  QPointF c1 = (end - pre) / 6.0; \
// + start  QPointF c2 = (start - post) / 6.0; // + end
                         double mid = (end.x() - start.x()) / 2;
@@ -832,7 +845,7 @@ bool KeyframeView::loadKeyframes(const QLocale locale, \
QDomElement effect, int c  }
     attachToEnd = -2;
     m_useOffset = effect.attribute(QStringLiteral("kdenlive:sync_in_out")) != \
                QLatin1String("1");
-    m_offset = effect.attribute("in").toInt() - cropStart;
+    m_offset = effect.attribute(QStringLiteral("in")).toInt() - cropStart;
     QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter"));
     for (int i = 0; i < params.count(); ++i) {
         QDomElement e = params.item(i).toElement();
@@ -891,9 +904,23 @@ bool KeyframeView::loadKeyframes(const QLocale locale, \
QDomElement effect, int c  
 void KeyframeView::setOffset(int frames)
 {
-    if (m_useOffset) {
+    if (!m_keyAnim.is_valid())
+        return;
+    if (m_keyAnim.is_key(-m_offset)) {
+        mlt_keyframe_type type = m_keyAnim.keyframe_type(-m_offset);
+        double value = \
m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), -m_offset, \
duration - m_offset); +        m_keyAnim.remove(-m_offset);
+        if (activeKeyframe == -m_offset) {
+            activeKeyframe -= frames;
+        }
+        m_offset -= frames;
+        m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), value, - \
m_offset, duration - m_offset, type); +        //addKeyframe(-m_offset, value, type);
+    } else {
         m_offset -= frames;
     }
+    //double value = \
m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), 0, duration - \
m_offset); +    //}
 }
 
 // static
@@ -962,6 +989,34 @@ QString KeyframeView::cutAnimation(const QString &animation, int \
start, int dura  }
 
 //static
+const QString KeyframeView::addBorderKeyframes(const QString &animation, int start, \
int duration) +{
+    bool modified = false;
+    Mlt::Properties props;
+    props.set("keyframes", animation.toUtf8().constData());
+    props.anim_get_double("keyframes", 0, start+duration);
+    Mlt::Animation anim = props.get_animation("keyframes");
+    if (!anim.is_key(start)) {
+        double value = props.anim_get_double("keyframes", start, start+duration);
+        int previous = anim.previous_key(start);
+	mlt_keyframe_type type = anim.keyframe_type(previous);
+        props.anim_set("keyframes", value, start, start+duration, type);
+        modified = true;
+    }
+    if (!anim.is_key(start+duration)) {
+        double value = props.anim_get_double("keyframes", start+duration, \
start+duration); +        int previous = anim.previous_key(start+duration);
+	mlt_keyframe_type type = anim.keyframe_type(previous);
+        props.anim_set("keyframes", value, start+duration, start+duration, type);
+        modified = true;
+    }
+    if (modified) {
+        return anim.serialize_cut();
+    }
+    return animation;
+}
+
+//static
 QString KeyframeView::switchAnimation(QString animation, int newPos, int oldPos, int \
newDuration, int oldDuration, bool isRect)  {
     Mlt::Properties props;
@@ -971,7 +1026,7 @@ QString KeyframeView::switchAnimation(QString animation, int \
newPos, int oldPos,  if (anim.is_key(oldPos)) {
 	// insert new keyframe at start
         if (isRect) {
-            mlt_rect rect = props.anim_get_rect("keyframes", oldPos);
+            mlt_rect rect = props.anim_get_rect("keyframes", oldPos, oldDuration);
             props.anim_set("keyframes", rect, newPos, newDuration, \
anim.keyframe_type(oldPos));  anim.remove(oldPos);
         } else {
diff --git a/src/timeline/keyframeview.h b/src/timeline/keyframeview.h
index 2eef776..342b50f 100644
--- a/src/timeline/keyframeview.h
+++ b/src/timeline/keyframeview.h
@@ -97,6 +97,8 @@ public:
     static QString switchAnimation(QString animation, int newPos, int oldPos, int \
                newDuration, int oldDuration, bool isRect);
     /** @brief when loading an animation from a serialized string, check where is \
the first negative keyframe) */  static int checkNegatives(const QString &data, int \
maxDuration); +    /** @brief Add keyframes at start / end points if not existing */
+    static const QString addBorderKeyframes(const QString &animation, int start, int \
duration);  /** @brief returns true if currently edited parameter name is name */
     bool activeParam(const QString &name) const;
     /** @brief Sets a temporary offset for drawing keyframes when resizing clip \
                start */
diff --git a/src/timeline/track.cpp b/src/timeline/track.cpp
index 32aa837..43ce2ad 100644
--- a/src/timeline/track.cpp
+++ b/src/timeline/track.cpp
@@ -905,9 +905,9 @@ bool Track::editEffect(double start, EffectsParameterList params, \
bool replace)  if (!clip) {
         return false;
     }
-    Mlt::Service clipService(clip->get_service());
-    EffectManager effect(clipService);
-    return effect.editEffect(params, duration, replace);
+    EffectManager effect(*clip.data());
+    bool result = effect.editEffect(params, duration, replace);
+    return result;
 }
 
 bool Track::editTrackEffect(EffectsParameterList params, bool replace)


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic