From e5d7ec0b184543b85c9671d6ef072c1cb4437bb6 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Fri, 19 Oct 2012 23:26:44 +0200 Subject: [PATCH] Add automatic scene split (requires MLT patch): http://kdenlive.org/mantis/view.php?id=683 --- src/kdenliveui.rc | 4 +- src/mainwindow.cpp | 34 +++++++++++------ src/mainwindow.h | 2 +- src/projectlist.cpp | 63 ++++++++++++++++++++++++++----- src/projectlist.h | 4 +- src/projecttree/abstractclipjob.h | 1 - src/projecttree/meltjob.cpp | 30 +++++++++++---- src/projecttree/meltjob.h | 8 +++- 8 files changed, 111 insertions(+), 35 deletions(-) diff --git a/src/kdenliveui.rc b/src/kdenliveui.rc index 870d074b..c5bb3d88 100644 --- a/src/kdenliveui.rc +++ b/src/kdenliveui.rc @@ -1,6 +1,6 @@ - + Extra Toolbar @@ -28,7 +28,7 @@ Extract Audio - Stabilize + Clip Jobs Transcode diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5ca55a8a..8a348fb6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -460,7 +460,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & loadPlugins(); loadTranscoders(); - loadStabilize(); + loadClipActions(); m_projectMonitor->setupMenu(static_cast(factory()->container("monitor_go", this)), m_playZone, m_loopZone, NULL, m_loopClip); m_clipMonitor->setupMenu(static_cast(factory()->container("monitor_go", this)), m_playZone, m_loopZone, static_cast(factory()->container("marker_menu", this))); @@ -471,7 +471,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & menus.insert("addMenu",static_cast(factory()->container("generators", this))); menus.insert("extractAudioMenu",static_cast(factory()->container("extract_audio", this))); menus.insert("transcodeMenu",static_cast(factory()->container("transcoders", this))); - menus.insert("stabilizeMenu",static_cast(factory()->container("stabilize", this))); + menus.insert("clipActionsMenu",static_cast(factory()->container("clip_actions", this))); menus.insert("inTimelineMenu",clipInTimeline); m_projectList->setupGeneratorMenu(menus); @@ -2735,7 +2735,7 @@ void MainWindow::updateConfiguration() // Update list of transcoding profiles loadTranscoders(); - loadStabilize(); + loadClipActions(); #ifdef USE_JOGSHUTTLE activateShuttleDevice(); #endif @@ -3887,25 +3887,35 @@ void MainWindow::slotMaximizeCurrent(bool) kDebug() << "CURRENT WIDGET: " << par->objectName(); } -void MainWindow::loadStabilize() +void MainWindow::loadClipActions() { - QMenu* stabMenu= static_cast(factory()->container("stabilize", this)); - if (stabMenu){ - stabMenu->clear(); + QMenu* actionMenu= static_cast(factory()->container("clip_actions", this)); + if (actionMenu){ + actionMenu->clear(); Mlt::Profile profile; - if (Mlt::Factory::filter(profile,(char*)"videostab")){ - QAction *action=stabMenu->addAction("Videostab (vstab)"); + Mlt::Filter *filter = Mlt::Factory::filter(profile,(char*)"videostab"); + if (filter) { + delete filter; + QAction *action=actionMenu->addAction("Videostab (vstab)"); action->setData("videostab"); connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize())); } - if (Mlt::Factory::filter(profile,(char*)"videostab2")){ - QAction *action=stabMenu->addAction("Videostab (transcode)"); + filter = Mlt::Factory::filter(profile,(char*)"videostab2"); + if (filter) { + delete filter; + QAction *action=actionMenu->addAction("Videostab (transcode)"); action->setData("videostab2"); connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize())); } + filter = Mlt::Factory::filter(profile,(char*)"motion_est"); + if (filter) { + delete filter; + QAction *action=actionMenu->addAction("Automatic scene split"); + action->setData("motion_est"); + connect(action,SIGNAL(triggered()), this, SLOT(slotStabilize())); + } } - } void MainWindow::loadTranscoders() diff --git a/src/mainwindow.h b/src/mainwindow.h index 7593c59a..dff7177a 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -305,7 +305,7 @@ private: QStringList m_pluginFileNames; QByteArray m_timelineState; void loadTranscoders(); - void loadStabilize(); + void loadClipActions(); QPixmap createSchemePreviewIcon(const KSharedConfigPtr &config); /** @brief Checks that the Kdenlive mime type is correctly installed. diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 069a5853..bc9c6831 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -425,8 +425,8 @@ void ProjectList::setupGeneratorMenu(const QHash& menus) transcodeMenu->setEnabled(false); m_transcodeAction = transcodeMenu; } - if (menus.contains("stabilizeMenu") && menus.value("stabilizeMenu") ){ - QMenu* stabilizeMenu=menus.value("stabilizeMenu"); + if (menus.contains("clipActionsMenu") && menus.value("clipActionsMenu") ){ + QMenu* stabilizeMenu=menus.value("clipActionsMenu"); m_menu->addMenu(stabilizeMenu); if (stabilizeMenu->isEmpty()) stabilizeMenu->setEnabled(false); @@ -903,7 +903,7 @@ void ProjectList::adjustProxyActions(ProjectItem *clip) const void ProjectList::adjustStabilizeActions(ProjectItem *clip) const { - if (clip == NULL || clip->type() != PROJECTCLIPTYPE || clip->clipType() == COLOR || clip->clipType() == TEXT || clip->clipType() == PLAYLIST || clip->clipType() == SLIDESHOW) { + if (clip == NULL || clip->type() != PROJECTCLIPTYPE || clip->clipType() == COLOR || clip->clipType() == TEXT || clip->clipType() == SLIDESHOW) { m_stabilizeAction->setEnabled(false); return; } @@ -2989,11 +2989,14 @@ void ProjectList::slotProcessJobs() } connect(job, SIGNAL(jobProgress(QString, int, int)), this, SIGNAL(processLog(QString, int, int))); connect(job, SIGNAL(cancelRunningJob(const QString, stringMap)), this, SIGNAL(cancelRunningJob(const QString, stringMap))); - connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap)), this, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap))); if (job->jobType == MLTJOB) { MeltJob *jb = static_cast (job); jb->setProducer(currentClip->getProducer(), currentClip->fileURL()); + if (jb->isProjectFilter()) + connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap)), this, SLOT(slotGotFilterJobResults(QString,int, int, QString,stringMap))); + else + connect(job, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap)), this, SIGNAL(gotFilterJobResults(QString,int, int, QString,stringMap))); } job->startJob(); if (job->jobStatus == JOBDONE) { @@ -3451,14 +3454,31 @@ void ProjectList::startClipFilterJob(const QString &filterName, const QString &c else { destination = item->clipUrl().directory(); } - QPointer d = new ClipStabilize(destination, ids.count(), filterName); - if (d->exec() == QDialog::Accepted) { - processClipJob(ids, d->destination(), d->autoAddClip(), d->params(), d->desc()); + if (filterName == "motion_est") { + // Autosplit filter + QStringList jobParams; + // Producer params + jobParams << QString(); + // Filter params, use a smaller region of the image to speed up operation + jobParams << filterName << "bounding=\"25%x25%:25%x25"; + // Consumer + jobParams << "null" << "all=1 terminate_on_pause=1 real_time=-1"; + // Keys + jobParams << "scene_cuts"; + QStringList extraParams; + extraParams << "projecttreefilter" << "project_profile"; + processClipJob(ids, QString(), false, jobParams, i18n("Auto split"), extraParams); + } + else { + QPointer d = new ClipStabilize(destination, ids.count(), filterName); + if (d->exec() == QDialog::Accepted) { + processClipJob(ids, d->destination(), d->autoAddClip(), d->params(), d->desc()); + } + delete d; } - delete d; } -void ProjectList::processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description) +void ProjectList::processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description, QStringList extraParams) { QStringList preParams; // in and out @@ -3485,12 +3505,13 @@ void ProjectList::processClipJob(QStringList ids, const QString&destination, boo } jobArgs << jobParams; - MeltJob *job = new MeltJob(item->clipType(), id, jobArgs); + MeltJob *job = new MeltJob(item->clipType(), id, jobArgs, extraParams); if (autoAdd) { job->setAddClipToProject(true); kDebug()<<"// ADDING TRUE"; } else kDebug()<<"// ADDING FALSE!!!"; + if (job->isExclusive() && hasPendingJob(item, job->jobType)) { delete job; return; @@ -3551,4 +3572,26 @@ void ProjectList::slotClosePopup() m_errorLog.clear(); } +void ProjectList::slotGotFilterJobResults(QString id, int , int , QString filter, stringMap results) +{ + if (filter == "motion_est") { + // Autosplit filter, add sub zones + QStringList cuts = results.value("scene_cuts").split(':', QString::SkipEmptyParts); + int cutPos = 0; + QUndoCommand *command = new QUndoCommand(); + command->setText(i18n("Auto Split Clip")); + foreach (const QString &pos, cuts) { + int newPos = pos.toInt(); + kDebug()<<"// SCENE CUT: "<childCount() == 0) + delete command; + else m_commandStack->push(command); + } + +} + #include "projectlist.moc" diff --git a/src/projectlist.h b/src/projectlist.h index 8ed251af..8d127722 100644 --- a/src/projectlist.h +++ b/src/projectlist.h @@ -424,7 +424,7 @@ private: /** @brief Get the list of job names for current clip. */ QStringList getPendingJobs(const QString &id); /** @brief Start an MLT process job. */ - void processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description); + void processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description, QStringList extraParams = QStringList()); private slots: void slotClipSelected(); @@ -490,6 +490,8 @@ private slots: void slotResetInfoMessage(); /** @brief close warning info passive popup. */ void slotClosePopup(); + /** @brief process clip job result. */ + void slotGotFilterJobResults(QString ,int , int, QString, stringMap); signals: void clipSelected(DocClipBase *, QPoint zone = QPoint(), bool forceUpdate = false); diff --git a/src/projecttree/abstractclipjob.h b/src/projecttree/abstractclipjob.h index 6123b3e9..ccd862e9 100644 --- a/src/projecttree/abstractclipjob.h +++ b/src/projecttree/abstractclipjob.h @@ -63,7 +63,6 @@ protected: signals: void jobProgress(QString, int, int); void cancelRunningJob(const QString, stringMap); - void gotFilterJobResults(const QString &id, int startPos, int track, const QString &filterName, stringMap params); }; diff --git a/src/projecttree/meltjob.cpp b/src/projecttree/meltjob.cpp index 605ad342..2bf1680b 100644 --- a/src/projecttree/meltjob.cpp +++ b/src/projecttree/meltjob.cpp @@ -35,13 +35,14 @@ static void consumer_frame_render(mlt_consumer, MeltJob * self, mlt_frame /*fram self->emitFrameNumber(); } -MeltJob::MeltJob(CLIPTYPE cType, const QString &id, QStringList parameters) : AbstractClipJob(MLTJOB, cType, id, parameters), +MeltJob::MeltJob(CLIPTYPE cType, const QString &id, QStringList parameters, QStringList extraParams) : AbstractClipJob(MLTJOB, cType, id, parameters), addClipToProject(0), m_producer(NULL), m_profile(NULL), m_consumer(NULL), m_showFrameEvent(NULL), - m_length(0) + m_length(0), + m_extra(extraParams) { jobStatus = JOBWAITING; m_params = parameters; @@ -71,7 +72,6 @@ void MeltJob::startJob() QString filter = m_params.takeFirst(); QString filterParams = m_params.takeFirst(); QString consumer = m_params.takeFirst(); - kDebug()<<"consumer: "<set_explicit(false); + if (m_extra.contains("project_profile")) { + m_profile = new Mlt::Profile(KdenliveSettings::current_profile().toUtf8().constData()); + } + else { + m_profile = new Mlt::Profile; + m_profile->set_explicit(false); + } if (out == -1) { prod = new Mlt::Producer(*m_profile, m_url.toUtf8().constData()); } @@ -102,8 +108,10 @@ void MeltJob::startJob() prod = tmp->cut(in, out); delete tmp; } - m_profile->from_producer(*prod); - m_profile->set_explicit(true); + if (!m_extra.contains("project_profile")) { + m_profile->from_producer(*prod); + m_profile->set_explicit(true); + } QStringList list = producerParams.split(' ', QString::SkipEmptyParts); foreach(const QString &data, list) { if (data.contains('=')) { @@ -126,6 +134,7 @@ void MeltJob::startJob() //m_consumer->set("eof", "pause" ); m_consumer->set("real_time", -KdenliveSettings::mltthreads() ); + list = consumerParams.split(' ', QString::SkipEmptyParts); foreach(const QString &data, list) { if (data.contains('=')) { @@ -210,3 +219,10 @@ void MeltJob::emitFrameNumber() } } +bool MeltJob::isProjectFilter() const +{ + return m_extra.contains("projecttreefilter"); +} + + + diff --git a/src/projecttree/meltjob.h b/src/projecttree/meltjob.h index 8b9e1049..63a34d24 100644 --- a/src/projecttree/meltjob.h +++ b/src/projecttree/meltjob.h @@ -41,7 +41,7 @@ class MeltJob : public AbstractClipJob Q_OBJECT public: - MeltJob(CLIPTYPE cType, const QString &id, QStringList parameters); + MeltJob(CLIPTYPE cType, const QString &id, QStringList parameters, QStringList extraParams = QStringList()); virtual ~ MeltJob(); const QString destination() const; void startJob(); @@ -50,6 +50,8 @@ public: const QString statusMessage(); void setProducer(Mlt::Producer *producer, KUrl url); void emitFrameNumber(); + /** Make the job work on a project tree clip. */ + bool isProjectFilter() const; private: Mlt::Producer *m_producer; @@ -60,6 +62,10 @@ private: QString m_dest; QString m_url; int m_length; + QStringList m_extra; + +signals: + void gotFilterJobResults(const QString &id, int startPos, int track, const QString &filterName, stringMap params); }; #endif -- 2.39.2