]> git.sesse.net Git - kdenlive/blobdiff - src/renderer.cpp
Try to fix audio mixing bug ( http://www.kdenlive.org:80/mantis/view.php?id=228 )
[kdenlive] / src / renderer.cpp
index 3675fd9fca9208943f0b43ca7b2e7e72b8b51b55..e0ce8c473dcc3e725db77668dbe7d0926fb98225 100644 (file)
@@ -65,13 +65,13 @@ static void consumer_frame_show(mlt_consumer, Render * self, mlt_frame frame_ptr
     }
 }
 
-Render::Render(const QString & rendererName, int winid, int extid, QWidget *parent): QObject(parent), m_name(rendererName), m_mltConsumer(NULL), m_mltProducer(NULL), m_mltTextProducer(NULL), m_winid(winid), m_externalwinid(extid),  m_framePosition(0), m_isBlocked(true), m_blackClip(NULL), m_isSplitView(false) {
+Render::Render(const QString & rendererName, int winid, int extid, QWidget *parent): QObject(parent), m_name(rendererName), m_mltConsumer(NULL), m_mltProducer(NULL), m_mltTextProducer(NULL), m_winid(winid), m_externalwinid(extid),  m_framePosition(0), m_isBlocked(true), m_blackClip(NULL), m_isSplitView(false), m_isZoneMode(false), m_isLoopMode(false) {
     kDebug() << "//////////  USING PROFILE: " << (char*)KdenliveSettings::current_profile().toUtf8().data();
     refreshTimer = new QTimer(this);
     connect(refreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
 
-    if (rendererName == "project") m_monitorId = 10000;
-    else m_monitorId = 10001;
+    /*if (rendererName == "project") m_monitorId = 10000;
+    else m_monitorId = 10001;*/
     osdTimer = new QTimer(this);
     connect(osdTimer, SIGNAL(timeout()), this, SLOT(slotOsdTimeout()));
 
@@ -120,6 +120,7 @@ void Render::buildConsumer() {
             unsetenv("SDL_VIDEO_YUV_HWACCEL");
         }
     }
+    setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 1);
 
     m_mltConsumer = new Mlt::Consumer(*m_mltProfile , "sdl_preview");
     m_mltConsumer->set("resize", 1);
@@ -201,8 +202,11 @@ int Render::resetProfile() {
 
 /** Wraps the VEML command of the same name; Seeks the renderer clip to the given time. */
 void Render::seek(GenTime time) {
-    sendSeekCommand(time);
-    //emit positionChanged(time);
+    if (!m_mltProducer)
+        return;
+    m_isBlocked = false;
+    m_mltProducer->seek((int)(time.frames(m_fps)));
+    refresh();
 }
 
 //static
@@ -464,7 +468,11 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
     QMap < QString, QString > metadataPropertyMap;
 
     KUrl url = KUrl(xml.attribute("resource", QString::null));
-    Mlt::Producer *producer;
+    Mlt::Producer *producer = NULL;
+    if (xml.attribute("type").toInt() == TEXT && !QFile::exists(url.path())) {
+        emit replyGetFileProperties(clipId, producer, filePropertyMap, metadataPropertyMap);
+        return;
+    }
     if (xml.attribute("type").toInt() == COLOR) {
         char *tmp = decodedString("colour:" + xml.attribute("colour"));
         producer = new Mlt::Producer(*m_mltProfile, "fezzik", tmp);
@@ -476,14 +484,39 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
         doc.appendChild(westley);
         westley.appendChild(play);
         play.appendChild(doc.importNode(xml, true));
-        kDebug() << "/ / / / /CLIP XML: " << doc.toString();
         char *tmp = decodedString(doc.toString());
         producer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp);
         delete[] tmp;
     } else {
-        char *tmp = decodedString(url.path());
+        QString urlpath = url.path();
+        /*if (urlpath.contains(':')) {
+            if (!urlpath.startsWith("file:")) urlpath.prepend("file:");
+            char *tmp = decodedString(urlpath);
+            producer = new Mlt::Producer(*m_mltProfile, "avformat", tmp);
+            delete[] tmp;
+        }
+        else {*/
+        char *tmp = decodedString(urlpath);
         producer = new Mlt::Producer(*m_mltProfile, tmp);
         delete[] tmp;
+
+        if (xml.hasAttribute("force_aspect_ratio")) {
+            double aspect = xml.attribute("force_aspect_ratio").toDouble();
+            if (aspect > 0) producer->set("force_aspect_ratio", aspect);
+        }
+        if (xml.hasAttribute("threads")) {
+            int threads = xml.attribute("threads").toInt();
+            if (threads != 1) producer->set("threads", threads);
+        }
+        if (xml.hasAttribute("video_index")) {
+            int vindex = xml.attribute("video_index").toInt();
+            if (vindex != 0) producer->set("video_index", vindex);
+        }
+        if (xml.hasAttribute("audio_index")) {
+            int aindex = xml.attribute("audio_index").toInt();
+            if (aindex != 0) producer->set("audio_index", aindex);
+        }
+        //}
     }
     if (xml.hasAttribute("out")) producer->set_in_and_out(xml.attribute("in").toInt(), xml.attribute("out").toInt());
 
@@ -499,11 +532,10 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
     if (frameNumber != 0) producer->seek(frameNumber);
     mlt_properties properties = MLT_PRODUCER_PROPERTIES(producer->get_producer());
 
-    filePropertyMap["filename"] = url.path();
     filePropertyMap["duration"] = QString::number(producer->get_playtime());
     //kDebug() << "///////  PRODUCER: " << url.path() << " IS: " << producer.get_playtime();
 
-    Mlt::Frame * frame = producer->get_frame();
+    Mlt::Frame *frame = producer->get_frame();
 
     if (xml.attribute("type").toInt() == SLIDESHOW) {
         if (xml.hasAttribute("ttl")) producer->set("ttl", xml.attribute("ttl").toInt());
@@ -558,7 +590,7 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
             QImage image((uchar *)new_image, frame_width, frame_height, QImage::Format_ARGB32);
 
             if (!image.isNull()) {
-                pix = pix.fromImage(image.rgbSwapped());
+                pix = QPixmap::fromImage(image.rgbSwapped());
             } else
                 pix.fill(Qt::black);
 
@@ -586,13 +618,43 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
         }*/
         // Get the video_index
         int index = mlt_properties_get_int(properties, "video_index");
+        int default_video = -1;
+        int video_max = 0;
+        int default_audio = -1;
+        int audio_max = 0;
+        // Find default audio stream (borrowed from MLT)
+        for (int ix = 0; ix < context->nb_streams; ix++) {
+            // Get the codec context
+            AVCodecContext *codec_context = context->streams[ ix ]->codec;
+
+            if (avcodec_find_decoder(codec_context->codec_id) == NULL)
+                continue;
+            // Determine the type and obtain the first index of each type
+            switch (codec_context->codec_type) {
+            case CODEC_TYPE_VIDEO:
+                if (default_video < 0) default_video = ix;
+                video_max = ix;
+                break;
+            case CODEC_TYPE_AUDIO:
+                if (default_audio < 0) default_audio = ix;
+                audio_max = ix;
+                break;
+            default:
+                break;
+            }
+        }
+        filePropertyMap["default_video"] = QString::number(default_video);
+        filePropertyMap["video_max"] = QString::number(video_max);
+        filePropertyMap["default_audio"] = QString::number(default_audio);
+        filePropertyMap["audio_max"] = QString::number(audio_max);
+
 
 #if ENABLE_FFMPEG_CODEC_DESCRIPTION
-        if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->long_name) {
+        if (index > -1 && context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->long_name) {
             filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->long_name;
         } else
 #endif
-            if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name) {
+            if (index > -1 && context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name) {
                 filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->name;
             }
     } else kDebug() << " / / / / /WARNING, VIDEO CONTEXT IS NULL!!!!!!!!!!!!!!";
@@ -602,11 +664,11 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
         int index = mlt_properties_get_int(properties, "audio_index");
 
 #if ENABLE_FFMPEG_CODEC_DESCRIPTION
-        if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->long_name)
+        if (index > -1 && context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->long_name)
             filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->long_name;
         else
 #endif
-            if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
+            if (index > -1 && context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
                 filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->name;
     }
 #endif
@@ -628,6 +690,7 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
     //if (producer) delete producer;
 }
 
+
 /** Create the producer from the Westley QDomDocument */
 #if 0
 void Render::initSceneList() {
@@ -729,7 +792,9 @@ void Render::setSceneList(QString playlist, int position) {
     if (m_blackClip) delete m_blackClip;
     m_blackClip = new Mlt::Producer(*m_mltProfile , "colour", "black");
     m_blackClip->set("id", "black");
-    if (!m_mltProducer || !m_mltProducer->is_valid()) kDebug() << " WARNING - - - - -INVALID PLAYLIST: " << tmp;
+    if (!m_mltProducer || !m_mltProducer->is_valid()) {
+        kDebug() << " WARNING - - - - -INVALID PLAYLIST: " << tmp;
+    }
     m_mltProducer->optimise();
 
     /*if (KdenliveSettings::osdtimecode()) {
@@ -770,59 +835,72 @@ void Render::setSceneList(QString playlist, int position) {
 
 /** Create the producer from the Westley QDomDocument */
 QString Render::sceneList() {
-    KTemporaryFile temp;
-    QString result;
-
-    if (temp.open()) {
-        saveSceneList(temp.fileName());
-        QFile file(temp.fileName());
-        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
-            kWarning() << "++++++++++++++++   CANNOT READ TMP SCENELIST FILE";
-            return QString();
-        }
-        QTextStream in(&file);
-        while (!in.atEnd()) {
-            result.append(in.readLine());
-        }
-    }
-    return result;
-}
-
-void Render::saveSceneList(QString path, QDomElement kdenliveData) {
-
-    char *tmppath = decodedString("westley:" + path);
-    Mlt::Consumer westleyConsumer(*m_mltProfile , tmppath);
+    QString playlist;
+    Mlt::Consumer westleyConsumer(*m_mltProfile , "westley:kdenlive_playlist");
     m_mltProducer->optimise();
-    delete[] tmppath;
     westleyConsumer.set("terminate_on_pause", 1);
     Mlt::Producer prod(m_mltProducer->get_producer());
     bool split = m_isSplitView;
     if (split) slotSplitView(false);
     westleyConsumer.connect(prod);
-    //prod.set("title", "kdenlive document");
-    //westleyConsumer.listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
     westleyConsumer.start();
     while (!westleyConsumer.is_stopped()) {}
+    playlist = westleyConsumer.get("kdenlive_playlist");
+    if (split) slotSplitView(true);
+    return playlist;
+}
+
+void Render::saveSceneList(QString path, QDomElement kdenliveData) {
+    QFile file(path);
+    QDomDocument doc;
+    doc.setContent(sceneList(), false);
     if (!kdenliveData.isNull()) {
         // add Kdenlive specific tags
-        QFile file(path);
-        QDomDocument doc;
-        doc.setContent(&file, false);
         QDomNode wes = doc.elementsByTagName("westley").at(0);
         wes.appendChild(doc.importNode(kdenliveData, true));
-        file.close();
-        if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
-            kWarning() << "//////  ERROR writing to file: " << path;
-            return;
-        }
-        QTextStream out(&file);
-        out << doc.toString();
-        file.close();
     }
-    if (split) slotSplitView(true);
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+        kWarning() << "//////  ERROR writing to file: " << path;
+        return;
+    }
+    QTextStream out(&file);
+    out << doc.toString();
+    file.close();
 }
 
 
+void Render::saveZone(KUrl url, QString desc, QPoint zone) {
+    kDebug() << "// SAVING CLIP ZONE, RENDER: " << m_name;
+    char *tmppath = decodedString("westley:" + url.path());
+    Mlt::Consumer westleyConsumer(*m_mltProfile , tmppath);
+    m_mltProducer->optimise();
+    delete[] tmppath;
+    westleyConsumer.set("terminate_on_pause", 1);
+    if (m_name == "clip") {
+        Mlt::Producer *prod = m_mltProducer->cut(zone.x(), zone.y());
+        tmppath = decodedString(desc);
+        Mlt::Playlist list;
+        list.insert_at(0, prod, 0);
+        list.set("title", tmppath);
+        delete[] tmppath;
+        westleyConsumer.connect(list);
+
+    } else {
+        //TODO: not working yet, save zone from timeline
+        Mlt::Producer *p1 = new Mlt::Producer(m_mltProducer->get_producer());
+        /* Mlt::Service service(p1->parent().get_service());
+         if (service.type() != tractor_type) kWarning() << "// TRACTOR PROBLEM";*/
+
+        //Mlt::Producer *prod = p1->cut(zone.x(), zone.y());
+        tmppath = decodedString(desc);
+        //prod->set("title", tmppath);
+        delete[] tmppath;
+        westleyConsumer.connect(*p1); //list);
+    }
+
+    westleyConsumer.start();
+}
+
 const double Render::fps() const {
     return m_fps;
 }
@@ -942,6 +1020,7 @@ void Render::stop() {
     m_isBlocked = true;
 
     if (m_mltProducer) {
+        if (m_isZoneMode) resetZoneMode();
         m_mltProducer->set_speed(0.0);
         //m_mltProducer->set("out", m_mltProducer->get_length() - 1);
         //kDebug() << m_mltProducer->get_length();
@@ -953,26 +1032,41 @@ void Render::stop(const GenTime & startTime) {
 
     kDebug() << "/////////////   RENDER STOP-------2";
     if (m_mltProducer) {
+        if (m_isZoneMode) resetZoneMode();
         m_mltProducer->set_speed(0.0);
         m_mltProducer->seek((int) startTime.frames(m_fps));
     }
     m_mltConsumer->purge();
 }
 
+void Render::pause() {
+    if (!m_mltProducer || !m_mltConsumer)
+        return;
+    if (m_mltProducer->get_speed() == 0.0) return;
+    if (m_isZoneMode) resetZoneMode();
+    m_isBlocked = true;
+    m_mltConsumer->set("refresh", 0);
+    m_mltProducer->set_speed(0.0);
+    emit rendererPosition(m_framePosition);
+    m_mltProducer->seek(m_framePosition);
+    m_mltConsumer->purge();
+}
+
 void Render::switchPlay() {
     if (!m_mltProducer || !m_mltConsumer)
         return;
+    if (m_isZoneMode) resetZoneMode();
     if (m_mltProducer->get_speed() == 0.0) {
-        //m_isBlocked = false;
+        m_isBlocked = false;
         m_mltProducer->set_speed(1.0);
         m_mltConsumer->set("refresh", 1);
-        kDebug() << " *********  RENDER PLAY: " << m_mltProducer->get_speed();
     } else {
-        //m_isBlocked = true;
+        m_isBlocked = true;
         m_mltConsumer->set("refresh", 0);
         m_mltProducer->set_speed(0.0);
-        //m_isBlocked = true;
-        m_mltProducer->seek((int) m_framePosition);
+        emit rendererPosition(m_framePosition);
+        m_mltProducer->seek(m_framePosition);
+        m_mltConsumer->purge();
         //kDebug()<<" *********  RENDER PAUSE: "<<m_mltProducer->get_speed();
         //m_mltConsumer->set("refresh", 0);
         /*mlt_position position = mlt_producer_position( m_mltProducer->get_producer() );
@@ -989,10 +1083,10 @@ void Render::switchPlay() {
 }
 
 void Render::play(double speed) {
-    kDebug() << " *********  REDNER PLAY";
     if (!m_mltProducer)
         return;
     // if (speed == 0.0) m_mltProducer->set("out", m_mltProducer->get_length() - 1);
+    m_isBlocked = false;
     m_mltProducer->set_speed(speed);
     /*if (speed == 0.0) {
     m_mltProducer->seek((int) m_framePosition + 1);
@@ -1001,44 +1095,48 @@ void Render::play(double speed) {
     refresh();
 }
 
-void Render::play(double speed, const GenTime & startTime) {
-    kDebug() << "/////////////   RENDER PLAY2-------" << speed;
-    if (!m_mltProducer)
+void Render::play(const GenTime & startTime) {
+    if (!m_mltProducer || !m_mltConsumer)
         return;
-    //m_mltProducer->set("out", m_mltProducer->get_length() - 1);
-    //if (speed == 0.0) m_mltConsumer->set("refresh", 0);
-    m_mltProducer->set_speed(speed);
+    m_isBlocked = false;
     m_mltProducer->seek((int)(startTime.frames(m_fps)));
-    //m_mltConsumer->purge();
-    //refresh();
+    m_mltProducer->set_speed(1.0);
+    m_mltConsumer->set("refresh", 1);
 }
 
-void Render::play(double speed, const GenTime & startTime,
-                  const GenTime & stopTime) {
-    kDebug() << "/////////////   RENDER PLAY3-------" << speed << stopTime.frames(m_fps);
-    if (!m_mltProducer)
+void Render::loopZone(const GenTime & startTime, const GenTime & stopTime) {
+    if (!m_mltProducer || !m_mltConsumer)
         return;
+    //m_mltProducer->set("eof", "loop");
+    m_isLoopMode = true;
+    m_loopStart = startTime;
+    playZone(startTime, stopTime);
+}
+
+void Render::playZone(const GenTime & startTime, const GenTime & stopTime) {
+    if (!m_mltProducer || !m_mltConsumer)
+        return;
+    m_isBlocked = false;
     m_mltProducer->set("out", stopTime.frames(m_fps));
     m_mltProducer->seek((int)(startTime.frames(m_fps)));
-    m_mltConsumer->purge();
-    m_mltProducer->set_speed(speed);
-    refresh();
+    m_mltProducer->set_speed(1.0);
+    m_mltConsumer->set("refresh", 1);
+    m_isZoneMode = true;
 }
 
-
-void Render::sendSeekCommand(GenTime time) {
-    //kDebug()<<" *********  RENDER SEND SEEK";
-    if (!m_mltProducer)
-        return;
-    //kDebug()<<"//////////  KDENLIVE SEEK: "<<(int) (time.frames(m_fps));
-    m_mltProducer->seek((int)(time.frames(m_fps)));
-    refresh();
+void Render::resetZoneMode() {
+    m_mltProducer->set("out", m_mltProducer->get_length() - 1);
+    //m_mltProducer->set("eof", "pause");
+    m_isZoneMode = false;
+    m_isLoopMode = false;
 }
 
 void Render::seekToFrame(int pos) {
     //kDebug()<<" *********  RENDER SEEK TO POS";
     if (!m_mltProducer)
         return;
+    m_isBlocked = false;
+    resetZoneMode();
     m_mltProducer->seek(pos);
     refresh();
 }
@@ -1062,17 +1160,6 @@ void Render::refresh() {
     }
 }
 
-/** Sets the description of this renderer to desc. */
-void Render::setDescription(const QString & description) {
-    m_description = description;
-}
-
-/** Returns the description of this renderer */
-QString Render::description() {
-    return m_description;
-}
-
-
 double Render::playSpeed() {
     if (m_mltProducer) return m_mltProducer->get_speed();
     return 0.0;
@@ -1099,6 +1186,8 @@ void Render::emitConsumerStopped() {
     // This is used to know when the playing stopped
     if (m_mltProducer) {
         double pos = m_mltProducer->position();
+        if (m_isLoopMode) play(m_loopStart);
+        else if (m_isZoneMode) resetZoneMode();
         emit rendererStopped((int) pos);
         //if (qApp->activeWindow()) QApplication::postEvent(qApp->activeWindow(), new PositionChangeEvent(GenTime((int) pos, m_fps), m_monitorId + 100));
         //new QCustomEvent(10002));
@@ -1219,8 +1308,8 @@ void Render::mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *pr
     Mlt::Producer *clip = prod->cut((int) info.cropStart.frames(m_fps), (int)(info.endPos - info.startPos + info.cropStart).frames(m_fps) - 1);
     int newIndex = trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *clip, 1);
 
-    if (QString(prod->get("transparency")).toInt() == 1)
-        mltAddClipTransparency(info, info.track - 1, QString(prod->get("id")).toInt());
+    /*if (QString(prod->get("transparency")).toInt() == 1)
+        mltAddClipTransparency(info, info.track - 1, QString(prod->get("id")).toInt());*/
 
     mlt_service_unlock(service.get_service());
 
@@ -1256,13 +1345,14 @@ void Render::mltCutClip(int track, GenTime position) {
 
     int clipIndex = trackPlaylist.get_clip_index_at(cutPos);
     if (trackPlaylist.is_blank(clipIndex)) {
-        kDebug() << "// WARMNING, TRYING TO CUT A BLANK";
+        kDebug() << "// WARNING, TRYING TO CUT A BLANK";
         m_isBlocked = false;
         return;
     }
     mlt_service_lock(service.get_service());
     int clipStart = trackPlaylist.clip_start(clipIndex);
     trackPlaylist.split(clipIndex, cutPos - clipStart - 1);
+    mlt_service_unlock(service.get_service());
 
     // duplicate effects
     Mlt::Producer *original = trackPlaylist.get_clip_at(clipStart);
@@ -1277,16 +1367,18 @@ void Render::mltCutClip(int track, GenTime position) {
     Mlt::Filter *filter = clipService.filter(ct);
     while (filter) {
         if (filter->get("kdenlive_id") != "") {
-            kDebug() << "++ ADDING FILTER: " << filter->get("kdenlive_id");
-            Mlt::Filter *dup = new Mlt::Filter(filter->get_filter());
-            dup->set("kdenlive_ix", filter->get("kdenlive_ix"));
-            dup->set("kdenlive_id", filter->get("kdenlive_id"));
+            // looks like there is no easy way to duplicate a filter,
+            // so we will create a new one and duplicate its properties
+            Mlt::Filter *dup = new Mlt::Filter(*m_mltProfile, filter->get("mlt_service"));
+            Mlt::Properties entries(filter->get_properties());
+            for (int i = 0;i < entries.count();i++) {
+                dup->set(entries.get_name(i), entries.get(i));
+            }
             dupService.attach(*dup);
         }
         ct++;
         filter = clipService.filter(ct);
     }
-    mlt_service_unlock(service.get_service());
 
     /* // Display playlist info
     kDebug()<<"////////////  AFTER";
@@ -1335,8 +1427,8 @@ bool Render::mltRemoveClip(int track, GenTime position) {
     Mlt::Producer clip(trackPlaylist.get_clip(clipIndex));
     trackPlaylist.replace_with_blank(clipIndex);
     trackPlaylist.consolidate_blanks(0);
-    if (QString(clip.parent().get("transparency")).toInt() == 1)
-        mltDeleteTransparency((int) position.frames(m_fps), track, QString(clip.parent().get("id")).toInt());
+    /*if (QString(clip.parent().get("transparency")).toInt() == 1)
+        mltDeleteTransparency((int) position.frames(m_fps), track, QString(clip.parent().get("id")).toInt());*/
 
     /* // Display playlist info
     kDebug()<<"////  AFTER";
@@ -1470,6 +1562,20 @@ bool Render::mltAddEffect(int track, GenTime position, QHash <QString, QString>
     }
     Mlt::Service clipService(clip->get_service());
     m_isBlocked = true;
+
+    // temporarily remove all effects after insert point
+    QList <Mlt::Filter *> filtersList;
+    const int filer_ix = QString(args.value("kdenlive_ix")).toInt();
+    int ct = 0;
+    Mlt::Filter *filter = clipService.filter(ct);
+    while (filter) {
+        if (QString(filter->get("kdenlive_ix")).toInt() > filer_ix) {
+            filtersList.append(filter);
+            clipService.detach(*filter);
+        } else ct++;
+        filter = clipService.filter(ct);
+    }
+
     // create filter
     QString tag = args.value("tag");
     kDebug() << " / / INSERTING EFFECT: " << tag;
@@ -1544,6 +1650,12 @@ bool Render::mltAddEffect(int track, GenTime position, QHash <QString, QString>
     }
     delete[] filterId;
     delete[] filterTag;
+
+    // re-add following filters
+    for (int i = 0; i < filtersList.count(); i++) {
+        clipService.attach(*(filtersList.at(i)));
+    }
+
     m_isBlocked = false;
     if (doRefresh) refresh();
     return true;
@@ -1675,7 +1787,7 @@ void Render::mltMoveEffect(int track, GenTime position, int oldPos, int newPos)
         while (filter) {
             int pos = QString(filter->get("kdenlive_ix")).toInt();
             if (pos >= newPos) {
-                if (pos < oldPos) filter->set("kdenlive_ix", QString(filter->get("kdenlive_ix")).toInt() + 1);
+                if (pos < oldPos) filter->set("kdenlive_ix", pos + 1);
                 filtersList.append(filter);
                 clipService.detach(*filter);
             } else ct++;
@@ -1742,20 +1854,9 @@ bool Render::mltResizeClipEnd(ItemInfo info, GenTime clipDuration) {
 
     trackPlaylist.consolidate_blanks(0);
 
-    /* // Display playlist info
-    kDebug()<<"////////////  AFTER RESIZE";
-    for (int i = 0; i < trackPlaylist.count(); i++) {
-    int blankStart = trackPlaylist.clip_start(i);
-    int blankDuration = trackPlaylist.clip_length(i) - 1;
-    QString blk;
-    if (trackPlaylist.is_blank(i)) blk = "(blank)";
-    kDebug()<<"CLIP "<<i<<": ("<<blankStart<<"x"<<blankStart + blankDuration<<")"<<blk;
-    }*/
 
-    //tractor.multitrack()->refresh();
-    //tractor.refresh();
     if (info.track != 0 && clipIndex == trackPlaylist.count()) mltCheckLength();
-    if (QString(clip->parent().get("transparency")).toInt() == 1) {
+    /*if (QString(clip->parent().get("transparency")).toInt() == 1) {
         //mltResizeTransparency(previousStart, previousStart, previousStart + newDuration, track, QString(clip->parent().get("id")).toInt());
         mltDeleteTransparency(info.startPos.frames(m_fps), info.track, QString(clip->parent().get("id")).toInt());
         ItemInfo transpinfo;
@@ -1763,7 +1864,7 @@ bool Render::mltResizeClipEnd(ItemInfo info, GenTime clipDuration) {
         transpinfo.endPos = info.startPos + clipDuration;
         transpinfo.track = info.track;
         mltAddClipTransparency(transpinfo, info.track - 1, QString(clip->parent().get("id")).toInt());
-    }
+    }*/
     m_isBlocked = false;
     return true;
 }
@@ -1827,7 +1928,7 @@ bool Render::mltResizeClipStart(ItemInfo info, GenTime diff) {
         else trackPlaylist.resize_clip(blankIndex, 0, blankLength + moveFrame - 1);
     }
     trackPlaylist.consolidate_blanks(0);
-    if (QString(clip->parent().get("transparency")).toInt() == 1) {
+    /*if (QString(clip->parent().get("transparency")).toInt() == 1) {
         //mltResizeTransparency(previousStart, (int) moveEnd.frames(m_fps), (int) (moveEnd + out - in).frames(m_fps), track, QString(clip->parent().get("id")).toInt());
         mltDeleteTransparency(info.startPos.frames(m_fps), info.track, QString(clip->parent().get("id")).toInt());
         ItemInfo transpinfo;
@@ -1835,19 +1936,19 @@ bool Render::mltResizeClipStart(ItemInfo info, GenTime diff) {
         transpinfo.endPos = info.startPos + diff + (info.endPos - info.startPos);
         transpinfo.track = info.track;
         mltAddClipTransparency(transpinfo, info.track - 1, QString(clip->parent().get("id")).toInt());
-    }
+    }*/
     m_isBlocked = false;
     //m_mltConsumer->set("refresh", 1);
     mlt_service_unlock(service.get_service());
     return true;
 }
 
-bool Render::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd) {
-    return mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps));
+bool Render::mltMoveClip(int startTrack, int endTrack, GenTime moveStart, GenTime moveEnd, Mlt::Producer *prod) {
+    return mltMoveClip(startTrack, endTrack, (int) moveStart.frames(m_fps), (int) moveEnd.frames(m_fps), prod);
 }
 
 
-bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd) {
+bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEnd, Mlt::Producer *prod) {
     m_isBlocked = true;
 
     m_mltConsumer->set("refresh", 0);
@@ -1875,9 +1976,9 @@ bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn
         } else {
             trackPlaylist.consolidate_blanks(0);
             int newIndex = trackPlaylist.insert_at(moveEnd, clipProducer, 1);
-            if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
+            /*if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
                 mltMoveTransparency(moveStart, moveEnd, startTrack, endTrack, QString(clipProducer.parent().get("id")).toInt());
-            }
+            }*/
             if (newIndex + 1 == trackPlaylist.count()) checkLength = true;
         }
         //mlt_service_unlock(service.get_service());
@@ -1893,12 +1994,28 @@ bool Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn
             Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
             trackPlaylist.consolidate_blanks(0);
             destTrackPlaylist.consolidate_blanks(1);
-            int newIndex = destTrackPlaylist.insert_at(moveEnd, clipProducer, 1);
+            Mlt::Producer *clip = prod->cut(clipProducer.get_in(), clipProducer.get_out());
+
+            // move all effects to the correct producer
+            Mlt::Service clipService(clipProducer.get_service());
+            Mlt::Service newClipService(clip->get_service());
+
+            int ct = 0;
+            Mlt::Filter *filter = clipService.filter(ct);
+            while (filter) {
+                if (filter->get("kdenlive_ix") != 0) {
+                    clipService.detach(*filter);
+                    newClipService.attach(*filter);
+                } else ct++;
+                filter = clipService.filter(ct);
+            }
+
+            int newIndex = destTrackPlaylist.insert_at(moveEnd, clip, 1);
             destTrackPlaylist.consolidate_blanks(0);
-            if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
+            /*if (QString(clipProducer.parent().get("transparency")).toInt() == 1) {
                 kDebug() << "//////// moving clip transparency";
                 mltMoveTransparency(moveStart, moveEnd, startTrack, endTrack, QString(clipProducer.parent().get("id")).toInt());
-            }
+            }*/
             if (clipIndex > trackPlaylist.count()) checkLength = true;
             else if (newIndex + 1 == destTrackPlaylist.count()) checkLength = true;
         }
@@ -2028,24 +2145,24 @@ void Render::mltDeleteTransition(QString tag, int a_track, int b_track, GenTime
     Mlt::Tractor tractor(service);
     Mlt::Field *field = tractor.field();
 
-    if (do_refresh) m_mltConsumer->set("refresh", 0);
+    //if (do_refresh) m_mltConsumer->set("refresh", 0);
     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");
     QString resource = mlt_properties_get(properties, "mlt_service");
-    int old_pos = (int)((in + out).frames(m_fps) / 2);
+
+    const int old_pos = (int)((in + out).frames(m_fps) / 2);
 
     while (mlt_type == "transition") {
         mlt_transition tr = (mlt_transition) nextservice;
         int currentTrack = mlt_transition_get_b_track(tr);
         int currentIn = (int) mlt_transition_get_in(tr);
         int currentOut = (int) mlt_transition_get_out(tr);
-        kDebug() << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack;
+        //kDebug() << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack;
 
         if (resource == tag && b_track == currentTrack && currentIn <= old_pos && currentOut >= old_pos) {
-            //kDebug() << " / / / / /DELETE TRANS DOOOMNE";
             mlt_field_disconnect_service(field->get_field(), nextservice);
             break;
         }
@@ -2055,7 +2172,7 @@ void Render::mltDeleteTransition(QString tag, int a_track, int b_track, GenTime
         mlt_type = mlt_properties_get(properties, "mlt_type");
         resource = mlt_properties_get(properties, "mlt_service");
     }
-    if (do_refresh) m_mltConsumer->set("refresh", 1);
+    //if (do_refresh) m_mltConsumer->set("refresh", 1);
 }
 
 QMap<QString, QString> Render::mltGetTransitionParamsFromXml(QDomElement xml) {
@@ -2245,8 +2362,8 @@ void Render::mltAddTransition(QString tag, int a_track, int b_track, GenTime in,
         transition->set_in_and_out((int) in.frames(m_fps), (int) out.frames(m_fps));
     QMap<QString, QString>::Iterator it;
     QString key;
-
-    kDebug() << " ------  ADDING TRANSITION PARAMs: " << args.count();
+    if (xml.attribute("automatic") == "1") transition->set("automatic", 1);
+    //kDebug() << " ------  ADDING TRANSITION PARAMs: " << args.count();
 
     for (it = args.begin(); it != args.end(); ++it) {
         key = it.key();
@@ -2273,7 +2390,32 @@ void Render::mltSavePlaylist() {
 
     fileConsumer.connect(service);
     fileConsumer.start();
+}
 
+QList <Mlt::Producer *> Render::producersList() {
+    QList <Mlt::Producer *> prods;
+    QStringList ids;
+    Mlt::Service service(m_mltProducer->parent().get_service());
+    Mlt::Tractor tractor(service);
+    Mlt::Field *field = tractor.field();
+
+    int trackNb = tractor.count();
+    for (int t = 1; t < trackNb; t++) {
+        Mlt::Producer trackProducer(tractor.track(t));
+        Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
+        int clipNb = trackPlaylist.count();
+        kDebug() << "// PARSING SCENE TRACK: " << t << ", CLIPS: " << clipNb;
+        for (int i = 0; i < clipNb; i++) {
+            Mlt::Producer *prod = trackPlaylist.get_clip(i);
+            Mlt::Producer *nprod = new Mlt::Producer(prod->get_parent());
+            //kDebug()<<"PROD: "<<nprod->get("producer")<<", ID: "<<nprod->get("id")<<nprod->get("resource");
+            if (nprod && !nprod->is_blank() && !ids.contains(nprod->get("id"))) {
+                ids.append(nprod->get("id"));
+                prods.append(nprod);
+            }
+        }
+    }
+    return prods;
 }
 
 #include "renderer.moc"