]> git.sesse.net Git - kdenlive/commitdiff
Bring back overlay & effects in stopmotion widget, rewrite of decklink capture to...
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Thu, 26 May 2011 08:01:46 +0000 (08:01 +0000)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Thu, 26 May 2011 08:01:46 +0000 (08:01 +0000)
svn path=/trunk/kdenlive/; revision=5608

src/blackmagic/devices.cpp
src/kdenlivesettings.kcfg
src/mltdevicecapture.cpp
src/mltdevicecapture.h
src/recmonitor.cpp
src/stopmotion/stopmotion.cpp
src/stopmotion/stopmotion.h

index 3be150a225a651ee7d9f36c71278a685f4ebbb84..7277c6c3f7dc21306c0864dd491a2c4dd9b854d7 100644 (file)
@@ -48,8 +48,6 @@ bool BMInterface::getBlackMagicDeviceList(KComboBox *devicelist, KComboBox *mode
     while(deckLinkIterator->Next(&deckLink) == S_OK) {
         char *      deviceNameString = NULL;
 
-        // Increment the total number of DeckLink cards found
-        numDevices++;
         //if (numDevices > 1)
         kDebug() << "// FOUND a BM device\n\n+++++++++++++++++++++++++++++++++++++";
 
@@ -119,6 +117,7 @@ bool BMInterface::getBlackMagicDeviceList(KComboBox *devicelist, KComboBox *mode
                 displayMode->Release();
             }
             devicelist->addItem(deviceName, availableModes);
+            devicelist->setItemData(devicelist->count() - 1, numDevices, Qt::UserRole + 1);
             found = true;
         }
 
@@ -133,6 +132,9 @@ bool BMInterface::getBlackMagicDeviceList(KComboBox *devicelist, KComboBox *mode
 
         // Release the IDeckLink instance when we've finished with it to prevent leaks
         deckLink->Release();
+        
+        // Increment the total number of DeckLink cards found
+        numDevices++;
     }
 
     deckLinkIterator->Release();
index a365044383791e86811e2f25fc11bddf207aec69..4172056376cf2f114fe694d8fdcdee3f712e0cf9 100644 (file)
       <default>10</default>
     </entry>
     
-    <entry name="blitzeffect" type="Int">
+    <entry name="stopmotioneffect" type="Int">
       <label>Effect applied to stopmotion frame overlay.</label>
       <default>0</default>
     </entry>
index f36fda0137733d8b4218efde4a03c94e7568222d..070633124b4f40914411c76aa76ebec4f47d970d 100644 (file)
@@ -64,9 +64,9 @@ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, ml
     if (self->sendFrameForAnalysis && frame_ptr->convert_image) {
         self->emitFrameUpdated(frame);
     }
-    if (self->doCapture) {
-        self->doCapture = false;
-        self->saveFrame(frame);
+    if (self->doCapture > 0) {
+        self->doCapture --;
+        if (self->doCapture == 0) self->saveFrame(frame);
     }
 
 /*    if (self->analyseAudio) {
@@ -83,7 +83,7 @@ static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, ml
 
 MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent) :
     AbstractRender(parent),
-    doCapture(false),
+    doCapture(0),
     sendFrameForAnalysis(false),
     m_mltConsumer(NULL),
     m_mltProducer(NULL),
@@ -162,20 +162,18 @@ void MltDeviceCapture::buildConsumer(const QString &profileName)
 
 void MltDeviceCapture::stop()
 {
+    bool isPlaylist = false;
     if (m_mltConsumer) {
+        m_mltConsumer->set("refresh", 0);
         m_mltConsumer->stop();
         //if (!m_mltConsumer->is_stopped()) m_mltConsumer->stop();
-        delete m_mltConsumer;
-        m_mltConsumer = NULL;
     }
-    kDebug()<<"STOPPING cap";
     if (m_mltProducer) {
         QList <Mlt::Producer *> prods;
         Mlt::Service service(m_mltProducer->parent().get_service());
         mlt_service_lock(service.get_service());
-kDebug()<<"STOPPING cap 2";
         if (service.type() == tractor_type) {
-            kDebug()<<"STOPPING cap 3";
+            isPlaylist = true;
             Mlt::Tractor tractor(service);
             mlt_tractor_close(tractor.get_tractor());
             Mlt::Field *field = tractor.field();
@@ -203,7 +201,7 @@ kDebug()<<"STOPPING cap 2";
                         // the video4linux device stays open, seems like a bug in MLT that is not cleaning properly
                         mlt_properties props = MLT_PRODUCER_PROPERTIES(trackPlaylist.get_clip(i)->get_parent());
                         while (mlt_properties_ref_count(props) > 0) mlt_properties_dec_ref(props);
-                        mlt_producer_close(trackPlaylist.get_clip(i)->get_parent());
+                        if (trackPlaylist.get_clip(i)) mlt_producer_close(trackPlaylist.get_clip(i)->get_parent());
                     }
                     mlt_playlist_close(trackPlaylist.get_playlist());
                     //trackPlaylist.clear();
@@ -214,9 +212,11 @@ kDebug()<<"STOPPING cap 2";
         }
         mlt_service_unlock(service.get_service());
         delete m_mltProducer;
-        kDebug()<<"/// STOP REC PROD";
         m_mltProducer = NULL;
     }
+    // For some reason, the consumer seems to be deleted by previous stuff when in playlist mode
+    if (!isPlaylist) delete m_mltConsumer;
+    m_mltConsumer = NULL;
 }
 
 
@@ -277,35 +277,14 @@ void MltDeviceCapture::showAudio(Mlt::Frame& frame)
     }
 }
 
-bool MltDeviceCapture::slotStartPreview(const QString &producer)
+bool MltDeviceCapture::slotStartPreview(const QString &producer, bool xmlFormat)
 {
-    //stop();
     if (m_mltConsumer == NULL) buildConsumer();
-    /*if (m_mltConsumer) delete m_mltConsumer;
-    if (m_mltProducer) delete m_mltProducer;
-    if (m_mltProfile) delete m_mltProfile;
-    
-    char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
-    setenv("MLT_PROFILE", tmp, 1);
-    m_mltProfile = new Mlt::Profile(tmp);
-    delete[] tmp;
-    m_mltProfile->get_profile()->is_explicit = 1;
-
-    m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
-
-    m_mltConsumer->set("window_id", m_winid);
-    m_mltConsumer->set("real_time", 0);
-//    m_mltConsumer->set("buffer", 1);
-    m_mltConsumer->set("resize", 1);
-    m_mltConsumer->set("progressive", 1);
-    m_mltConsumer->set("rescale", "nearest");*/
-    
-    //char *tmp = qstrdup(QString("avformat-novalidate:video4linux2:%1?frame_rate:%2&width:%3&height:%4").arg(KdenliveSettings::video4vdevice()).arg(m_mltProfile->fps()).arg(m_mltProfile->width()).arg(m_mltProfile->height()).toUtf8().constData());
-
     char *tmp = qstrdup(producer.toUtf8().constData());
-    
-    m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp);
+    if (xmlFormat) m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp);
+    else m_mltProducer = new Mlt::Producer(*m_mltProfile, tmp);
     delete[] tmp;
+
     if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
         kDebug()<<"//// ERROR CREATRING PROD";
         return false;
@@ -338,6 +317,13 @@ void MltDeviceCapture::saveFrame(Mlt::Frame& frame)
     const uchar* image = frame.get_image(format, width, height);
     QImage qimage(width, height, QImage::Format_ARGB32);
     memcpy(qimage.bits(), image, width * height * 4);
+
+    // Re-enable overlay
+    Mlt::Service service(m_mltProducer->parent().get_service());
+    Mlt::Tractor tractor(service);
+    Mlt::Producer trackProducer(tractor.track(0));
+    trackProducer.set("hide", 0);
+    
     qimage.rgbSwapped().save(m_capturePath);
     emit frameSaved(m_capturePath);
     m_capturePath.clear();
@@ -345,8 +331,19 @@ void MltDeviceCapture::saveFrame(Mlt::Frame& frame)
 
 void MltDeviceCapture::captureFrame(const QString &path)
 {
+    if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
+
+    // Hide overlay track before doing the capture
+    Mlt::Service service(m_mltProducer->parent().get_service());
+    Mlt::Tractor tractor(service);
+    Mlt::Producer trackProducer(tractor.track(0));
+    mlt_service_lock(service.get_service());
+    trackProducer.set("hide", 1);
+    m_mltConsumer->purge();
+    mlt_service_unlock(service.get_service());
     m_capturePath = path;
-    doCapture = true;
+    // Wait for 5 frames before capture to make sure overlay is gone
+    doCapture = 5;
 }
 
 bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &path, const QString &playlist)
@@ -383,8 +380,6 @@ bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &pa
     
     // FIXME: the event object returned by the listen gets leaked...
     m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_show);
-
-    //tmp = qstrdup(QString("avformat-novalidate:video4linux2:%1?frame_rate:%2&width:%3&height:%4").arg(KdenliveSettings::video4vdevice()).arg(m_mltProfile->fps()).arg(m_mltProfile->width()).arg(m_mltProfile->height()).toUtf8().constData());
     tmp = qstrdup(playlist.toUtf8().constData());
     m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", tmp);
     delete[] tmp;
@@ -404,3 +399,138 @@ bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &pa
 }
 
 
+void MltDeviceCapture::setOverlay(const QString &path)
+{
+    if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
+    Mlt::Producer parentProd(m_mltProducer->parent());
+    if (parentProd.get_producer() == NULL) {
+        kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
+        return;
+    }
+
+    Mlt::Service service(parentProd.get_service());
+    if (service.type() != tractor_type) {
+        kWarning() << "// TRACTOR PROBLEM";
+        return;
+    }
+    Mlt::Tractor tractor(service);
+    if ( tractor.count() < 2) {
+        kWarning() << "// TRACTOR PROBLEM";
+        return;
+    }
+    mlt_service_lock(service.get_service());
+    Mlt::Producer trackProducer(tractor.track(0));
+    Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+
+    trackPlaylist.remove(0);
+    if (path.isEmpty()) {
+        mlt_service_unlock(service.get_service());
+        return;
+    }
+
+    // Add overlay clip
+    char *tmp = qstrdup(path.toUtf8().constData());
+    Mlt::Producer *clip = new Mlt::Producer (*m_mltProfile, "loader", tmp);
+    delete[] tmp;
+    clip->set_in_and_out(0, 99999);
+    trackPlaylist.insert_at(0, clip, 1);
+
+    // Add transition
+    mlt_service serv = m_mltProducer->parent().get_service();
+    mlt_service nextservice = mlt_service_get_producer(serv);
+    mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice);
+    QString mlt_type = mlt_properties_get(properties, "mlt_type");
+    if (mlt_type != "transition") {
+        // transition does not exist, add it
+        Mlt::Field *field = tractor.field();
+        Mlt::Transition *transition = new Mlt::Transition(*m_mltProfile, "composite");
+        transition->set_in_and_out(0, 0);
+        transition->set("geometry", "0,0:100%x100%:70");
+        transition->set("fill", 1);
+        transition->set("operator", "and");
+        transition->set("a_track", 0);
+        transition->set("b_track", 1);
+        field->plant_transition(*transition, 0, 1);
+    }
+    mlt_service_unlock(service.get_service());
+    //delete clip;
+}
+
+void MltDeviceCapture::setOverlayEffect(const QString tag, QStringList parameters)
+{
+    if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
+    Mlt::Service service(m_mltProducer->parent().get_service());
+    Mlt::Tractor tractor(service);
+    Mlt::Producer trackProducer(tractor.track(0));
+    Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+    Mlt::Service trackService(trackProducer.get_service());
+
+    mlt_service_lock(service.get_service());
+
+    // delete previous effects
+    Mlt::Filter *filter;
+    filter = trackService.filter(0);
+    if (filter && !tag.isEmpty()) {
+        QString currentService = filter->get("mlt_service");
+        if (currentService == tag) {
+            // Effect is already there
+            mlt_service_unlock(service.get_service());
+            return;
+        }
+    }
+    while (filter) {
+        trackService.detach(*filter);
+        delete filter;
+        filter = trackService.filter(0);
+    }
+    
+    if (tag.isEmpty()) {
+        mlt_service_unlock(service.get_service());
+        return;
+    }
+    
+    char *tmp = qstrdup(tag.toUtf8().constData());
+    filter = new Mlt::Filter(*m_mltProfile, tmp);
+    delete[] tmp;
+    if (filter && filter->is_valid()) {
+        for (int j = 0; j < parameters.count(); j++) {
+            filter->set(parameters.at(j).section("=", 0, 0).toUtf8().constData(), parameters.at(j).section("=", 1, 1).toUtf8().constData());
+        }
+        trackService.attach(*filter);
+    }
+    mlt_service_unlock(service.get_service());
+}
+
+void MltDeviceCapture::mirror(bool activate)
+{
+    if (m_mltProducer == NULL || !m_mltProducer->is_valid()) return;
+    Mlt::Service service(m_mltProducer->parent().get_service());
+    Mlt::Tractor tractor(service);
+    Mlt::Producer trackProducer(tractor.track(1));
+    Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+    Mlt::Service trackService(trackProducer.get_service());
+
+    mlt_service_lock(service.get_service());
+
+    // delete previous effects
+    Mlt::Filter *filter;
+    filter = trackService.filter(0);
+    while (filter) {
+        trackService.detach(*filter);
+        delete filter;
+        filter = trackService.filter(0);
+    }
+
+    if (!activate) {
+        mlt_service_unlock(service.get_service());
+        return;
+    }
+
+    filter = new Mlt::Filter(*m_mltProfile, "mirror");
+    if (filter && filter->is_valid()) {
+        filter->set("mirror", "flip");
+        trackService.attach(*filter);
+    }
+    mlt_service_unlock(service.get_service());
+}
+
index 461c8295f75e599e68c71db33a45b7f1374374ff..da341ebc29d399c2502f2136378ba8f99d31cc99 100644 (file)
@@ -57,7 +57,7 @@ Q_OBJECT public:
     /** @brief Destroy the MLT Renderer. */
     ~MltDeviceCapture();
 
-    bool doCapture;
+    int doCapture;
 
     /** @brief This property is used to decide if the renderer should convert it's frames to QImage for use in other Kdenlive widgets. */
     bool sendFrameForAnalysis;
@@ -77,12 +77,20 @@ Q_OBJECT public:
      * @param surface The widget onto which the frame should be painted
      */
     bool slotStartCapture(const QString &params, const QString &path, const QString &playlist);
-    bool slotStartPreview(const QString &producer);
+    bool slotStartPreview(const QString &producer, bool xmlFormat = false);
     /** @brief A frame arrived from the MLT Video4Linux process. */
     void gotCapturedFrame(Mlt::Frame& frame);
     /** @brief Save current frame to file. */
     void captureFrame(const QString &path);
     void doRefresh();
+    /** @brief This will add the video clip from path and add it in the overlay track. */
+    void setOverlay(const QString &path);
+
+    /** @brief This will add an MLT video effect to the overlay track. */
+    void setOverlayEffect(const QString tag, QStringList parameters);
+
+    /** @brief This will add a horizontal flip effect, easier to work when filming yourself. */
+    void mirror(bool activate);
 
 private:
     Mlt::Consumer * m_mltConsumer;
index ba38afcbe1a262ebf0706c8709ca30fac3a3ce03..1e239b49a5e271bce0c4a9e8e0fc87f02b44e4dc 100644 (file)
@@ -211,8 +211,8 @@ void RecMonitor::slotVideoDeviceChanged(int ix)
     if (m_captureDevice) {
         // MLT capture still running, abort
         m_captureDevice->stop();
-        //delete m_captureDevice;
-        //m_captureDevice = NULL;
+        delete m_captureDevice;
+        m_captureDevice = NULL;
     }
     switch (ix) {
     case SCREENGRAB:
@@ -240,8 +240,8 @@ void RecMonitor::slotVideoDeviceChanged(int ix)
         checkDeviceAvailability();
         break;
     case BLACKMAGIC:
-        createBlackmagicDevice();
-        m_recAction->setEnabled(false);
+        //createBlackmagicDevice();
+        m_recAction->setEnabled(true);
         m_stopAction->setEnabled(false);
         m_playAction->setEnabled(true);
 
@@ -399,10 +399,13 @@ void RecMonitor::slotStopCapture()
         QTimer::singleShot(1000, m_captureProcess, SLOT(kill()));
         break;
     case BLACKMAGIC:
-        m_bmCapture->stopPreview();
+        if (m_captureDevice) {
+            m_captureDevice->stop();
+        }
+        //m_bmCapture->stopPreview();
         m_playAction->setEnabled(true);
         m_stopAction->setEnabled(false);
-        m_recAction->setEnabled(false);
+        m_recAction->setEnabled(true);
         break;
     default:
         break;
@@ -434,8 +437,8 @@ void RecMonitor::slotStartCapture(bool play)
     MltVideoProfile profile;
     QString producer;
     QStringList dvargs = KdenliveSettings::dvgrabextra().simplified().split(" ", QString::SkipEmptyParts);
-    video_capture->setVisible(device_selector->currentIndex() == BLACKMAGIC);
-    video_frame->setHidden(device_selector->currentIndex() == BLACKMAGIC);
+    //video_capture->setVisible(device_selector->currentIndex() == BLACKMAGIC);
+    //video_frame->setHidden(device_selector->currentIndex() == BLACKMAGIC);
 
     switch (device_selector->currentIndex()) {
     case FIREWIRE:
@@ -509,7 +512,26 @@ void RecMonitor::slotStartCapture(bool play)
         m_captureProcess->start("ffmpeg", m_captureArgs);*/
         break;
     case BLACKMAGIC:
-        m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode());
+        path = KdenliveSettings::current_profile();
+        m_manager->activateMonitor("record");
+        if (m_captureDevice == NULL) {
+            m_captureDevice = new MltDeviceCapture(path, m_videoBox, this);
+            m_captureDevice->sendFrameForAnalysis = m_analyse;
+            m_manager->updateScopeSource();
+        }
+        profile = ProfilesDialog::getVideoProfile(path);
+        producer = QString("decklink:%1").arg(KdenliveSettings::hdmi_capturedevice());
+        if (!m_captureDevice->slotStartPreview(producer)) {
+            // v4l capture failed to start
+            video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters..."));
+            m_videoBox->setHidden(true);
+            
+        } else {
+            m_videoBox->setHidden(false);
+            m_playAction->setEnabled(false);
+            m_stopAction->setEnabled(true);
+        }
+        //m_bmCapture->startPreview(KdenliveSettings::hdmi_capturedevice(), KdenliveSettings::hdmi_capturemode());
         m_playAction->setEnabled(false);
         m_stopAction->setEnabled(true);
         m_recAction->setEnabled(true);
@@ -529,7 +551,7 @@ void RecMonitor::slotStartCapture(bool play)
 
 void RecMonitor::slotRecord()
 {
-    if (device_selector->currentIndex() == BLACKMAGIC) {
+    /*if (device_selector->currentIndex() == BLACKMAGIC) {
         if (m_blackmagicCapturing) {
             // We are capturing, stop it
             m_bmCapture->stopCapture();
@@ -543,7 +565,7 @@ void RecMonitor::slotRecord()
             m_blackmagicCapturing = true;
         }
         return;
-    }
+    }*/
 
     if (m_captureProcess->state() == QProcess::NotRunning && device_selector->currentIndex() == FIREWIRE) {
         slotStartCapture();
@@ -651,6 +673,30 @@ void RecMonitor::slotRecord()
             kDebug() << "Capture: Running ffmpeg " << m_captureArgs.join(" ");
             m_captureProcess->start("ffmpeg", m_captureArgs);*/
             break;
+            
+        case BLACKMAGIC:
+            path = KdenliveSettings::current_profile();
+            profile = ProfilesDialog::getVideoProfile(path);
+            if (m_captureDevice == NULL) {
+                m_captureDevice = new MltDeviceCapture(path, m_videoBox, this);
+                m_captureDevice->sendFrameForAnalysis = m_analyse;
+                m_manager->updateScopeSource();
+            }
+               
+            playlist = QString("<producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">%1</property><property name=\"mlt_service\">decklink</property></producer>").arg(KdenliveSettings::hdmi_capturedevice());
+
+            if (m_captureDevice->slotStartCapture(KdenliveSettings::v4l_parameters(), m_captureFile.path(), playlist)) {
+                m_videoBox->setHidden(false);
+                m_isCapturing = true;
+            }
+            else {
+                video_frame->setText(i18n("Failed to start Decklink,\ncheck your parameters..."));                
+                m_videoBox->setHidden(true);
+                m_isCapturing = false;
+                m_recAction->setChecked(false);
+            }
+            break;
+            
         case SCREENGRAB:
             switch (KdenliveSettings::rmd_capture_type()) {
             case 0:
index c93a15acae959f0dde0656cabfe7f2d8027844e0..28ce8a89443c94cdb376e6391ed24bce32674df7 100644 (file)
 #include <kdeversion.h>
 #include <KNotification>
 
-#ifdef QIMAGEBLITZ
-#include <qimageblitz/qimageblitz.h>
-#endif
-
 #include <QtConcurrentRun>
 #include <QInputDialog>
 #include <QComboBox>
@@ -150,6 +146,12 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     analyse->setCheckable(true);
     analyse->setChecked(KdenliveSettings::analyse_stopmotion());
     connect(analyse, SIGNAL(triggered(bool)), this, SLOT(slotSwitchAnalyse(bool)));
+
+    QAction* mirror = new QAction(i18n("Mirror display"), this);
+    mirror->setCheckable(true);
+    //mirror->setChecked(KdenliveSettings::analyse_stopmotion());
+    connect(mirror, SIGNAL(triggered(bool)), this, SLOT(slotSwitchMirror(bool)));
+
     addActions(actions);
     setupUi(this);
     setWindowTitle(i18n("Stop Motion Capture"));
@@ -182,22 +184,21 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     overlay_button->setDefaultAction(m_showOverlay);
     //confMenu->addAction(m_showOverlay);
 
-#ifdef QIMAGEBLITZ
-    m_effectIndex = KdenliveSettings::blitzeffect();
+    m_effectIndex = KdenliveSettings::stopmotioneffect();    
     QMenu* effectsMenu = new QMenu(i18n("Overlay effect"));
     QActionGroup* effectGroup = new QActionGroup(this);
     QAction* noEffect = new QAction(i18n("No Effect"), effectGroup);
-    noEffect->setData(1);
+    noEffect->setData(0);
     QAction* contrastEffect = new QAction(i18n("Contrast"), effectGroup);
-    contrastEffect->setData(2);
+    contrastEffect->setData(1);
     QAction* edgeEffect = new QAction(i18n("Edge detect"), effectGroup);
-    edgeEffect->setData(3);
+    edgeEffect->setData(2);
     QAction* brightEffect = new QAction(i18n("Brighten"), effectGroup);
-    brightEffect->setData(4);
+    brightEffect->setData(3);
     QAction* invertEffect = new QAction(i18n("Invert"), effectGroup);
-    invertEffect->setData(5);
+    invertEffect->setData(4);
     QAction* thresEffect = new QAction(i18n("Threshold"), effectGroup);
-    thresEffect->setData(6);
+    thresEffect->setData(5);
 
     effectsMenu->addAction(noEffect);
     effectsMenu->addAction(contrastEffect);
@@ -214,7 +215,6 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     }
     connect(effectsMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotUpdateOverlayEffect(QAction*)));
     confMenu->addMenu(effectsMenu);
-#endif
 
     QAction* showThumbs = new QAction(KIcon("image-x-generic"), i18n("Show sequence thumbnails"), this);
     showThumbs->setCheckable(true);
@@ -231,6 +231,7 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     confMenu->addAction(showThumbs);
     confMenu->addAction(removeCurrent);
     confMenu->addAction(analyse);
+    confMenu->addAction(mirror);
     confMenu->addAction(conf);
     config_button->setIcon(KIcon("configure"));
     config_button->setMenu(confMenu);
@@ -252,8 +253,6 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     
     if (BMInterface::getBlackMagicDeviceList(capture_device, NULL)) {
         // Found a BlackMagic device
-        //m_bmCapture = new BmdCaptureHandler(m_layout);
-        //connect(m_bmCapture, SIGNAL(gotMessage(const QString&)), this, SLOT(slotGotHDMIMessage(const QString&)));
     }
     if (QFile::exists(KdenliveSettings::video4vdevice())) {
 #if !defined(Q_WS_MAC) && !defined(Q_OS_FREEBSD)
@@ -270,17 +269,10 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
                 }
             }
         }
-
-        //if (m_bmCapture == NULL) {
-            
-            //m_captureDevice->sendFrameForAnalysis = m_analyse;
-            /*m_bmCapture = new V4lCaptureHandler(m_layout);
-            m_bmCapture->setDevice(capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString(), capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 2).toString());*/
-        //}
 #endif
     }
 
-    connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateHandler()));
+    connect(capture_device, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateDeviceHandler()));
     /*if (m_bmCapture) {
         connect(m_bmCapture, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString)));
         connect(m_bmCapture, SIGNAL(gotFrame(QImage)), this, SIGNAL(gotFrame(QImage)));
@@ -294,9 +286,19 @@ StopmotionWidget::StopmotionWidget(MonitorManager *manager, KUrl projectFolder,
     video_preview->setLayout(layout);
 
     //kDebug()<<video_preview->winId();
+
+    QString profilePath;
+    // Create MLT producer data
+    if (capture_device->itemData(capture_device->currentIndex()) == "v4l") {
+        // Capture using a video4linux device
+        profilePath = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
+    }
+    else {
+        // Decklink capture
+        profilePath = KdenliveSettings::current_profile();
+    }
     
-    QString path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
-    m_captureDevice = new MltDeviceCapture(path, m_videoBox, this);
+    m_captureDevice = new MltDeviceCapture(profilePath, m_videoBox, this);
     m_captureDevice->sendFrameForAnalysis = KdenliveSettings::analyse_stopmotion();
     m_monitor->setRender(m_captureDevice);
     connect(m_captureDevice, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString)));
@@ -335,11 +337,9 @@ StopmotionWidget::~StopmotionWidget()
 
 void StopmotionWidget::slotUpdateOverlayEffect(QAction* act)
 {
-#ifdef QIMAGEBLITZ
     if (act) m_effectIndex = act->data().toInt();
-    KdenliveSettings::setBlitzeffect(m_effectIndex);
-    if (m_showOverlay->isChecked()) slotUpdateOverlay();
-#endif
+    KdenliveSettings::setStopmotioneffect(m_effectIndex);
+    slotUpdateOverlay();
 }
 
 void StopmotionWidget::closeEvent(QCloseEvent* e)
@@ -387,8 +387,11 @@ void StopmotionWidget::slotShowThumbs(bool show)
 }
 
 
-void StopmotionWidget::slotUpdateHandler()
+void StopmotionWidget::slotUpdateDeviceHandler()
 {
+    slotLive(false);
+    delete m_captureDevice;
+    m_captureDevice = NULL;
     /*QString data = capture_device->itemData(capture_device->currentIndex()).toString();
     slotLive(false);
     if (m_bmCapture) {
@@ -457,21 +460,42 @@ void StopmotionWidget::slotLive(bool isOn)
     if (isOn) {
         m_frame_preview->setHidden(true);
         m_videoBox->setHidden(false);
-        QString path = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
 
-        kDebug()<<"SURFACE; "<<m_videoBox->width()<<"x"<<m_videoBox->height();
+        MltVideoProfile profile;
+        QString resource;
+        QString service;
+        QString profilePath;
+        // Create MLT producer data
+        if (capture_device->itemData(capture_device->currentIndex()) == "v4l") {
+            // Capture using a video4linux device
+            profilePath = KStandardDirs::locateLocal("appdata", "profiles/video4linux");
+            profile = ProfilesDialog::getVideoProfile(profilePath);
+            service = "avformat-novalidate";
+            QString devicePath = capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString();
+            resource = QString("video4linux2:%1?width:%2&amp;height:%3&amp;frame_rate:%4").arg(devicePath).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den);
+        }
+        else {
+            // Decklink capture
+            profilePath = KdenliveSettings::current_profile();
+            profile = ProfilesDialog::getVideoProfile(profilePath);
+            service = "decklink";
+            resource = capture_device->itemData(capture_device->currentIndex(), Qt::UserRole + 1).toString();
+        }
+
         if (m_captureDevice == NULL) {
-            m_captureDevice = new MltDeviceCapture(path, m_videoBox, this);
+            m_captureDevice = new MltDeviceCapture(profilePath, m_videoBox, this);
             m_captureDevice->sendFrameForAnalysis = KdenliveSettings::analyse_stopmotion();
             m_monitor->setRender(m_captureDevice);
             connect(m_captureDevice, SIGNAL(frameSaved(const QString)), this, SLOT(slotNewThumb(const QString)));
         }
-
-        MltVideoProfile profile = ProfilesDialog::getVideoProfile(path);
+        
         m_manager->activateMonitor("stopmotion");
-        QString producer = QString("avformat-novalidate:video4linux2:%1?width:%2&height:%3&frame_rate:%4").arg(KdenliveSettings::video4vdevice()).arg(profile.width).arg(profile.height).arg((double) profile.frame_rate_num / profile.frame_rate_den);
-        if (m_captureDevice->slotStartPreview(producer)) {
-            kDebug()<<"// STARt CAPTURE GO";
+        QString producer = createProducer(profile, service, resource);
+        if (m_captureDevice->slotStartPreview(producer, true)) {
+            if (m_showOverlay->isChecked()) {
+                reloadOverlay();
+                slotUpdateOverlay();
+            }
             capture_button->setEnabled(true);
             live_button->setChecked(true);
             log_box->insertItem(-1, i18n("Playing %1x%2 (%3 fps)", profile.width, profile.height, QString::number((double)profile.frame_rate_num/profile.frame_rate_den).rightJustified(2, '0')));
@@ -512,53 +536,62 @@ void StopmotionWidget::slotLive(bool isOn)
     live_button->blockSignals(false);
 }
 
-void StopmotionWidget::slotShowOverlay(bool /*isOn*/)
+void StopmotionWidget::slotShowOverlay(bool isOn)
 {
-/*    if (isOn) {
-        if (live_button->isChecked() && m_sequenceFrame > 0) {
-            slotUpdateOverlay();
-        }
-    } else if (m_bmCapture) {
-        m_bmCapture->hideOverlay();
-    }*/
+    if (isOn) {
+        // Overlay last frame of the sequence
+        reloadOverlay();
+        slotUpdateOverlay();
+    }
+    else {
+        // Remove overlay
+        m_captureDevice->setOverlay(QString());
+    }
 }
 
-void StopmotionWidget::slotUpdateOverlay()
+void StopmotionWidget::reloadOverlay()
 {
-    if (m_captureDevice == NULL) return;
     QString path = getPathForFrame(m_sequenceFrame - 1);
-    if (!QFile::exists(path)) return;
-    QImage img(path);
-    if (img.isNull()) {
-        QTimer::singleShot(1000, this, SLOT(slotUpdateOverlay()));
+    if (!QFile::exists(path)) {
+        log_box->insertItem(-1, i18n("No previous frame found"));
+        log_box->setCurrentIndex(0);
         return;
     }
+    m_captureDevice->setOverlay(path);
+}
+
+void StopmotionWidget::slotUpdateOverlay()
+{
+    if (m_captureDevice == NULL) return;
+
+    QString tag;
+    QStringList params;
 
-#ifdef QIMAGEBLITZ
-    //img = Blitz::convolveEdge(img, 0, Blitz::Low);
     switch (m_effectIndex) {
+    case 1:
+        tag = "frei0r.contrast0r";
+        params << "Contrast=1.2";
+        break;
     case 2:
-        img = Blitz::contrast(img, true, 6);
+        tag = "charcoal";
+        params << "x_scatter=4" << "y_scatter=4" << "scale=1" << "mix=0";
         break;
     case 3:
-        img = Blitz::edge(img);
+        tag = "frei0r.brightness";
+        params << "Brightness=0.7";
         break;
     case 4:
-        img = Blitz::intensity(img, 0.5);
+        tag = "invert";
         break;
     case 5:
-        Blitz::invert(img);
-        break;
-    case 6:
-        img = Blitz::threshold(img, 120, Blitz::Grayscale, qRgba(0, 0, 0, 0), qRgba(255, 0, 0, 255));
-        //img = Blitz::flatten(img, QColor(255, 0, 0, 255), QColor(0, 0, 0, 0));
+        tag = "threshold";
+        params << "midpoint=125";
         break;
     default:
         break;
 
     }
-#endif
-    //m_bmCapture->showOverlay(img);
+    m_captureDevice->setOverlayEffect(tag, params);
 }
 
 void StopmotionWidget::sequenceNameChanged(const QString& name)
@@ -633,8 +666,9 @@ void StopmotionWidget::slotNewThumb(const QString path)
 {
     if (!KdenliveSettings::showstopmotionthumbs()) return;
     m_filesList.append(path);
-    if (m_showOverlay->isChecked()) slotUpdateOverlay();
+    if (m_showOverlay->isChecked()) reloadOverlay();
     if (!m_future.isRunning()) m_future = QtConcurrent::run(this, &StopmotionWidget::slotPrepareThumbs);
+    
 }
 
 void StopmotionWidget::slotPrepareThumbs()
@@ -839,7 +873,33 @@ void StopmotionWidget::slotSwitchAnalyse(bool isOn)
 {
     KdenliveSettings::setAnalyse_stopmotion(isOn);
     if (m_captureDevice) m_captureDevice->sendFrameForAnalysis = isOn;
-    //m_bmCapture->setAnalyse(isOn);
 }
 
+void StopmotionWidget::slotSwitchMirror(bool isOn)
+{
+    //KdenliveSettings::setAnalyse_stopmotion(isOn);
+    if (m_captureDevice) m_captureDevice->mirror(isOn);
+}
+
+const QString StopmotionWidget::createProducer(MltVideoProfile profile, const QString service, const QString resource)
+{   
+    
+    QString playlist = "<mlt title=\"capture\"><producer id=\"producer0\" in=\"0\" out=\"99999\"><property name=\"mlt_type\">producer</property><property name=\"length\">100000</property><property name=\"eof\">pause</property><property name=\"resource\">" + resource + "</property><property name=\"mlt_service\">" + service + "</property></producer>";
+
+    // overlay track
+    playlist.append("<playlist id=\"playlist0\"></playlist>");
+
+    // video4linux track
+    playlist.append("<playlist id=\"playlist1\"><entry producer=\"producer0\" in=\"0\" out=\"99999\"/></playlist>");
+
+    playlist.append("<tractor id=\"tractor0\" title=\"video0\" global_feed=\"1\" in=\"0\" out=\"99999\">");
+    playlist.append("<track producer=\"playlist0\"/>");
+    playlist.append("<track producer=\"playlist1\"/>");
+    playlist.append("</tractor></mlt>");
+
+    
+    return playlist;
+}
+
+
 
index dcdfa39e79124948b67041af7e755b563b9fd93e..98636f3688609cde3fc343004b761502e8dfe6eb 100644 (file)
@@ -31,6 +31,7 @@
 class MltDeviceCapture;
 class MonitorManager;
 class VideoPreviewContainer;
+class MltVideoProfile;
 
 class MyLabel : public QLabel
 {
@@ -103,8 +104,6 @@ private:
     MltDeviceCapture *m_captureDevice;
 
     VideoPreviewContainer *m_videoBox;
-    
-    //CaptureHandler* m_bmCapture;
 
     /** @brief Holds the name of the current sequence.
      * Files will be saved in project folder with name: sequence001.png */
@@ -150,8 +149,15 @@ private:
 
     MonitorManager *m_manager;
 
+    /** @brief The monitor is used to control the v4l capture device from the monitormanager class. */
     StopmotionMonitor *m_monitor;
 
+    /** @brief Create the XML playlist. */
+    const QString createProducer(MltVideoProfile profile, const QString service, const QString resource);
+
+    /** @brief A new frame arrived, reload overlay. */
+    void reloadOverlay();
+
 
 #ifdef QIMAGEBLITZ
     int m_effectIndex;
@@ -212,7 +218,7 @@ private slots:
     void slotPrepareThumbs();
 
     /** @brief Called when user switches the video capture backend. */
-    void slotUpdateHandler();
+    void slotUpdateDeviceHandler();
 
     /** @brief Show / hide sequence thumbnails. */
     void slotShowThumbs(bool show);
@@ -234,6 +240,9 @@ private slots:
     
     /** @brief Enable / disable frame analysis (in color scopes). */
     void slotSwitchAnalyse(bool isOn);
+
+    /** @brief Enable / disable horizontal mirror effect. */
+    void slotSwitchMirror(bool isOn);
     
     /** @brief Send a notification a few seconds before capturing. */
     void slotPreNotify();