From af20dd7143d1889c1424349b666bd51353cc6924 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Thu, 12 Apr 2012 21:29:48 +0200 Subject: [PATCH] Several fixes for region effect --- src/effectstack/effectstackview2.cpp | 43 +++++----- src/effectstack/effectstackview2.h | 3 + src/kdenliveui.rc | 9 ++- src/mainwindow.cpp | 19 ++++- src/mainwindow.h | 2 + src/renderer.cpp | 115 +++++++++++++++++++-------- src/renderer.h | 4 + 7 files changed, 136 insertions(+), 59 deletions(-) diff --git a/src/effectstack/effectstackview2.cpp b/src/effectstack/effectstackview2.cpp index dc09c99e..27f77f42 100644 --- a/src/effectstack/effectstackview2.cpp +++ b/src/effectstack/effectstackview2.cpp @@ -225,26 +225,7 @@ void EffectStackView2::setupListView() } else { vbox1->addWidget(currentEffect); } - - // Check drag & drop - currentEffect->installEventFilter( this ); - - connect(currentEffect, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this , SLOT(slotUpdateEffectParams(const QDomElement, const QDomElement, int))); - connect(currentEffect, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this , SLOT(slotStartFilterJob(QString,QString,QString,QString,QString,QString))); - connect(currentEffect, SIGNAL(deleteEffect(const QDomElement)), this , SLOT(slotDeleteEffect(const QDomElement))); - connect(currentEffect, SIGNAL(reloadEffects()), this , SIGNAL(reloadEffects())); - connect(currentEffect, SIGNAL(resetEffect(int)), this , SLOT(slotResetEffect(int))); - connect(currentEffect, SIGNAL(changeEffectPosition(int,bool)), this , SLOT(slotMoveEffectUp(int , bool))); - connect(currentEffect, SIGNAL(effectStateChanged(bool,int,bool)), this, SLOT(slotUpdateEffectState(bool,int,bool))); - connect(currentEffect, SIGNAL(activateEffect(int)), this, SLOT(slotSetCurrentEffect(int))); - connect(currentEffect, SIGNAL(checkMonitorPosition(int)), this, SLOT(slotCheckMonitorPosition(int))); - connect(currentEffect, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int))); - connect(currentEffect, SIGNAL(createGroup(int)), this , SLOT(slotCreateGroup(int))); - connect(currentEffect, SIGNAL(moveEffect(int,int,int,QString)), this , SLOT(slotMoveEffect(int,int,int,QString))); - connect(currentEffect, SIGNAL(addEffect(QDomElement)), this , SLOT(slotAddEffect(QDomElement))); - connect(currentEffect, SIGNAL(createRegion(int,KUrl)), this, SLOT(slotCreateRegion(int,KUrl))); - - //ui.title->setPixmap(icon.pixmap(QSize(12, 12))); + connectEffect(currentEffect); } vbox1->addStretch(10); slotUpdateCheckAllButton(); @@ -254,6 +235,25 @@ void EffectStackView2::setupListView() QTimer::singleShot(200, this, SLOT(slotCheckWheelEventFilter())); } +void EffectStackView2::connectEffect(CollapsibleEffect *currentEffect) +{ + // Check drag & drop + currentEffect->installEventFilter( this ); + connect(currentEffect, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this , SLOT(slotUpdateEffectParams(const QDomElement, const QDomElement, int))); + connect(currentEffect, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this , SLOT(slotStartFilterJob(QString,QString,QString,QString,QString,QString))); + connect(currentEffect, SIGNAL(deleteEffect(const QDomElement)), this , SLOT(slotDeleteEffect(const QDomElement))); + connect(currentEffect, SIGNAL(reloadEffects()), this , SIGNAL(reloadEffects())); + connect(currentEffect, SIGNAL(resetEffect(int)), this , SLOT(slotResetEffect(int))); + connect(currentEffect, SIGNAL(changeEffectPosition(int,bool)), this , SLOT(slotMoveEffectUp(int , bool))); + connect(currentEffect, SIGNAL(effectStateChanged(bool,int,bool)), this, SLOT(slotUpdateEffectState(bool,int,bool))); + connect(currentEffect, SIGNAL(activateEffect(int)), this, SLOT(slotSetCurrentEffect(int))); + connect(currentEffect, SIGNAL(checkMonitorPosition(int)), this, SLOT(slotCheckMonitorPosition(int))); + connect(currentEffect, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int))); + connect(currentEffect, SIGNAL(createGroup(int)), this , SLOT(slotCreateGroup(int))); + connect(currentEffect, SIGNAL(moveEffect(int,int,int,QString)), this , SLOT(slotMoveEffect(int,int,int,QString))); + connect(currentEffect, SIGNAL(addEffect(QDomElement)), this , SLOT(slotAddEffect(QDomElement))); + connect(currentEffect, SIGNAL(createRegion(int,KUrl)), this, SLOT(slotCreateRegion(int,KUrl))); +} void EffectStackView2::slotCheckWheelEventFilter() { @@ -660,7 +660,8 @@ void EffectStackView2::slotCreateRegion(int ix, KUrl url) m_currentEffectList.insert(region); current->deleteLater(); CollapsibleEffect *currentEffect = new CollapsibleEffect(region, m_currentEffectList.itemFromIndex(ix), info, &m_effectMetaInfo, ix == m_currentEffectList.count() - 1, m_ui.container->widget()); - connect(currentEffect, SIGNAL(parameterChanged(const QDomElement, const QDomElement, int)), this , SLOT(slotUpdateEffectParams(const QDomElement, const QDomElement, int))); + connectEffect(currentEffect); + if (m_effectMetaInfo.trackMode) { isSelected = currentEffect->effectIndex() == 1; } diff --git a/src/effectstack/effectstackview2.h b/src/effectstack/effectstackview2.h index 1c4b5e68..2a1da032 100644 --- a/src/effectstack/effectstackview2.h +++ b/src/effectstack/effectstackview2.h @@ -107,6 +107,9 @@ private: /** @brief Build the drag info and start it. */ void startDrag(); + + /** @brief Connect an effect to its signals. */ + void connectEffect(CollapsibleEffect *currentEffect); public slots: /** @brief Sets the clip whose effect list should be managed. diff --git a/src/kdenliveui.rc b/src/kdenliveui.rc index 1cb088d4..c6b393fb 100644 --- a/src/kdenliveui.rc +++ b/src/kdenliveui.rc @@ -100,9 +100,12 @@ - - - + Current clip + + + + + Guides diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 409dfaa9..d03ff48f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -538,7 +538,6 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_timelineContextClipMenu->addAction(actionCollection()->action("clip_in_project_tree")); //m_timelineContextClipMenu->addAction(actionCollection()->action("clip_to_project_tree")); - m_timelineContextClipMenu->addAction(actionCollection()->action("edit_item_duration")); m_timelineContextClipMenu->addAction(actionCollection()->action("delete_item")); m_timelineContextClipMenu->addSeparator(); m_timelineContextClipMenu->addAction(actionCollection()->action("group_clip")); @@ -556,7 +555,6 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_timelineContextClipMenu->addMenu(m_transitionsMenu); m_timelineContextClipMenu->addMenu(m_effectsMenu); - m_timelineContextTransitionMenu->addAction(actionCollection()->action("edit_item_duration")); m_timelineContextTransitionMenu->addAction(actionCollection()->action("delete_item")); m_timelineContextTransitionMenu->addAction(actionCollection()->action(KStandardAction::name(KStandardAction::Copy))); @@ -1393,6 +1391,10 @@ void MainWindow::setupActions() KAction* editItemDuration = new KAction(KIcon("measure"), i18n("Edit Duration"), this); collection.addAction("edit_item_duration", editItemDuration); connect(editItemDuration, SIGNAL(triggered(bool)), this, SLOT(slotEditItemDuration())); + + KAction* saveTimelineClip = new KAction(KIcon("document-save"), i18n("Save clip"), this); + collection.addAction("save_timeline_clip", saveTimelineClip); + connect(saveTimelineClip, SIGNAL(triggered(bool)), this, SLOT(slotSaveTimelineClip())); KAction* clipInProjectTree = new KAction(KIcon("go-jump-definition"), i18n("Clip in Project Tree"), this); collection.addAction("clip_in_project_tree", clipInProjectTree); @@ -4446,6 +4448,19 @@ void MainWindow::slotChangePalette() } } +void MainWindow::slotSaveTimelineClip() +{ + if (m_activeTimeline && m_projectMonitor->render) { + ClipItem *clip = m_activeTimeline->projectView()->getActiveClipUnderCursor(true); + if (!clip) { + m_messageLabel->setMessage(i18n("Select a clip to save"), InformationMessage); + return; + } + KUrl url = KFileDialog::getSaveUrl(m_activeDocument->projectFolder(), "video/mlt-playlist"); + if (!url.isEmpty()) m_projectMonitor->render->saveClip(m_activeDocument->tracksCount() - clip->track(), clip->startPos(), url); + } +} + #include "mainwindow.moc" diff --git a/src/mainwindow.h b/src/mainwindow.h index c54a2325..3b33dad7 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -554,6 +554,8 @@ private slots: void slotDownloadResources(); void slotChangePalette(); + /** @brief Save current timeline clip as mlt playlist. */ + void slotSaveTimelineClip(); signals: Q_SCRIPTABLE void abortRenderJob(const QString &url); diff --git a/src/renderer.cpp b/src/renderer.cpp index 14927a75..a0b2c610 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -1320,6 +1320,34 @@ void Render::saveZone(KUrl url, QString desc, QPoint zone) xmlConsumer.start(); } + +bool Render::saveClip(int track, GenTime position, KUrl url, QString desc) +{ + // find clip + Mlt::Service service(m_mltProducer->parent().get_service()); + Mlt::Tractor tractor(service); + Mlt::Producer trackProducer(tractor.track(track)); + Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); + + int clipIndex = trackPlaylist.get_clip_index_at((int) position.frames(m_fps)); + Mlt::Producer *clip = trackPlaylist.get_clip(clipIndex); + if (!clip) { + kDebug() << "WARINIG, CANNOT FIND CLIP ON track: " << track << ", AT POS: " << position.frames(m_fps); + return false; + } + + Mlt::Consumer xmlConsumer(*m_mltProfile, ("xml:" + url.path()).toUtf8().constData()); + xmlConsumer.set("terminate_on_pause", 1); + Mlt::Playlist list; + list.insert_at(0, clip, 0); + //delete clip; + list.set("title", desc.toUtf8().constData()); + xmlConsumer.connect(list); + xmlConsumer.run(); + kDebug()<<"// SAVED: "<set("kdenlive_ix", filter->get_int("kdenlive_ix") + 1); + service.attach(*filter); + } + service.unlock(); + if (doRefresh) refresh(); + return true; +} + + +bool Render::addFilterToService(Mlt::Service service, EffectsParameterList params, int duration) +{ + // create filter QString tag = params.paramValue("tag"); //kDebug() << " / / INSERTING EFFECT: " << tag << ", REGI: " << region; char *filterTag = qstrdup(tag.toUtf8().constData()); char *filterId = qstrdup(params.paramValue("id").toUtf8().constData()); - QHash::Iterator it; QString kfr = params.paramValue("keyframes"); - - if (!kfr.isEmpty()) { + if (!kfr.isEmpty()) { QStringList keyFrames = kfr.split(';', QString::SkipEmptyParts); //kDebug() << "// ADDING KEYFRAME EFFECT: " << params.paramValue("keyframes"); char *starttag = qstrdup(params.paramValue("starttag", "start").toUtf8().constData()); @@ -2645,20 +2687,9 @@ bool Render::mltAddEffect(Mlt::Service service, EffectsParameterList params, int } else { Mlt::Filter *filter; QString prefix; - if (!region.isEmpty()) { - filter = new Mlt::Filter(*m_mltProfile, "region"); - } else filter = new Mlt::Filter(*m_mltProfile, filterTag); + filter = new Mlt::Filter(*m_mltProfile, filterTag); if (filter && filter->is_valid()) { filter->set("kdenlive_id", filterId); - if (!region.isEmpty()) { - filter->set("resource", region.toUtf8().constData()); - filter->set("kdenlive_ix", params.paramValue("kdenlive_ix").toUtf8().constData()); - filter->set("filter0", filterTag); - prefix = "filter0."; - params.removeParam("id"); - params.removeParam("region"); - params.removeParam("kdenlive_ix"); - } } else { kDebug() << "filter is NULL"; service.unlock(); @@ -2690,22 +2721,12 @@ bool Render::mltAddEffect(Mlt::Service service, EffectsParameterList params, int //kDebug() << "SOX EFFECTS: " << effectArgs.simplified(); filter->set("effect", effectArgs.simplified().toUtf8().constData()); } - // attach filter to the clip service.attach(*filter); } + delete[] filterId; delete[] filterTag; - - // re-add following filters - for (int i = 0; i < filtersList.count(); i++) { - Mlt::Filter *filter = filtersList.at(i); - if (updateIndex) - filter->set("kdenlive_ix", filter->get_int("kdenlive_ix") + 1); - service.attach(*filter); - } - service.unlock(); - if (doRefresh) refresh(); return true; } @@ -2755,7 +2776,7 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par int index = params.paramValue("kdenlive_ix").toInt(); QString tag = params.paramValue("tag"); - if (!params.paramValue("keyframes").isEmpty() || (tag == "affine" && params.hasParam("background")) || tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle" || params.hasParam("region")) { + if (!params.paramValue("keyframes").isEmpty() || (tag == "affine" && params.hasParam("background")) || tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle") { // This is a keyframe effect, to edit it, we remove it and re-add it. bool success = mltRemoveEffect(track, position, index, false); // if (!success) kDebug() << "// ERROR Removing effect : " << index; @@ -2806,17 +2827,45 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par bool success = mltAddEffect(track, position, params); return success; } - QString prefix; + ct = 0; QString ser = filter->get("mlt_service"); - if (ser == "region") prefix = "filter0."; + QList filtersList; + service.lock(); + if (ser != tag) { + // Effect service changes, delete effect and re-add it + clip->detach(*filter); + + // Delete all effects after deleted one + filter = clip->filter(ct); + while (filter) { + if (filter->get_int("kdenlive_ix") > index) { + filtersList.append(filter); + clip->detach(*filter); + } + else ct++; + filter = clip->filter(ct); + } + + // re-add filter + addFilterToService(*clip, params, clip->get_playtime()); + delete clip; + service.unlock(); + + if (doRefresh) refresh(); + return true; + } if (params.hasParam("_sync_in_out")) { // This effect must sync in / out with parent clip params.removeParam("_sync_in_out"); filter->set_in_and_out(clip->get_in(), clip->get_out()); } - service.lock(); + for (int j = 0; j < params.count(); j++) { - filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData()); + filter->set((params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData()); + } + + for (int j = 0; j < filtersList.count(); j++) { + clip->attach(*(filtersList.at(j))); } delete clip; diff --git a/src/renderer.h b/src/renderer.h index c71f4b6a..cd81010e 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -155,6 +155,9 @@ Q_OBJECT public: void loopZone(const GenTime & startTime, const GenTime & stopTime); void saveZone(KUrl url, QString desc, QPoint zone); + + /** @brief Save a clip in timeline to an xml playlist. */ + bool saveClip(int track, GenTime position, KUrl url, QString desc = QString()); /** @brief Returns the speed at which the renderer is currently playing. * @@ -223,6 +226,7 @@ Q_OBJECT public: /** @brief Adds an effect to a clip in MLT's playlist. */ bool mltAddEffect(int track, GenTime position, EffectsParameterList params, bool doRefresh = true); + bool addFilterToService(Mlt::Service service, EffectsParameterList params, int duration); bool mltAddEffect(Mlt::Service service, EffectsParameterList params, int duration, bool doRefresh); bool mltAddTrackEffect(int track, EffectsParameterList params); -- 2.39.2