]> git.sesse.net Git - kdenlive/blobdiff - src/mltdevicecapture.cpp
Const'ref
[kdenlive] / src / mltdevicecapture.cpp
index f36fda0137733d8b4218efde4a03c94e7568222d..425b81a6be28fedec74bc74e1f07a14197f3a1a0 100644 (file)
@@ -19,9 +19,6 @@
 #include "mltdevicecapture.h"
 #include "kdenlivesettings.h"
 #include "definitions.h"
-//#include "recmonitor.h"
-//#include "renderer.h"
-#include "blackmagic/devices.h"
 
 #include <mlt++/Mlt.h>
 
@@ -35,6 +32,8 @@
 #include <QDir>
 #include <QString>
 #include <QApplication>
+#include <QThread>
+#include <QTimer>
 
 #include <cstdlib>
 #include <cstdarg>
@@ -50,12 +49,12 @@ static void consumer_gl_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_fr
     self->showFrame(frame);
 }
 
-static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
+/*static void rec_consumer_frame_show(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
 {
     Mlt::Frame frame(frame_ptr);
     if (!frame.is_valid()) return;
     self->gotCapturedFrame(frame);
-}
+}*/
 
 static void rec_consumer_frame_preview(mlt_consumer, MltDeviceCapture * self, mlt_frame frame_ptr)
 {
@@ -64,36 +63,42 @@ 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) {
+    //TODO: connect record monitor to audio scopes
+    
+    if (self->analyseAudio) {
         self->showAudio(frame);
     }
-    if (frame.get_double("_speed") == 0.0) {
-        self->emitConsumerStopped();
-    } else if (frame.get_double("_speed") < 0.0 && mlt_frame_get_position(frame_ptr) <= 0) {
-        self->pause();
-        self->emitConsumerStopped();
-    }*/
+    
 }
 
 
-MltDeviceCapture::MltDeviceCapture(QString profile, VideoPreviewContainer *surface, QWidget *parent) :
-    AbstractRender(parent),
-    doCapture(false),
+MltDeviceCapture::MltDeviceCapture(QString profile, VideoSurface *surface, QWidget *parent) :
+    AbstractRender(Kdenlive::recordMonitor, parent),
+    doCapture(0),
     sendFrameForAnalysis(false),
+    processingImage(false),
     m_mltConsumer(NULL),
     m_mltProducer(NULL),
     m_mltProfile(NULL),
-    m_captureDisplayWidget(surface),
-    m_winid((int) surface->winId()),
-    m_analyseAudio(KdenliveSettings::monitor_audio())
+    m_showFrameEvent(NULL),
+    m_droppedFrames(0),
+    m_livePreview(KdenliveSettings::enable_recording_preview()),
+    m_winid((int) surface->winId())
 {
-    if (profile.isEmpty()) profile = KdenliveSettings::current_profile();
+    m_captureDisplayWidget = surface;
+    analyseAudio = KdenliveSettings::monitor_audio();
+    if (profile.isEmpty())
+        profile = KdenliveSettings::current_profile();
     buildConsumer(profile);
+    connect(this, SIGNAL(unblockPreview()), this, SLOT(slotPreparePreview()));
+    m_droppedFramesTimer.setSingleShot(false);
+    m_droppedFramesTimer.setInterval(1000);
+    connect(&m_droppedFramesTimer, SIGNAL(timeout()), this, SLOT(slotCheckDroppedFrames()));
 }
 
 MltDeviceCapture::~MltDeviceCapture()
@@ -112,7 +117,7 @@ void MltDeviceCapture::buildConsumer(const QString &profileName)
     char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
     setenv("MLT_PROFILE", tmp, 1);
     m_mltProfile = new Mlt::Profile(tmp);
-    m_mltProfile->get_profile()->is_explicit = 1;
+    m_mltProfile->set_explicit(true);
     delete[] tmp;
 
     QString videoDriver = KdenliveSettings::videodrivername();
@@ -125,23 +130,23 @@ void MltDeviceCapture::buildConsumer(const QString &profileName)
         }
     }
     setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
-
+    
+  
     if (m_winid == 0) {
         // OpenGL monitor
         m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_audio");
         m_mltConsumer->set("preview_off", 1);
-        m_mltConsumer->set("preview_format", mlt_image_rgb24a);
-        m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
+        m_mltConsumer->set("preview_format", mlt_image_rgb24);
+        m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
     } else {
         m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
         m_mltConsumer->set("window_id", m_winid);
+        m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
     }
-    m_mltConsumer->set("resize", 1);
+    //m_mltConsumer->set("resize", 1);
     //m_mltConsumer->set("terminate_on_pause", 1);
     m_mltConsumer->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
-    m_mltConsumer->set("rescale", "nearest");
-    
-    m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
+    //m_mltConsumer->set("rescale", "nearest");
 
     QString audioDevice = KdenliveSettings::audiodevicename();
     if (!audioDevice.isEmpty())
@@ -155,27 +160,42 @@ void MltDeviceCapture::buildConsumer(const QString &profileName)
     if (!audioDriver.isEmpty())
         m_mltConsumer->set("audio_driver", audioDriver.toUtf8().constData());
 
-    //m_mltConsumer->set("progressive", 1);
+    //m_mltConsumer->set("progressive", 0);
     //m_mltConsumer->set("buffer", 1);
     //m_mltConsumer->set("real_time", 0);
 }
 
+void MltDeviceCapture::pause()
+{   
+    if (m_mltConsumer) {
+          m_mltConsumer->set("refresh", 0);
+         //m_mltProducer->set_speed(0.0);
+         m_mltConsumer->purge();
+    }
+}
+
 void MltDeviceCapture::stop()
 {
+    m_droppedFramesTimer.stop();
+    bool isPlaylist = false;
+    //disconnect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
+    //m_captureDisplayWidget->stop();
+    
+    if (m_showFrameEvent) delete m_showFrameEvent;
+    m_showFrameEvent = NULL;
+    
     if (m_mltConsumer) {
-        m_mltConsumer->stop();
+        m_mltConsumer->set("refresh", 0);
+        m_mltConsumer->purge();
+       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();
@@ -194,59 +214,66 @@ kDebug()<<"STOPPING cap 2";
                 mlt_type = mlt_properties_get(properties, "mlt_type");
                 resource = mlt_properties_get(properties, "mlt_service");
             }
-            for (int trackNb = tractor.count() - 1; trackNb >= 0; --trackNb) {
-                Mlt::Producer trackProducer(tractor.track(trackNb));
-                Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
-                if (trackPlaylist.type() == playlist_type) {
-                    for (int i = 0; i < trackPlaylist.count();i++) {
-                        // We need to manually decrease the ref count and close the producer, otherwise
-                        // 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());
-                    }
-                    mlt_playlist_close(trackPlaylist.get_playlist());
-                    //trackPlaylist.clear();
-                }
-            }
             delete field;
             field = NULL;
         }
         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 && m_mltConsumer) delete m_mltConsumer;
+    m_mltConsumer = NULL;
 }
 
 
-void MltDeviceCapture::doRefresh()
+void MltDeviceCapture::slotDoRefresh()
 {
-    if (m_mltConsumer) m_mltConsumer->set("refresh", 1);
+    QMutexLocker locker(&m_mutex);
+    if (!m_mltProducer)
+        return;
+    if (m_mltConsumer) {
+        if (m_mltConsumer->is_stopped()) m_mltConsumer->start();
+        m_mltConsumer->purge();
+        m_mltConsumer->set("refresh", 1);
+    }
 }
 
 
 void MltDeviceCapture::emitFrameUpdated(Mlt::Frame& frame)
 {
-    mlt_image_format format = mlt_image_rgb24a;
+    /*
+    //TEST: is it better to convert the frame in a thread outside of MLT??
+    if (processingImage) return;
+    mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24;
+    int width = frame.get_int("width");
+    int height = frame.get_int("height");
+    unsigned char *buffer = (unsigned char *) frame.get_data("image");
+    if (format == mlt_image_yuv422) {
+        QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
+    }
+    */
+
+    mlt_image_format format = mlt_image_rgb24;
     int width = 0;
     int height = 0;
     const uchar* image = frame.get_image(format, width, height);
-    QImage qimage(width, height, QImage::Format_ARGB32);
-    memcpy(qimage.bits(), image, width * height * 4);
-    emit frameUpdated(qimage.rgbSwapped());
+    QImage qimage(width, height, QImage::Format_RGB888);
+    //QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
+    memcpy(qimage.bits(), image, width * height * 3);
+    emit frameUpdated(qimage);
 }
 
 void MltDeviceCapture::showFrame(Mlt::Frame& frame)
 {
-    mlt_image_format format = mlt_image_rgb24a;
+    mlt_image_format format = mlt_image_rgb24;
     int width = 0;
     int height = 0;
     const uchar* image = frame.get_image(format, width, height);
-    QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied);
-    memcpy(qimage.scanLine(0), image, width * height * 4);
+    QImage qimage(width, height, QImage::Format_RGB888);
+    memcpy(qimage.scanLine(0), image, width * height * 3);
     emit showImageSignal(qimage);
-    if (m_analyseAudio) showAudio(frame);
+
     if (sendFrameForAnalysis && frame.get_frame()->convert_image) {
         emit frameUpdated(qimage.rgbSwapped());
     }
@@ -271,42 +298,26 @@ void MltDeviceCapture::showAudio(Mlt::Frame& frame)
     // So the vector is of size samples*channels.
     QVector<int16_t> sampleVector(samples*num_channels);
     memcpy(sampleVector.data(), data, samples*num_channels*sizeof(int16_t));
-
     if (samples > 0) {
         emit audioSamplesSignal(sampleVector, freq, num_channels, samples);
     }
 }
 
-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());
-
+    if (m_mltConsumer == NULL) {
+        buildConsumer();
+    }
     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()) {
+        if (m_mltProducer) {
+            delete m_mltProducer;
+            m_mltProducer = NULL;
+        }
         kDebug()<<"//// ERROR CREATRING PROD";
         return false;
     }
@@ -316,63 +327,117 @@ bool MltDeviceCapture::slotStartPreview(const QString &producer)
         m_mltConsumer = NULL;
         return 0;
     }
+    m_droppedFramesTimer.start();
+    //connect(this, SIGNAL(imageReady(QImage)), this, SIGNAL(frameUpdated(QImage)));
     return 1;
 }
 
+void MltDeviceCapture::slotCheckDroppedFrames()
+{
+    if (m_mltProducer) {
+        int dropped = m_mltProducer->get_int("dropped");
+        if (dropped > m_droppedFrames) {
+            m_droppedFrames = dropped;
+            emit droppedFrames(m_droppedFrames);
+        }
+    }
+}
+
 void MltDeviceCapture::gotCapturedFrame(Mlt::Frame& frame)
 {
-    mlt_image_format format = mlt_image_rgb24a;
+    if (m_mltProducer) {
+        int dropped = m_mltProducer->get_int("dropped");
+        if (dropped > m_droppedFrames) {
+            m_droppedFrames = dropped;
+            emit droppedFrames(m_droppedFrames);
+        }
+    }
+    m_frameCount++;
+    if (!m_livePreview) return;
+    //if (m_livePreview == 0 && (m_frameCount % 10 > 0)) return;
+    mlt_image_format format = mlt_image_rgb24;
     int width = 0;
     int height = 0;
-    const uchar* image = frame.get_image(format, width, height);
-    QImage qimage(width, height, QImage::Format_ARGB32);
-    memcpy(qimage.bits(), image, width * height * 4);
-    m_captureDisplayWidget->setImage(qimage.rgbSwapped());
+    uint8_t *data = frame.get_image(format, width, height, 0);
+    //QImage image(width, height, QImage::Format_RGB888);
+    //memcpy(image.bits(), data, width * height * 3);
+    QImage image((uchar *)data, width, height, QImage::Format_RGB888);
+
+    //m_captureDisplayWidget->setImage(image);
+
+    //TEST: is it better to process frame conversion ouside MLT???
+    /*
+    if (!m_livePreview || processingImage) return;
+
+    mlt_image_format format = (mlt_image_format) frame.get_int("format"); //mlt_image_rgb24a;
+    int width = frame.get_int("width");
+    int height = frame.get_int("height");
+    unsigned char *buffer = (unsigned char *) frame.get_data("image");
+    //unsigned char *buffer = frame.get_image(format, width, height);
+    //convert from uyvy422 to rgba
+    if (format == mlt_image_yuv422) {
+        QtConcurrent::run(this, &MltDeviceCapture::uyvy2rgb, (unsigned char *) buffer, width, height);
+        //CaptureHandler::uyvy2rgb((uchar *)frameBytes, (uchar *)image.bits(), videoFrame->GetWidth(), videoFrame->GetHeight());
+    }*/
 }
 
 void MltDeviceCapture::saveFrame(Mlt::Frame& frame)
 {
-    mlt_image_format format = mlt_image_rgb24a;
+    mlt_image_format format = mlt_image_rgb24;
     int width = 0;
     int height = 0;
     const uchar* image = frame.get_image(format, width, height);
-    QImage qimage(width, height, QImage::Format_ARGB32);
-    memcpy(qimage.bits(), image, width * height * 4);
-    qimage.rgbSwapped().save(m_capturePath);
+    QImage qimage(width, height, QImage::Format_RGB888);
+    memcpy(qimage.bits(), image, width * height * 3);
+
+    // 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.save(m_capturePath);
     emit frameSaved(m_capturePath);
     m_capturePath.clear();
 }
 
 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)
+bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &path, const QString &playlist, bool livePreview, bool xmlPlaylist)
 {
     stop();
+    m_livePreview = livePreview;
+    m_frameCount = 0;
+    m_droppedFrames = 0;
     if (m_mltProfile) delete m_mltProfile;
     char *tmp = qstrdup(m_activeProfile.toUtf8().constData());
     m_mltProfile = new Mlt::Profile(tmp);
     delete[] tmp;
-    m_mltProfile->get_profile()->is_explicit = 1;
-    kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
+    //m_mltProfile->get_profile()->is_explicit = 1;
+    
+    
+    /*kDebug()<<"-- CREATING CAP: "<<params<<", PATH: "<<path;
     tmp = qstrdup(QString("avformat:" + path).toUtf8().constData());
     m_mltConsumer = new Mlt::Consumer(*m_mltProfile, tmp);
-    m_mltConsumer->set("terminate_on_pause", 1);
-    delete[] tmp;
-
-    QStringList paramList = params.split(" ", QString::SkipEmptyParts);
-    char *tmp2;
-    for (int i = 0; i < paramList.count(); i++) {
-        tmp = qstrdup(paramList.at(i).section("=", 0, 0).toUtf8().constData());
-        tmp2 = qstrdup(paramList.at(i).section("=", 1, 1).toUtf8().constData());
-        m_mltConsumer->set(tmp, tmp2);
-        delete[] tmp;
-        delete[] tmp2;
-    }
+    m_mltConsumer->set("real_time", -KdenliveSettings::mltthreads());
+    delete[] tmp;*/
     
+    m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "multi");
     if (m_mltConsumer == NULL || !m_mltConsumer->is_valid()) {
         if (m_mltConsumer) {
             delete m_mltConsumer;
@@ -381,26 +446,332 @@ bool MltDeviceCapture::slotStartCapture(const QString &params, const QString &pa
         return false;
     }
     
-    // FIXME: the event object returned by the listen gets leaked...
-    m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_show);
+    m_winid = (int) m_captureDisplayWidget->winId();
+    
+    // Create multi consumer setup
+    Mlt::Properties *renderProps = new Mlt::Properties;
+    renderProps->set("mlt_service", "avformat");
+    renderProps->set("target", path.toUtf8().constData());
+    renderProps->set("real_time", -KdenliveSettings::mltthreads());
+    //renderProps->set("terminate_on_pause", 0);
+    renderProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
+    
 
-    //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;
+    QStringList paramList = params.split(' ', QString::SkipEmptyParts);
+    char *tmp2;
+    for (int i = 0; i < paramList.count(); ++i) {
+        tmp = qstrdup(paramList.at(i).section('=', 0, 0).toUtf8().constData());
+        QString value = paramList.at(i).section('=', 1, 1);
+        if (value == "%threads") value = QString::number(QThread::idealThreadCount());
+        tmp2 = qstrdup(value.toUtf8().constData());
+        renderProps->set(tmp, tmp2);
+        delete[] tmp;
+        delete[] tmp2;
+    }
+    mlt_properties consumerProperties = m_mltConsumer->get_properties();
+    mlt_properties_set_data(consumerProperties, "0", renderProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
+    
+    if (m_livePreview) 
+    {
+        // user wants live preview
+        Mlt::Properties *previewProps = new Mlt::Properties;
+        QString videoDriver = KdenliveSettings::videodrivername();
+        if (!videoDriver.isEmpty()) {
+            if (videoDriver == "x11_noaccel") {
+                setenv("SDL_VIDEO_YUV_HWACCEL", "0", 1);
+                videoDriver = "x11";
+            } else {
+                unsetenv("SDL_VIDEO_YUV_HWACCEL");
+            }
+        }
+        setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
+        
+        if (m_winid == 0) {
+            // OpenGL monitor
+            previewProps->set("mlt_service", "sdl_audio");
+            previewProps->set("preview_off", 1);
+            previewProps->set("preview_format", mlt_image_rgb24);
+            previewProps->set("terminate_on_pause", 0);
+            m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_gl_frame_show);
+        } else {
+            previewProps->set("mlt_service", "sdl_preview");
+            previewProps->set("window_id", m_winid);
+            previewProps->set("terminate_on_pause", 0);
+            //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) rec_consumer_frame_preview);
+        }
+        //m_mltConsumer->set("resize", 1);
+        previewProps->set("window_background", KdenliveSettings::window_background().name().toUtf8().constData());
+        QString audioDevice = KdenliveSettings::audiodevicename();
+        if (!audioDevice.isEmpty())
+            previewProps->set("audio_device", audioDevice.toUtf8().constData());
+
+        if (!videoDriver.isEmpty())
+            previewProps->set("video_driver", videoDriver.toUtf8().constData());
+
+        QString audioDriver = KdenliveSettings::audiodrivername();
+
+        if (!audioDriver.isEmpty())
+            previewProps->set("audio_driver", audioDriver.toUtf8().constData());
+        
+        previewProps->set("real_time", "0");
+        previewProps->set("mlt_profile", m_activeProfile.toUtf8().constData());
+        mlt_properties_set_data(consumerProperties, "1", previewProps->get_properties(), 0, (mlt_destructor) mlt_properties_close, NULL);
+        //m_showFrameEvent = m_mltConsumer->listen("consumer-frame-render", this, (mlt_listener) rec_consumer_frame_show);
+    }
+    else {
+        
+    }
+    
+    if (xmlPlaylist) {
+        // create an xml producer
+        m_mltProducer = new Mlt::Producer(*m_mltProfile, "xml-string", playlist.toUtf8().constData());
+    }
+    else {
+        // create a producer based on mltproducer parameter
+        m_mltProducer = new Mlt::Producer(*m_mltProfile, playlist.toUtf8().constData());
+    }
 
     if (m_mltProducer == NULL || !m_mltProducer->is_valid()) {
         kDebug()<<"//// ERROR CREATRING PROD";
+       if (m_mltConsumer) {
+            delete m_mltConsumer;
+            m_mltConsumer = NULL;
+        }
+       if (m_mltProducer) {
+           delete m_mltProducer;
+           m_mltProducer = NULL;
+       }
         return false;
     }
-
+    
     m_mltConsumer->connect(*m_mltProducer);
     if (m_mltConsumer->start() == -1) {
+        if (m_showFrameEvent) delete m_showFrameEvent;
+        m_showFrameEvent = NULL;
         delete m_mltConsumer;
         m_mltConsumer = NULL;
         return 0;
     }
+    m_droppedFramesTimer.start();
     return 1;
 }
 
 
+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, const 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());
+}
+
+void MltDeviceCapture::uyvy2rgb(unsigned char *yuv_buffer, int width, int height)
+{
+    processingImage = true;
+    QImage image(width, height, QImage::Format_RGB888);
+    unsigned char *rgb_buffer = image.bits();    
+
+    int len;
+    int r, g, b;
+    int Y, U, V, Y2;
+    int rgb_ptr, y_ptr, t;
+
+    len = width * height / 2;
+
+    rgb_ptr = 0;
+    y_ptr = 0;
+
+    for (t = 0; t < len; t++) { 
+      
+
+        Y = yuv_buffer[y_ptr];
+        U = yuv_buffer[y_ptr+1];
+        Y2 = yuv_buffer[y_ptr+2];
+        V = yuv_buffer[y_ptr+3];
+        y_ptr += 4;
+
+        r = ((298 * (Y - 16)               + 409 * (V - 128) + 128) >> 8);
+
+        g = ((298 * (Y - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
+
+        b = ((298 * (Y - 16) + 516 * (U - 128)               + 128) >> 8);
+
+        if (r > 255) r = 255;
+        if (g > 255) g = 255;
+        if (b > 255) b = 255;
+
+        if (r < 0) r = 0;
+        if (g < 0) g = 0;
+        if (b < 0) b = 0;
+
+        rgb_buffer[rgb_ptr] = r;
+        rgb_buffer[rgb_ptr+1] = g;
+        rgb_buffer[rgb_ptr+2] = b;
+        rgb_ptr += 3;
+
+
+        r = ((298 * (Y2 - 16)               + 409 * (V - 128) + 128) >> 8);
+
+        g = ((298 * (Y2 - 16) - 100 * (U - 128) - 208 * (V - 128) + 128) >> 8);
+
+        b = ((298 * (Y2 - 16) + 516 * (U - 128)               + 128) >> 8);
+
+        if (r > 255) r = 255;
+        if (g > 255) g = 255;
+        if (b > 255) b = 255;
+
+        if (r < 0) r = 0;
+        if (g < 0) g = 0;
+        if (b < 0) b = 0;
+
+        rgb_buffer[rgb_ptr] = r;
+        rgb_buffer[rgb_ptr+1] = g;
+        rgb_buffer[rgb_ptr+2] = b;
+        rgb_ptr += 3;
+    }
+    //emit imageReady(image);
+    //m_captureDisplayWidget->setImage(image);
+    emit unblockPreview();
+    //processingImage = false;
+}
+
+void MltDeviceCapture::slotPreparePreview()
+{
+    QTimer::singleShot(1000, this, SLOT(slotAllowPreview()));
+}
+
+void MltDeviceCapture::slotAllowPreview()
+{
+    processingImage = false;
+}
+
+
+
+#include "mltdevicecapture.moc"