From e006f3c3de685754c0a98ebd2c86da6f6967d524 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Sat, 21 Jun 2008 13:39:44 +0000 Subject: [PATCH] several keyframe effect fixes svn path=/branches/KDE4/; revision=2261 --- effects/volume.xml | 2 +- src/clipitem.cpp | 63 +++++++++++++++++++++++++------- src/clipitem.h | 1 + src/customtrackview.cpp | 5 +-- src/effectslist.cpp | 9 +++++ src/effectslist.h | 2 +- src/renderer.cpp | 13 ++++--- src/trackview.cpp | 80 +++++++++++++++++++++++++++++++++++++---- 8 files changed, 145 insertions(+), 30 deletions(-) diff --git a/effects/volume.xml b/effects/volume.xml index 0a8ca002..1eaa6e0c 100644 --- a/effects/volume.xml +++ b/effects/volume.xml @@ -1,5 +1,5 @@ - + Volume Adjust audio volume with keyframes Dan Dennedy diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 1792e636..fd9caa6b 100644 --- a/src/clipitem.cpp +++ b/src/clipitem.cpp @@ -104,6 +104,32 @@ int ClipItem::selectedEffectIndex() const { return m_selectedEffect; } +void ClipItem::initEffect(QDomElement effect) { + // the kdenlive_ix int is used to identify an effect in mlt's playlist, should + // not be changed + if (effect.attribute("kdenlive_ix").toInt() == 0) + effect.setAttribute("kdenlive_ix", QString::number(effectsCounter())); + // init keyframes if required + QDomNodeList params = effect.elementsByTagName("parameter"); + for (int i = 0; i < params.count(); i++) { + QDomElement e = params.item(i).toElement(); + if (!e.isNull() && e.attribute("type") == "keyframe") { + double max = e.attribute("max").toDouble(); + double min = e.attribute("min").toDouble(); + double def = e.attribute("default").toDouble(); + double factor = e.attribute("factor", "1").toDouble(); + + // Effect has a keyframe type parameter, we need to set the values + if (e.attribute("keyframes").isEmpty()) { + // no keyframes defined, set up 2 keyframes (start and end) with default value. + e.setAttribute("keyframes", QString::number(m_cropStart.frames(m_fps)) + ":" + QString::number(100 * def / (max - min)) + ";" + QString::number((m_cropStart + m_cropDuration).frames(m_fps)) + ":" + QString::number(100 * def / (max - min))); + //kDebug() << "///// EFFECT KEYFRAMES INITED: " << e.attribute("keyframes"); + break; + } + } + } +} + void ClipItem::setSelectedEffect(int ix) { //if (ix == m_selectedEffect) return; @@ -114,24 +140,25 @@ void ClipItem::setSelectedEffect(int ix) { QDomElement e = params.item(i).toElement(); if (!e.isNull() && e.attribute("type") == "keyframe") { m_keyframes.clear(); - int max = e.attribute("max").toInt(); - int min = e.attribute("min").toInt(); - int def = e.attribute("default").toInt(); + double max = e.attribute("max").toDouble(); + double min = e.attribute("min").toDouble(); + double def = e.attribute("default").toDouble(); double factor = e.attribute("factor", "1").toDouble(); // Effect has a keyframe type parameter, we need to set the values - if (e.attribute("keyframes").isEmpty()) { + /*if (e.attribute("keyframes").isEmpty()) { // no keyframes defined, set up 2 keyframes (start and end) with default value. m_keyframes[m_cropStart.frames(m_fps)] = 100 * def / (max - min); m_keyframes[(m_cropStart + m_cropDuration).frames(m_fps)] = 100 * def / (max - min); - } else { - // parse keyframes - QStringList keyframes = e.attribute("keyframes").split(";", QString::SkipEmptyParts); - foreach(QString str, keyframes) { - int pos = str.section(":", 0, 0).toInt(); - double val = str.section(":", 1, 1).toDouble(); - m_keyframes[pos] = val; - } + e.setAttribute("keyframes", QString::number(m_cropStart.frames(m_fps)) + ":" + QString::number(100 * def / (max - min)) + ";" + QString::number((m_cropStart + m_cropDuration).frames(m_fps)) + ":" + QString::number(100 * def / (max - min))); + } else {*/ + // parse keyframes + QStringList keyframes = e.attribute("keyframes").split(";", QString::SkipEmptyParts); + foreach(QString str, keyframes) { + int pos = str.section(":", 0, 0).toInt(); + double val = str.section(":", 1, 1).toDouble(); + m_keyframes[pos] = val; + //} } update(); return; @@ -784,7 +811,17 @@ QMap ClipItem::addEffect(QDomElement effect, bool animate) { for (int i = 0; i < params.count(); i++) { QDomElement e = params.item(i).toElement(); if (!e.isNull()) { - double f = e.attribute("factor", "1").toDouble(); + if (e.attribute("type") == "keyframe") { + effectParams["keyframes"] = e.attribute("keyframes"); + effectParams["min"] = e.attribute("min"); + effectParams["max"] = e.attribute("max"); + effectParams["factor"] = e.attribute("factor", "1"); + effectParams["starttag"] = e.attribute("starttag", "start"); + effectParams["endtag"] = e.attribute("endtag", "end"); + } + + double f = e.attribute("factor", "1").toDouble(); + if (f == 1) { effectParams[e.attribute("name")] = e.attribute("value"); // check if it is a fade effect diff --git a/src/clipitem.h b/src/clipitem.h index 51c6e44c..e091916a 100644 --- a/src/clipitem.h +++ b/src/clipitem.h @@ -85,6 +85,7 @@ public: void updateKeyframeEffect(); QDomElement selectedEffect(); int selectedEffectIndex() const; + void initEffect(QDomElement effect); protected: //virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * event); diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 19e94e7f..0c514f15 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -610,10 +610,7 @@ void CustomTrackView::slotAddEffect(QDomElement effect, GenTime pos, int track) for (int i = 0; i < itemList.count(); i++) { if (itemList.at(i)->type() == AVWIDGET) { ClipItem *item = (ClipItem *)itemList.at(i); - // the kdenlive_ix int is used to identify an effect in mlt's playlist, should - // not be changed - if (effect.attribute("kdenlive_ix").toInt() == 0) - effect.setAttribute("kdenlive_ix", QString::number(item->effectsCounter())); + item->initEffect(effect); AddEffectCommand *command = new AddEffectCommand(this, m_tracksList.count() - item->track(), item->startPos(), effect, true); m_commandStack->push(command); } diff --git a/src/effectslist.cpp b/src/effectslist.cpp index c5b7d621..c9586801 100644 --- a/src/effectslist.cpp +++ b/src/effectslist.cpp @@ -113,6 +113,15 @@ QString EffectsList::getInfo(QString effectName) { return info; } +bool EffectsList::hasKeyFrames(QDomElement effect) { + QDomNodeList params = effect.elementsByTagName("parameter"); + for (int i = 0; i < params.count(); i++) { + QDomElement e = params.item(i).toElement(); + if (e.attribute("type") == "keyframe") return true; + } + return false; +} + // static void EffectsList::setParameter(QDomElement effect, QString name, QString value) { QDomNodeList params = effect.elementsByTagName("parameter"); diff --git a/src/effectslist.h b/src/effectslist.h index e7f6d28b..462e283f 100644 --- a/src/effectslist.h +++ b/src/effectslist.h @@ -38,7 +38,7 @@ public: QStringList effectNames(); QString getInfo(QString effectName); QMap effect(const QString & name); - + static bool hasKeyFrames(QDomElement effect); static void setParameter(QDomElement effect, QString name, QString value); }; diff --git a/src/renderer.cpp b/src/renderer.cpp index b2d00f29..ea552816 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1150,17 +1150,20 @@ void Render::mltAddEffect(int track, GenTime position, QMap a if (!kfr.isEmpty()) { QStringList keyFrames = kfr.split(";", QString::SkipEmptyParts); kDebug() << "// ADDING KEYFRAME EFFECT: " << args.value("keyframes"); - char *starttag = decodedString(args.value("starttag")); + char *starttag = decodedString(args.value("starttag", "start")); char *endtag = decodedString(args.value("endtag", "end")); kDebug() << "// ADDING KEYFRAME TAGS: " << starttag << ", " << endtag; int duration = clip->get_playtime(); - int max = args.value("max").toInt(); - int min = args.value("min").toInt(); + double max = args.value("max").toDouble(); + double min = args.value("min").toDouble(); double factor = args.value("factor", "1").toDouble(); args.remove("starttag"); args.remove("endtag"); args.remove("keyframes"); - int offset = 0; + args.remove("min"); + args.remove("max"); + args.remove("factor"); + int offset = 0; for (int i = 0; i < keyFrames.size() - 1; ++i) { Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, filterTag); filter->set("kdenlive_id", filterId); @@ -1183,7 +1186,7 @@ void Render::mltAddEffect(int track, GenTime position, QMap a filter->set(starttag, QString::number((min + y1 * (max - min) / 100.0) / factor).toUtf8().data()); filter->set(endtag, QString::number((min + y2 * (max - min) / 100.0) / factor).toUtf8().data()); clipService.attach(*filter); - offset = 1; + offset = 1; } delete[] starttag; delete[] endtag; diff --git a/src/trackview.cpp b/src/trackview.cpp index 32e162d6..2d217bda 100644 --- a/src/trackview.cpp +++ b/src/trackview.cpp @@ -207,8 +207,8 @@ void TrackView::parseDocument(QDomDocument doc) { QDomElement e = params.item(i).toElement(); if (!e.isNull() && e.attribute("tag") == paramName) { if (e.attribute("type") == "double") { - QString factor = e.attribute("factor"); - if (!factor.isEmpty()) { + QString factor = e.attribute("factor", "1"); + if (factor != "1") { double val = paramValue.toDouble() * factor.toDouble(); paramValue = QString::number(val); } @@ -353,6 +353,7 @@ int TrackView::slotAddProjectTrack(int ix, QDomElement xml, bool videotrack) { for (QDomNode n2 = elem.firstChild(); !n2.isNull(); n2 = n2.nextSibling()) { QDomElement effect = n2.toElement(); if (effect.tagName() == "filter") { + kDebug() << " * * * * * * * * * * ** CLIP EFF FND * * * * * * * * * * *"; // add effect to clip QString effecttag; QString effectid; @@ -363,11 +364,9 @@ int TrackView::slotAddProjectTrack(int ix, QDomElement xml, bool videotrack) { QDomElement effectparam = n3.toElement(); if (effectparam.attribute("name") == "tag") { effecttag = effectparam.text(); - } - if (effectparam.attribute("name") == "kdenlive_id") { + } else if (effectparam.attribute("name") == "kdenlive_id") { effectid = effectparam.text(); - } - if (effectparam.attribute("name") == "kdenlive_ix") { + } else if (effectparam.attribute("name") == "kdenlive_ix") { effectindex = effectparam.text(); } } @@ -379,6 +378,75 @@ int TrackView::slotAddProjectTrack(int ix, QDomElement xml, bool videotrack) { clipeffect.setAttribute("kdenlive_ix", effectindex); QDomNodeList clipeffectparams = clipeffect.childNodes(); + if (MainWindow::videoEffects.hasKeyFrames(clipeffect)) { + kDebug() << " * * * * * * * * * * ** CLIP EFF WITH KFR FND * * * * * * * * * * *"; + // effect is key-framable, read all effects to retrieve keyframes + double min; + double max; + double factor; + QString starttag; + QString endtag; + QDomNodeList params = clipeffect.elementsByTagName("parameter"); + for (int i = 0; i < params.count(); i++) { + QDomElement e = params.item(i).toElement(); + if (e.attribute("type") == "keyframe") { + starttag = e.attribute("starttag", "start"); + endtag = e.attribute("endtag", "end"); + min = e.attribute("min").toDouble(); + max = e.attribute("max").toDouble(); + factor = e.attribute("factor", "1").toDouble(); + break; + } + } + QString keyframes; + int effectin = effect.attribute("in").toInt(); + int effectout = effect.attribute("out").toInt(); + double startvalue; + double endvalue; + for (QDomNode n3 = effect.firstChild(); !n3.isNull(); n3 = n3.nextSibling()) { + // parse effect parameters + QDomElement effectparam = n3.toElement(); + if (effectparam.attribute("name") == starttag) + startvalue = effectparam.text().toDouble() * factor / (max - min) * 100; + if (effectparam.attribute("name") == endtag) + endvalue = effectparam.text().toDouble() * factor / (max - min) * 100; + } + // add first keyframe + keyframes.append(QString::number(in + effectin) + ":" + QString::number(startvalue) + ";" + QString::number(in + effectout) + ":" + QString::number(endvalue) + ";"); + QDomNode lastParsedEffect; + n2 = n2.nextSibling(); + bool continueParsing = true; + for (; !n2.isNull() && continueParsing; n2 = n2.nextSibling()) { + // parse all effects + QDomElement kfreffect = n2.toElement(); + int effectout = kfreffect.attribute("out").toInt(); + + for (QDomNode n4 = kfreffect.firstChild(); !n4.isNull(); n4 = n4.nextSibling()) { + // parse effect parameters + QDomElement subeffectparam = n4.toElement(); + if (subeffectparam.attribute("name") == "kdenlive_ix" && subeffectparam.text() != effectindex) { + //We are not in the same effect, stop parsing + lastParsedEffect = n2.previousSibling(); + continueParsing = false; + break; + } else if (subeffectparam.attribute("name") == endtag) { + endvalue = subeffectparam.text().toDouble() * factor / (max - min) * 100; + break; + } + } + if (continueParsing) keyframes.append(QString::number(in + effectout) + ":" + QString::number(endvalue) + ";"); + } + + params = clipeffect.elementsByTagName("parameter"); + for (int i = 0; i < params.count(); i++) { + QDomElement e = params.item(i).toElement(); + if (e.attribute("type") == "keyframe") e.setAttribute("keyframes", keyframes); + } + if (!continueParsing) { + n2 = lastParsedEffect; + } + } + // adjust effect parameters for (QDomNode n3 = effect.firstChild(); !n3.isNull(); n3 = n3.nextSibling()) { // parse effect parameters -- 2.39.2