From: Dan Dennedy Date: Tue, 31 Aug 2010 07:44:51 +0000 (+0000) Subject: Add animation feature to Slideshow Clip. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=e3b4bf11679a3a195be8896f465b1616581f1fb3;p=kdenlive Add animation feature to Slideshow Clip. svn path=/trunk/kdenlive/; revision=4791 --- diff --git a/src/clipmanager.cpp b/src/clipmanager.cpp index fc48734f..dd9ffb7d 100644 --- a/src/clipmanager.cpp +++ b/src/clipmanager.cpp @@ -372,7 +372,10 @@ void ClipManager::slotAddColorClipFile(const QString name, const QString color, m_doc->commandStack()->push(command); } -void ClipManager::slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId) +void ClipManager::slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, + const bool loop, const bool crop, const bool fade, + const QString &luma_duration, const QString &luma_file, const int softness, + const QString &animation, QString group, const QString &groupId) { QDomDocument doc; QDomElement prod = doc.createElement("producer"); @@ -391,6 +394,7 @@ void ClipManager::slotAddSlideshowClipFile(const QString name, const QString pat prod.setAttribute("fade", fade); prod.setAttribute("softness", QString::number(softness)); prod.setAttribute("luma_file", luma_file); + prod.setAttribute("animation", animation); if (!group.isEmpty()) { prod.setAttribute("groupname", group); prod.setAttribute("groupid", groupId); diff --git a/src/clipmanager.h b/src/clipmanager.h index 8ea9b4a8..2e83e7c5 100644 --- a/src/clipmanager.h +++ b/src/clipmanager.h @@ -76,7 +76,10 @@ Q_OBJECT public: void slotAddTextTemplateClip(QString titleName, const KUrl path, const QString group, const QString &groupId); void slotAddXmlClipFile(const QString name, const QDomElement xml, const QString group, const QString &groupId); void slotAddColorClipFile(const QString name, const QString color, QString duration, const QString group, const QString &groupId); - void slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, const QString group, const QString &groupId); + void slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, + const bool loop, const bool crop,const bool fade, + const QString &luma_duration, const QString &luma_file, const int softness, + const QString &animation, const QString group, const QString &groupId); DocClipBase *getClipById(QString clipId); const QList getClipByResource(QString resource); void slotDeleteClips(QStringList ids); diff --git a/src/clipproperties.cpp b/src/clipproperties.cpp index 4ff65f02..4c833223 100644 --- a/src/clipproperties.cpp +++ b/src/clipproperties.cpp @@ -183,11 +183,22 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg m_view.image_type->addItem("TGA (*.tga)", "tga"); m_view.image_type->addItem("TIFF (*.tiff)", "tiff"); m_view.image_type->addItem("Open EXR (*.exr)", "exr"); + m_view.animation->addItem(i18n("None"), QString()); + m_view.animation->addItem(i18n("Pan"), "Pan"); + m_view.animation->addItem(i18n("Pan, low-pass"), "Pan, low-pass"); + m_view.animation->addItem(i18n("Pan and zoom"), "Pan and zoom"); + m_view.animation->addItem(i18n("Pan and zoom, low-pass"), "Pan and zoom, low-pass"); + m_view.animation->addItem(i18n("Zoom"), "Zoom"); + m_view.animation->addItem(i18n("Zoom, low-pass"), "Zoom, low-pass"); m_view.slide_loop->setChecked(props.value("loop").toInt()); m_view.slide_crop->setChecked(props.value("crop").toInt()); m_view.slide_fade->setChecked(props.value("fade").toInt()); m_view.luma_softness->setValue(props.value("softness").toInt()); + if (!props.value("animation").isEmpty()) + m_view.animation->setCurrentItem(props.value("animation")); + else + m_view.animation->setCurrentIndex(0); QString path = props.value("resource"); QString ext = path.section('.', -1); for (int i = 0; i < m_view.image_type->count(); i++) { @@ -631,6 +642,15 @@ QMap ClipProperties::properties() } } + QString animation = m_view.animation->itemData(m_view.animation->currentIndex()).toString(); + if (animation != m_old_props.value("animation")) { + if (animation.isEmpty()) { + props["animation"].clear(); + } else { + props["animation"] = animation; + } + m_clipNeedsRefresh = true; + } } return props; } diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index fc74fbf1..87194e0f 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -28,6 +28,7 @@ #include "kdenlivesettings.h" #include "kthumb.h" #include "clipmanager.h" +#include "slideshowclip.h" #include #include @@ -650,6 +651,49 @@ void DocClipBase::slotRefreshProducer() if (!getProperty("out").isEmpty()) m_clipProducer->set_in_and_out(getProperty("in").toInt(), getProperty("out").toInt());*/ setProducerProperty("ttl", getProperty("ttl").toInt()); //m_clipProducer->set("id", getProperty("id")); + if (!getProperty("animation").isEmpty()) { + Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service()); + int ct = 0; + Mlt::Filter *filter = clipService.filter(ct); + while (filter) { + if (strcmp(filter->get("mlt_service"), "affine") == 0) { + break; + } + else if (strcmp(filter->get("mlt_service"), "boxblur") == 0) { + clipService.detach(*filter); + } else ct++; + filter = clipService.filter(ct); + } + + if (!filter || strcmp(filter->get("mlt_service"), "affine")) { + // filter does not exist, create it. + Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "affine"); + if (filter && filter->is_valid()) { + int cycle = getProperty("ttl").toInt(); + QString geometry = SlideshowClip::animationToGeometry(getProperty("animation"), cycle); + if (!geometry.isEmpty()) { + if (getProperty("animation").contains("low-pass")) { + Mlt::Filter *blur = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "boxblur"); + if (blur && blur->is_valid()) + clipService.attach(*blur); + } + filter->set("transition.geometry", geometry.toUtf8().data()); + filter->set("transition.cycle", cycle); + clipService.attach(*filter); + } + } + } + } else { + Mlt::Service clipService(m_baseTrackProducers.at(0)->get_service()); + int ct = 0; + Mlt::Filter *filter = clipService.filter(0); + while (filter) { + if (strcmp(filter->get("mlt_service"), "affine") == 0 || strcmp(filter->get("mlt_service"), "boxblur") == 0) { + clipService.detach(*filter); + } else ct++; + filter = clipService.filter(ct); + } + } if (getProperty("fade") == "1") { // we want a fade filter effect kDebug() << "//////////// FADE WANTED"; @@ -665,8 +709,8 @@ void DocClipBase::slotRefreshProducer() } if (filter && strcmp(filter->get("mlt_service"), "luma") == 0) { - filter->set("period", getProperty("ttl").toInt() - 1); - filter->set("luma.out", getProperty("luma_duration").toInt()); + filter->set("cycle", getProperty("ttl").toInt()); + filter->set("duration", getProperty("luma_duration").toInt()); QString resource = getProperty("luma_file"); char *tmp = (char *) qstrdup(resource.toUtf8().data()); filter->set("luma.resource", tmp); @@ -678,8 +722,8 @@ void DocClipBase::slotRefreshProducer() } else { // filter does not exist, create it... Mlt::Filter *filter = new Mlt::Filter(*(m_baseTrackProducers.at(0)->profile()), "luma"); - filter->set("period", getProperty("ttl").toInt() - 1); - filter->set("luma.out", getProperty("luma_duration").toInt()); + filter->set("cycle", getProperty("ttl").toInt()); + filter->set("duration", getProperty("luma_duration").toInt()); QString resource = getProperty("luma_file"); char *tmp = (char *) qstrdup(resource.toUtf8().data()); filter->set("luma.resource", tmp); diff --git a/src/kdenlivedoc.cpp b/src/kdenlivedoc.cpp index 3af911e5..7ea9272a 100644 --- a/src/kdenlivedoc.cpp +++ b/src/kdenlivedoc.cpp @@ -1074,9 +1074,15 @@ void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color, emit selectLastAddedClip(QString::number(m_clipManager->lastClipId())); } -void KdenliveDoc::slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId) -{ - m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop, crop, fade, luma_duration, luma_file, softness, group, groupId); +void KdenliveDoc::slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, + const bool loop, const bool crop, const bool fade, + const QString &luma_duration, const QString &luma_file, const int softness, + const QString &animation, QString group, const QString &groupId) +{ + m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop, + crop, fade, luma_duration, + luma_file, softness, + animation, group, groupId); setModified(true); emit selectLastAddedClip(QString::number(m_clipManager->lastClipId())); } diff --git a/src/kdenlivedoc.h b/src/kdenlivedoc.h index f34dbabf..d8d2fc22 100644 --- a/src/kdenlivedoc.h +++ b/src/kdenlivedoc.h @@ -154,7 +154,10 @@ private: public slots: void slotCreateXmlClip(const QString &name, const QDomElement xml, QString group, const QString &groupId); void slotCreateColorClip(const QString &name, const QString &color, const QString &duration, QString group, const QString &groupId); - void slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool crop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId); + void slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, + const bool loop, const bool crop, const bool fade, + const QString &luma_duration, const QString &luma_file, const int softness, + const QString &animation, QString group, const QString &groupId); void slotCreateTextClip(QString group, const QString &groupId, const QString &templatePath = QString()); void slotCreateTextTemplateClip(QString group, const QString &groupId, KUrl path); /** Set to true if document needs saving, false otherwise */ diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 8b2d0aa5..9899268e 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -1103,7 +1103,10 @@ void ProjectList::slotAddClip(const QList givenList, const QString &group fileName.chop(1); } - m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()), false, false, false, m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0, groupInfo.at(0), groupInfo.at(1)); + m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()), + false, false, false, + m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0, + QString(), groupInfo.at(0), groupInfo.at(1)); return; } } @@ -1191,8 +1194,10 @@ void ProjectList::slotAddSlideshowClip() if (dia->exec() == QDialog::Accepted) { QStringList groupInfo = getGroup(); - m_doc->slotCreateSlideshowClipFile(dia->clipName(), dia->selectedPath(), dia->imageCount(), dia->clipDuration(), dia->loop(), dia->crop(), dia->fade(), - dia->lumaDuration(), dia->lumaFile(), dia->softness(), groupInfo.at(0), groupInfo.at(1)); + m_doc->slotCreateSlideshowClipFile(dia->clipName(), dia->selectedPath(), dia->imageCount(), dia->clipDuration(), + dia->loop(), dia->crop(), dia->fade(), + dia->lumaDuration(), dia->lumaFile(), dia->softness(), + dia->animation(), groupInfo.at(0), groupInfo.at(1)); } delete dia; } diff --git a/src/renderer.cpp b/src/renderer.cpp index 4d6d3153..c6086450 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -27,6 +27,7 @@ #include "kdenlivesettings.h" #include "kthumb.h" #include "definitions.h" +#include "slideshowclip.h" #include @@ -712,13 +713,31 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int Mlt::Frame *frame = producer->get_frame(); if (xml.attribute("type").toInt() == SLIDESHOW) { - if (xml.hasAttribute("ttl")) producer->set("ttl", xml.attribute("ttl").toInt()); + int ttl = xml.hasAttribute("ttl") ? xml.attribute("ttl").toInt() : 0; + if (ttl) producer->set("ttl", ttl); + if (!xml.attribute("animation").isEmpty()) { + Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, "affine"); + if (filter && filter->is_valid()) { + int cycle = ttl; + QString geometry = SlideshowClip::animationToGeometry(xml.attribute("animation"), cycle); + if (!geometry.isEmpty()) { + if (xml.attribute("animation").contains("low-pass")) { + Mlt::Filter *blur = new Mlt::Filter(*m_mltProfile, "boxblur"); + if (blur && blur->is_valid()) + producer->attach(*blur); + } + filter->set("transition.geometry", geometry.toUtf8().data()); + filter->set("transition.cycle", cycle); + producer->attach(*filter); + } + } + } if (xml.attribute("fade") == "1") { // user wants a fade effect to slideshow Mlt::Filter *filter = new Mlt::Filter(*m_mltProfile, "luma"); if (filter && filter->is_valid()) { - if (xml.hasAttribute("ttl")) filter->set("period", xml.attribute("ttl").toInt() - 1); - if (xml.hasAttribute("luma_duration") && !xml.attribute("luma_duration").isEmpty()) filter->set("luma.out", xml.attribute("luma_duration").toInt()); + if (ttl) filter->set("cycle", ttl); + if (xml.hasAttribute("luma_duration") && !xml.attribute("luma_duration").isEmpty()) filter->set("duration", xml.attribute("luma_duration").toInt()); if (xml.hasAttribute("luma_file") && !xml.attribute("luma_file").isEmpty()) { char *tmp = decodedString(xml.attribute("luma_file")); filter->set("luma.resource", tmp); @@ -728,8 +747,7 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int filter->set("luma.softness", (double) soft / 100.0); } } - Mlt::Service clipService(producer->get_service()); - clipService.attach(*filter); + producer->attach(*filter); } } if (xml.attribute("crop") == "1") { diff --git a/src/slideshowclip.cpp b/src/slideshowclip.cpp index aa8e67ba..3938b029 100644 --- a/src/slideshowclip.cpp +++ b/src/slideshowclip.cpp @@ -58,6 +58,13 @@ SlideshowClip::SlideshowClip(Timecode tc, QWidget * parent) : m_view.image_type->addItem("TGA (*.tga)", "tga"); m_view.image_type->addItem("TIFF (*.tiff)", "tiff"); m_view.image_type->addItem("Open EXR (*.exr)", "exr"); + m_view.animation->addItem(i18n("None"), QString()); + m_view.animation->addItem(i18n("Pan"), "Pan"); + m_view.animation->addItem(i18n("Pan, low-pass"), "Pan, low-pass"); + m_view.animation->addItem(i18n("Pan and zoom"), "Pan and zoom"); + m_view.animation->addItem(i18n("Pan and zoom, low-pass"), "Pan and zoom, low-pass"); + m_view.animation->addItem(i18n("Zoom"), "Zoom"); + m_view.animation->addItem(i18n("Zoom, low-pass"), "Zoom, low-pass"); m_view.clip_duration->setInputMask(""); m_view.clip_duration->setValidator(m_timecode.validator()); @@ -378,6 +385,12 @@ QString SlideshowClip::lumaFile() const return m_view.luma_file->itemData(m_view.luma_file->currentIndex()).toString(); } +QString SlideshowClip::animation() const +{ + if (m_view.animation->itemData(m_view.animation->currentIndex()).isNull()) return QString(); + return m_view.animation->itemData(m_view.animation->currentIndex()).toString(); +} + void SlideshowClip::slotUpdateDurationFormat(int ix) { bool framesFormat = ix == 1; @@ -414,7 +427,24 @@ void SlideshowClip::slotMethodChanged(bool active) parseFolder(); } - +// static +QString SlideshowClip::animationToGeometry(const QString &animation, int &ttl) +{ + QString geometry; + if (animation.startsWith("Pan and zoom")) { + geometry = QString().sprintf("0=0,0:100%%x100%%;%d=-14%%,-14%%:120%%x120%%;%d=-5%%,-5%%:110%%x110%%;%d=0,0:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=-5%%,0:110%%x110%%", + ttl-1, ttl, ttl*2 - 1, ttl*2, ttl*3 - 1 ); + ttl *= 3; + } else if (animation.startsWith("Pan")) { + geometry = QString().sprintf("0=-5%%,-5%%:110%%x110%%;%d=0,0:110%%x110%%;%d=0,0:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=-5%%,-5%%:110%%x110%%;%d=0,-5%%:110%%x110%%;%d=-5%%,0:110%%x110%%", + ttl-1, ttl, ttl*2 - 1, ttl*2, ttl*3 - 1, ttl*3, ttl*4 - 1 ); + ttl *= 4; + } else if (animation.startsWith("Zoom")) { + geometry = QString().sprintf("0=0,0:100%%x100%%;%d=-14%%,-14%%:120%%x120%%", + ttl-1, ttl ); + } + return geometry; +} #include "slideshowclip.moc" diff --git a/src/slideshowclip.h b/src/slideshowclip.h index 9aa38387..36ba0a2a 100644 --- a/src/slideshowclip.h +++ b/src/slideshowclip.h @@ -47,11 +47,14 @@ public: bool fade() const; QString lumaFile() const; int softness() const; + QString animation() const; /** @brief Check if there are several files with filename pattern, like: image_001.jpg, image_002.jpg,... */ static int sequenceCount(KUrl file); /** @brief return the url pattern for selected slideshow. */ static QString selectedPath(KUrl url, bool isMime, QString extension, int *count); + /** @brief Convert the selection animation style into an affine geometry string. */ + static QString animationToGeometry(const QString &animation, int &ttl); private slots: void parseFolder(); diff --git a/src/widgets/clipproperties_ui.ui b/src/widgets/clipproperties_ui.ui index 309822c3..ed169834 100644 --- a/src/widgets/clipproperties_ui.ui +++ b/src/widgets/clipproperties_ui.ui @@ -6,8 +6,8 @@ 0 0 - 302 - 424 + 306 + 478 @@ -392,14 +392,14 @@ - + No image found - + Qt::Vertical @@ -419,6 +419,16 @@ + + + + Animation + + + + + + diff --git a/src/widgets/slideshowclip_ui.ui b/src/widgets/slideshowclip_ui.ui index 97dbdafd..c2b34e2f 100644 --- a/src/widgets/slideshowclip_ui.ui +++ b/src/widgets/slideshowclip_ui.ui @@ -6,8 +6,8 @@ 0 0 - 287 - 453 + 290 + 507 @@ -245,10 +245,10 @@ - + - + @@ -279,7 +279,7 @@ - + Qt::Horizontal @@ -296,6 +296,23 @@ + + + + Animation + + + + + + + + 0 + 0 + + + +