]> git.sesse.net Git - kdenlive/commitdiff
Add automatic scene split (requires MLT patch): http://kdenlive.org/mantis/view.php...
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Fri, 19 Oct 2012 21:26:44 +0000 (23:26 +0200)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Fri, 19 Oct 2012 21:26:44 +0000 (23:26 +0200)
src/kdenliveui.rc
src/mainwindow.cpp
src/mainwindow.h
src/projectlist.cpp
src/projectlist.h
src/projecttree/abstractclipjob.h
src/projecttree/meltjob.cpp
src/projecttree/meltjob.h

index 870d074bbf9d678ae209363a70e9dcd3ca9550ae..c5bb3d88f5d70bd5f9979ba24aee3fdf499d4453 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<gui name="kdenlive" version="69">
+<gui name="kdenlive" version="72">
   <ToolBar name="extraToolBar" >
     <text>Extra Toolbar</text>
        <Action name="project_render" />
@@ -28,7 +28,7 @@
       <Action name="download_resource" /> 
       <Menu name="extract_audio" ><text>Extract Audio</text>
       </Menu>
-      <Menu name="stabilize" ><text>Stabilize</text>
+      <Menu name="clip_actions" ><text>Clip Jobs</text>
       </Menu>
       <Menu name="transcoders" ><text>Transcode</text>
       </Menu>
index 5ca55a8a4bcd2bcebf776e61e60529b920fd638d..8a348fb6ea174119b6716d3dcb66dbca5de6ef4e 100644 (file)
@@ -460,7 +460,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
 
     loadPlugins();
     loadTranscoders();
-    loadStabilize();
+    loadClipActions();
 
     m_projectMonitor->setupMenu(static_cast<QMenu*>(factory()->container("monitor_go", this)), m_playZone, m_loopZone, NULL, m_loopClip);
     m_clipMonitor->setupMenu(static_cast<QMenu*>(factory()->container("monitor_go", this)), m_playZone, m_loopZone, static_cast<QMenu*>(factory()->container("marker_menu", this)));
@@ -471,7 +471,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
        menus.insert("addMenu",static_cast<QMenu*>(factory()->container("generators", this)));
         menus.insert("extractAudioMenu",static_cast<QMenu*>(factory()->container("extract_audio", this)));
        menus.insert("transcodeMenu",static_cast<QMenu*>(factory()->container("transcoders", this)));
-       menus.insert("stabilizeMenu",static_cast<QMenu*>(factory()->container("stabilize", this)));
+       menus.insert("clipActionsMenu",static_cast<QMenu*>(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<QMenu*>(factory()->container("stabilize", this));
-       if (stabMenu){
-               stabMenu->clear();
+       QMenu* actionMenu= static_cast<QMenu*>(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()
index 7593c59a9c81871ecffd6362ddaa3d665af577ac..dff7177a77a4b7159de30a56387e54b6022d6278 100644 (file)
@@ -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.
index 069a58539a7c1e24e41139e63327d8ffe090efcb..bc9c68311716c23c6f2bd492e78f4af45ae932e5 100644 (file)
@@ -425,8 +425,8 @@ void ProjectList::setupGeneratorMenu(const QHash<QString,QMenu*>& 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<MeltJob *> (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<ClipStabilize> 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<ClipStabilize> 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: "<<cutPos<<" - "<<newPos;
+           if (newPos - cutPos < 24) continue;
+           (void) new AddClipCutCommand(this, id, cutPos, newPos, QString(), true, false, command);
+           cutPos = newPos;
+       }
+       if (command->childCount() == 0)
+           delete command;
+       else m_commandStack->push(command);
+    }
+    
+}
+
 #include "projectlist.moc"
index 8ed251afc507455e7f1a3c9b11f2090a3a7199d6..8d127722f90b60cfa286ec334abe360533162d77 100644 (file)
@@ -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);
index 6123b3e975d04a01a1aaf222181eb7729974cde8..ccd862e99e26c219da79f72eef4c5c5af3ebe164 100644 (file)
@@ -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);
 };
 
 
index 605ad342709f14e2c9c0c6446ff19997d9ebc144..2bf1680b036124559a62ae56bb7e69c4865eeb14 100644 (file)
@@ -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: "<<consumer;
     if (consumer.contains(':')) m_dest = consumer.section(':', 1);
     QString consumerParams = m_params.takeFirst();
     
@@ -86,14 +86,20 @@ void MeltJob::startJob()
     if (!m_params.isEmpty()) finalFilter = m_params.takeFirst();
     else finalFilter = filter;
 
+
     if (out != -1 && out <= in) {
         m_errorMessage.append(i18n("Clip zone undefined (%1 - %2).", in, out));
         setStatus(JOBCRASHED);
         return;
     }
     Mlt::Producer *prod ;
-    m_profile = new Mlt::Profile;
-    m_profile->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");
+}
+
+
+
index 8b9e1049f12e6eff204e4e9a1869e69e9ff9e1de..63a34d24b4e5c21b693d037d58c2d0b5f81c7803 100644 (file)
@@ -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