]> git.sesse.net Git - kdenlive/commitdiff
Introduce MLT clip analysis, can now be used for getting auto normalize data in sox...
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Thu, 29 Dec 2011 15:57:06 +0000 (16:57 +0100)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Thu, 29 Dec 2011 15:57:06 +0000 (16:57 +0100)
12 files changed:
effects/sox_gain.xml
src/customtrackview.cpp
src/customtrackview.h
src/effectstackedit.cpp
src/effectstackedit.h
src/effectstackview.cpp
src/effectstackview.h
src/mainwindow.cpp
src/projectlist.cpp
src/projectlist.h
src/projecttree/abstractclipjob.h
src/projecttree/meltjob.cpp

index d43f91ee782591634ecfb7ca65459ff878f9d286..4a0e5adb4cae45384b27dd8121e3ddc3c7a4b68d 100644 (file)
@@ -3,7 +3,10 @@
        <name>Sox Gain</name>
        <description>Sox gain audio effect</description>
        <author>http://sox.sourceforge.net</author>
-       <parameter type="constant" name="gain" max="50" min="-50" default="5">
+       <parameter type="double" name="gain" max="50" min="-50" default="5.00" decimals="2">
                <name>Gain</name>
        </parameter>
+       <parameter type="filterjob" filtertag="sox:analysis" filterparams="" consumer="null" consumerparams="video_off=1 all=1" wantedproperties="gain" finalfilter="sox_gain">
+               <name>Normalize</name>
+       </parameter>
 </effect>
index 1ec88d5c336df1ffb746452ff8a21eaa6868bc0b..fd6d7084f35dbf459208f2017e3c79b01c1dd2bb 100644 (file)
@@ -1896,7 +1896,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
         return;
     }
     QDomElement effect = insertedEffect.cloneNode().toElement();
-    //kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", TRACK: "<<track;
+    //kDebug() << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", GAIN: "<<EffectsList::parameter(effect, "gain");
     if (pos < GenTime()) {
         // editing a track effect
         EffectsParameterList effectParams = getEffectArgs(effect);
@@ -1964,6 +1964,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
                 emit clipItemSelected(clip, ix);
         }
     }
+    else emit displayMessage(i18n("Cannot find clip to update effect"), ErrorMessage);
     setDocumentModified();
 }
 
@@ -6748,3 +6749,28 @@ void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoComma
 }
 
 
+void CustomTrackView::slotGotFilterJobResults(const QString &id, int startPos, int track, const QString &filter, stringMap filterParams)
+{
+    ClipItem *clip = getClipItemAt(GenTime(startPos, m_document->fps()), track);
+    if (clip == NULL) {
+        emit displayMessage(i18n("Cannot find clip for effect update %1.", filter), ErrorMessage);
+        return;
+    }
+    QDomElement newEffect;
+    QDomElement effect = clip->getEffectAt(clip->selectedEffectIndex());
+    if (effect.attribute("id") == filter) {
+        newEffect = effect.cloneNode().toElement();
+        QMap<QString, QString>::const_iterator i = filterParams.constBegin();
+        while (i != filterParams.constEnd()) {
+            EffectsList::setParameter(newEffect, i.key(), i.value());
+            kDebug()<<"// RESULT FILTER: "<<i.key()<<"="<< i.value();
+            ++i;
+        }
+        EditEffectCommand *command = new EditEffectCommand(this, m_document->tracksCount() - clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true);
+        m_commandStack->push(command);
+        emit clipItemSelected(clip, clip->selectedEffectIndex());
+    }
+    
+}
+
+
index dea6e8dff27962e817a146836f779b59bb6a2124..747d490b60d1889ee88527d569e2a8e23c951274 100644 (file)
@@ -451,6 +451,8 @@ private slots:
      *  @param id The clip's Id string.
      *  @param resetThumbs Should we recreate the timeline thumbnails. */
     void slotRefreshThumbs(const QString &id, bool resetThumbs);
+    /** @brief A Filter job producer results. */
+    void slotGotFilterJobResults(const QString &id, int startPos, int track, const QString &filter, stringMap filterParams);
 
 signals:
     void cursorMoved(int, int);
index c274a8f81398f51363b19457f3aba4fddeed6d23..2f3d1d8d16f61bd45ba771281832b3eb0d7d267b 100644 (file)
@@ -910,7 +910,7 @@ void EffectStackEdit::slotStartFilterJobAction()
         QDomElement pa = namenode.item(i).toElement();
         QString type = pa.attribute("type");
         if (type == "filterjob") {
-            emit startFilterJob(pa.attribute("filtertag"), pa.attribute("filterparams"), pa.attribute("consumer"), pa.attribute("consumerparams"), pa.attribute("wantedproperties"));
+            emit startFilterJob(pa.attribute("filtertag"), pa.attribute("filterparams"), pa.attribute("finalfilter"), pa.attribute("consumer"), pa.attribute("consumerparams"), pa.attribute("wantedproperties"));
             kDebug()<<" - - -PROPS:\n"<<pa.attribute("filtertag")<<"-"<< pa.attribute("filterparams")<<"-"<< pa.attribute("consumer")<<"-"<< pa.attribute("consumerparams")<<"-"<< pa.attribute("wantedproperties");
             break;
         }
index 645672d62322c5d66574155cdaee6e26fb84b099..73f117ecd709628ac14ff4712bf4ef8827721e68 100644 (file)
@@ -109,7 +109,7 @@ signals:
     void showComments(bool show);
     void effectStateChanged(bool enabled);
     /** @brief Start an MLT filter job on this clip. */
-    void startFilterJob(const QString &filterName, const QString &filterParams, const QString &consumer, const QString &consumerParams, const QString &properties);
+    void startFilterJob(const QString &filterName, const QString &filterParams, const QString &finalFilterName, const QString &consumer, const QString &consumerParams, const QString &properties);
 };
 
 #endif
index 2c7b41cb6b9a9bb296e7093b9e1545543800319a..9a5911cb1b22b1473f1102600845a60010209890 100644 (file)
@@ -92,10 +92,11 @@ EffectStackView::EffectStackView(Monitor *monitor, QWidget *parent) :
     connect(m_ui.checkAll, SIGNAL(stateChanged(int)), this, SLOT(slotCheckAll(int)));
     connect(m_ui.buttonShowComments, SIGNAL(clicked()), this, SLOT(slotShowComments()));
     connect(m_effectedit, SIGNAL(parameterChanged(const QDomElement &, const QDomElement &)), this , SLOT(slotUpdateEffectParams(const QDomElement &, const QDomElement &)));
-    connect(m_effectedit, SIGNAL(startFilterJob(QString,QString,QString,QString,QString)), this , SLOT(slotStartFilterJob(QString,QString,QString,QString,QString)));
+    connect(m_effectedit, SIGNAL(startFilterJob(QString,QString,QString,QString,QString,QString)), this , SLOT(slotStartFilterJob(QString,QString,QString,QString,QString,QString)));
     connect(m_effectedit, SIGNAL(seekTimeline(int)), this , SLOT(slotSeekTimeline(int)));
     connect(m_effectedit, SIGNAL(displayMessage(const QString&, int)), this, SIGNAL(displayMessage(const QString&, int)));
     connect(m_effectedit, SIGNAL(checkMonitorPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
+    
     connect(monitor, SIGNAL(renderPosition(int)), this, SLOT(slotRenderPos(int)));
     connect(this, SIGNAL(showComments(bool)), m_effectedit, SIGNAL(showComments(bool)));
     m_effectLists["audio"] = &MainWindow::audioEffects;
@@ -529,10 +530,10 @@ void EffectStackView::slotShowComments()
     emit showComments(m_ui.buttonShowComments->isChecked());
 }
 
-void EffectStackView::slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&consumer, const QString&consumerParams, const QString&properties)
+void EffectStackView::slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties)
 {
     if (!m_clipref) return;
-    emit startFilterJob(m_clipref->clipProducer(), filterName, filterParams, consumer, consumerParams, properties);
+    emit startFilterJob(m_clipref->info(), m_clipref->clipProducer(), filterName, filterParams, finalFilterName, consumer, consumerParams, properties);
 }
 
 #include "effectstackview.moc"
index e3412bd45fcee53996366f622c243a380dae5ed8..c2a4e2bda28866259ccc36d3fd880f394d498f64 100644 (file)
@@ -143,7 +143,7 @@ private slots:
     void slotShowComments();
     
     /** @brief Triggers a filter job on this clip. */
-    void slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&consumer, const QString&consumerParams, const QString&properties);
+    void slotStartFilterJob(const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties);
 
 signals:
     void removeEffect(ClipItem*, int, QDomElement);
@@ -164,7 +164,7 @@ signals:
     void updateClipRegion(ClipItem*, int, QString);
     void displayMessage(const QString&, int);
     void showComments(bool show);
-    void startFilterJob(const QString &clipId, const QString &filterName, const QString &filterParams, const QString &consumer, const QString &consumerParams, const QString &properties);
+    void startFilterJob(ItemInfo info, const QString &clipId, const QString &filterName, const QString &filterParams, const QString&finalFilterName, const QString &consumer, const QString &consumerParams, const QString &properties);
 };
 
 #endif
index 164d5fe5fef5f0a57a0c7ce609fe4cd090a02c9f..72d3897eda9c5ac151461f3afd46567c3ed8f9ff 100644 (file)
@@ -269,7 +269,7 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString &
     m_effectStack = new EffectStackView(m_projectMonitor);
     m_effectStackDock->setWidget(m_effectStack);
     addDockWidget(Qt::TopDockWidgetArea, m_effectStackDock);
-    connect(m_effectStack, SIGNAL(startFilterJob(const QString&,const QString&,const QString&,const QString&,const QString&,const QString&)), m_projectList, SLOT(slotStartFilterJob(const QString&,const QString&,const QString&,const QString&,const QString&,const QString&)));
+    connect(m_effectStack, SIGNAL(startFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QString&)), m_projectList, SLOT(slotStartFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QString&)));
 
     m_transitionConfigDock = new QDockWidget(i18n("Transition"), this);
     m_transitionConfigDock->setObjectName("transition");
@@ -2488,6 +2488,8 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
             disconnect(m_activeTimeline->projectView(), SIGNAL(playMonitor()), m_projectMonitor, SLOT(slotPlay()));
             disconnect(m_activeTimeline->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType)));
             disconnect(m_activeTimeline->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, bool, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, bool, const int)));
+            disconnect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), m_activeTimeline->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap)));
+            
             disconnect(m_activeTimeline, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor()));
             disconnect(m_activeTimeline, SIGNAL(insertTrack(int)), this, SLOT(slotInsertTrack(int)));
             disconnect(m_activeTimeline, SIGNAL(deleteTrack(int)), this, SLOT(slotDeleteTrack(int)));
@@ -2568,6 +2570,8 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc)   //cha
 
     connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(ClipItem*)));
     connect(trackView->projectView(), SIGNAL(transitionItemSelected(Transition*, int, QPoint, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(Transition*)));
+    
+    connect(m_projectList, SIGNAL(gotFilterJobResults(const QString &, int, int, const QString &, stringMap)), trackView->projectView(), SLOT(slotGotFilterJobResults(const QString &, int, int, const QString &, stringMap)));
 
     connect(m_effectStack, SIGNAL(updateEffect(ClipItem*, int, QDomElement, QDomElement, int)), trackView->projectView(), SLOT(slotUpdateClipEffect(ClipItem*, int, QDomElement, QDomElement, int)));
     connect(m_effectStack, SIGNAL(updateClipRegion(ClipItem*, int, QString)), trackView->projectView(), SLOT(slotUpdateClipRegion(ClipItem*, int, QString)));
index fb481bd7366856523a4daa7cac6decc10d64baad..bfbfd78a1495cc738847fb30ddad150eebd52739 100644 (file)
@@ -2832,6 +2832,7 @@ 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);
@@ -3247,13 +3248,13 @@ void ProjectList::discardJobs(const QString &id, JOBTYPE type) {
     }
 }
 
-void ProjectList::slotStartFilterJob(const QString&id, const QString&filterName, const QString&filterParams, const QString&consumer, const QString&consumerParams, const QString&properties)
+void ProjectList::slotStartFilterJob(ItemInfo info, const QString&id, const QString&filterName, const QString&filterParams, const QString&finalFilterName, const QString&consumer, const QString&consumerParams, const QString&properties)
 {
     ProjectItem *item = getItemById(id);
     if (!item) return;
     QStringList jobParams;
-    jobParams << filterName << filterParams << consumer << consumerParams << properties;
-    kDebug()<<"// STARTING JOB: "<<jobParams;
+    jobParams << QString::number(info.cropStart.frames(m_fps)) << QString::number((info.cropStart + info.cropDuration).frames(m_fps));
+    jobParams << filterName << filterParams << consumer << consumerParams << properties << QString::number(info.startPos.frames(m_fps)) << QString::number(info.track) << finalFilterName;
     MeltJob *job = new MeltJob(item->clipType(), id, jobParams);
     if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
         delete job;
index 1fb55de7b18b34d8b19144b1e2409e14954aebfc..785cbff593ca294a53133873c99ddf29a2645f9f 100644 (file)
@@ -303,7 +303,7 @@ public slots:
     void slotCutClipJob(const QString &id, QPoint zone);
     void slotTranscodeClipJob(QStringList ids, QString params, QString desc);
     /** @brief Start an MLT process job. */
-    void slotStartFilterJob(const QString&,const QString&,const QString&,const QString&,const QString&,const QString&);
+    void slotStartFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QString&);
 
 private:
     ProjectListView *m_listView;
@@ -483,6 +483,8 @@ signals:
     void updateJobStatus(const QString, int, int, const QString &label = QString(), const QString &actionName = QString(), const QString details = QString());
     void gotProxy(const QString);
     void checkJobProcess();
+    /** @brief A Filter Job produced results, send them back to the clip. */
+    void gotFilterJobResults(const QString &id, int startPos, int track, const QString &filterName, stringMap params);
 };
 
 #endif
index 26c46a6ddaa2118b93a6c78eb3f67f560a9d3bbf..fdd049c8d082d92bcf3d90a189b56ba078c13131 100644 (file)
@@ -59,6 +59,7 @@ 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 7e239e206f8ce20a65a753736a61442d96de9262..97fe61690150d94d56f4a467b2c00a4afa3c320b 100644 (file)
@@ -57,11 +57,25 @@ void MeltJob::startJob()
         setStatus(JOBCRASHED);
         return;
     }
+    int in = m_params.takeFirst().toInt();
+    int out = m_params.takeFirst().toInt();
     QString filter = m_params.takeFirst();
     QString filterParams = m_params.takeFirst();
     QString consumer = m_params.takeFirst();
     QString consumerParams = m_params.takeFirst();
     QString properties = m_params.takeFirst();
+    int startPos = m_params.takeFirst().toInt();
+    int track = m_params.takeFirst().toInt();
+    QString finalFilter;
+    if (!m_params.isEmpty()) finalFilter = m_params.takeFirst();
+    else finalFilter = filter;
+
+    if (out <= in) {
+        m_errorMessage.append(i18n("Clip zone undefined (%1 - %2).", in, out));
+        setStatus(JOBCRASHED);
+        return;
+    }
+    Mlt::Producer *prod = m_producer->cut(in, out);
     m_profile = m_producer->profile();
     m_consumer = new Mlt::Consumer(*m_profile, consumer.toUtf8().constData());
     if (!m_consumer || !m_consumer->is_valid()) {
@@ -88,25 +102,29 @@ void MeltJob::startJob()
             mltFilter.set(data.section('=', 0, 0).toUtf8().constData(), data.section('=', 1, 1).toUtf8().constData());
         }
     }
-    m_producer->attach(mltFilter);
-    m_length = m_producer->get_length();
-    m_consumer->connect(*m_producer);
-    m_producer->set_speed(0);
-    m_producer->seek(0);
+    prod->attach(mltFilter);
+    m_length = prod->get_length();
+    m_consumer->connect(*prod);
+    prod->set_speed(0);
+    prod->seek(0);
     m_showFrameEvent = m_consumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_render);
     m_consumer->start();
-    m_producer->set_speed(1);
+    prod->set_speed(1);
     while (jobStatus != JOBABORTED && !m_consumer->is_stopped()) {
         
     }
     m_consumer->stop();
     QStringList wanted = properties.split(',', QString::SkipEmptyParts);
+    stringMap jobResults;
     foreach(const QString key, wanted) {
         QString value = mltFilter.get(key.toUtf8().constData());
+        jobResults.insert(key, value);
         kDebug()<<"RESULT: "<<key<<" = "<< value;
     }
+    if (!jobResults.isEmpty()) emit gotFilterJobResults(m_clipId, startPos, track, finalFilter, jobResults);
     setStatus(JOBDONE);
     delete m_consumer;
+    delete prod;
     return;
 }