]> git.sesse.net Git - kdenlive/blobdiff - src/renderer.cpp
Fix freeze when making fast play / pause
[kdenlive] / src / renderer.cpp
index c70abc4eaab2ec182ad12506ba1bfa097f7f1b35..3e18730174c408034b15898a708d2a7d5a72019b 100644 (file)
@@ -71,14 +71,21 @@ static void consumer_frame_show(mlt_consumer, Render * self, mlt_frame frame_ptr
     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) {
+    if (frame.get_double("_speed") < 0.0 && mlt_frame_get_position(frame_ptr) <= 0) {
         self->pause();
         self->emitConsumerStopped();
     }
 }
 
+
+static void consumer_paused(mlt_consumer, Render * self, mlt_frame /*frame_ptr*/)
+{
+    // detect if the producer has finished playing. Is there a better way to do it?
+    if (self->m_isBlocked) return;
+    self->emitConsumerStopped();
+}
+
+
 static void consumer_gl_frame_show(mlt_consumer, Render * self, mlt_frame frame_ptr)
 {
     // detect if the producer has finished playing. Is there a better way to do it?
@@ -94,10 +101,9 @@ static void consumer_gl_frame_show(mlt_consumer, Render * self, mlt_frame frame_
 }
 
 Render::Render(const QString & rendererName, int winid, QString profile, QWidget *parent) :
-    QObject(parent),
+    AbstractRender(rendererName, parent),
     m_isBlocked(0),
     analyseAudio(KdenliveSettings::monitor_audio()),
-    sendFrameForAnalysis(false),
     m_name(rendererName),
     m_mltConsumer(NULL),
     m_mltProducer(NULL),
@@ -241,6 +247,7 @@ void Render::buildConsumer(const QString profileName)
         m_mltConsumer = new Mlt::Consumer(*m_mltProfile, "sdl_preview");
         // FIXME: the event object returned by the listen gets leaked...
         m_mltConsumer->listen("consumer-frame-show", this, (mlt_listener) consumer_frame_show);
+        m_mltConsumer->listen("consumer-sdl-paused", this, (mlt_listener) consumer_paused);
         m_mltConsumer->set("window_id", m_winid);
     }
     m_mltConsumer->set("resize", 1);
@@ -283,6 +290,7 @@ Mlt::Producer *Render::invalidProducer(const QString &id)
 
 int Render::resetProfile(const QString profileName)
 {
+    QString scene = sceneList();
     if (m_mltConsumer) {
         if (m_externalConsumer == KdenliveSettings::external_display()) {
             if (KdenliveSettings::external_display() && m_activeProfile == profileName) return 1;
@@ -303,9 +311,9 @@ int Render::resetProfile(const QString profileName)
         delete m_mltConsumer;
         m_mltConsumer = NULL;
     }
-    QString scene = sceneList();
     int pos = 0;
     double current_fps = m_mltProfile->fps();
+    double current_dar = m_mltProfile->dar();
     delete m_blackClip;
     m_blackClip = NULL;
 
@@ -327,6 +335,7 @@ int Render::resetProfile(const QString profileName)
     m_mltProducer = NULL;
     buildConsumer(profileName);
     double new_fps = m_mltProfile->fps();
+    double new_dar = m_mltProfile->dar();
     if (current_fps != new_fps) {
         // fps changed, we must update the scenelist positions
         scene = updateSceneListFps(current_fps, new_fps, scene);
@@ -334,7 +343,7 @@ int Render::resetProfile(const QString profileName)
     //kDebug() << "//RESET WITHSCENE: " << scene;
     setSceneList(scene, pos);
     // producers have changed (different profile), so reset them...
-    emit refreshDocumentProducers();
+    emit refreshDocumentProducers(new_dar != current_dar);
     /*Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "xml-string", scene.toUtf8().constData());
     m_mltProducer = producer;
     m_blackClip = new Mlt::Producer(*m_mltProfile , "colour", "black");
@@ -406,14 +415,26 @@ int Render::renderHeight() const
     return m_mltProfile->height();
 }
 
-QImage Render::extractFrame(int frame_position, int width, int height)
+QImage Render::extractFrame(int frame_position, QString path, int width, int height)
 {
     if (width == -1) {
         width = renderWidth();
         height = renderHeight();
     } else if (width % 2 == 1) width++;
 
-    if (!m_mltProducer) {
+    if (!path.isEmpty()) {
+        Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile, path.toUtf8().constData());
+        if (producer) {
+            if (producer->is_valid()) {
+                QImage img = KThumb::getFrame(producer, frame_position, width, height);
+                delete producer;
+                return img;
+            }
+            else delete producer;
+        }
+    }
+    
+    if (!m_mltProducer || !path.isEmpty()) {
         QImage pix(width, height, QImage::Format_RGB32);
         pix.fill(Qt::black);
         return pix;
@@ -545,10 +566,17 @@ void Render::slotSplitView(bool doit)
 void Render::getFileProperties(const QDomElement xml, const QString &clipId, int imageHeight, bool replaceProducer, bool selectClip)
 {
     QString path;
-    if (xml.hasAttribute("proxy") && xml.attribute("proxy") != "-") path = xml.attribute("proxy");
-    else path = xml.attribute("resource");
-    
-    
+    bool proxyProducer;
+    if (xml.hasAttribute("proxy") && xml.attribute("proxy") != "-") {
+        path = xml.attribute("proxy");
+        proxyProducer = true;
+    }
+    else {
+        path = xml.attribute("resource");
+        proxyProducer = false;
+    }
+
+
     KUrl url = KUrl(path);
     Mlt::Producer *producer = NULL;
     CLIPTYPE type = (CLIPTYPE)xml.attribute("type").toInt();
@@ -576,17 +604,28 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int
         producer = new Mlt::Producer(*m_mltProfile, url.path().toUtf8().constData());
     }
 
+
     if (producer == NULL || producer->is_blank() || !producer->is_valid()) {
         kDebug() << " / / / / / / / / ERROR / / / / // CANNOT LOAD PRODUCER: ";
-        if (xml.hasAttribute("proxy") && xml.attribute("proxy") != "-") {
+        if (proxyProducer) {
             // Proxy file is corrupted
-            emit removeInvalidProxy(clipId);
+            emit removeInvalidProxy(clipId, false);
         }
         else emit removeInvalidClip(clipId, replaceProducer);
         delete producer;
         return;
     }
 
+    if (proxyProducer && xml.hasAttribute("proxy_out")) {
+        producer->set("out", xml.attribute("proxy_out").toInt());
+        if (producer->get_out() != xml.attribute("proxy_out").toInt()) {
+            // Proxy file length is different than original clip length, this will corrupt project so disable this proxy clip
+            emit removeInvalidProxy(clipId, true);
+            delete producer;
+            return;
+        }
+    }
+
     if (xml.hasAttribute("force_aspect_ratio")) {
         double aspect = xml.attribute("force_aspect_ratio").toDouble();
         if (aspect > 0) producer->set("force_aspect_ratio", aspect);
@@ -636,11 +675,11 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int
         int full_luma = xml.attribute("full_luma").toInt();
         if (full_luma != 0) producer->set("set.force_full_luma", full_luma);
     }
-    
+
     int clipOut = 0;
     int duration = 0;
     if (xml.hasAttribute("out")) clipOut = xml.attribute("out").toInt();
-    
+
     // setup length here as otherwise default length (currently 15000 frames in MLT) will be taken even if outpoint is larger
     if (type == COLOR || type == TEXT || type == IMAGE || type == SLIDESHOW) {
         int length;
@@ -762,7 +801,7 @@ void Render::getFileProperties(const QDomElement xml, const QString &clipId, int
                     variance = KThumb::imageVariance(image);
                 } else
                     pix.fill(Qt::black);
-                
+
                 if (frameNumber == 0 && variance < 6) {
                     // Thumbnail is not interesting (for example all black, seek to fetch better thumb
                     frameNumber = 100;
@@ -988,6 +1027,7 @@ int Render::setSceneList(QString playlist, int position)
                 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());
@@ -1237,7 +1277,6 @@ void Render::stop()
     if (m_mltProducer == NULL) return;
     if (m_mltConsumer && !m_mltConsumer->is_stopped()) {
         kDebug() << "/////////////   RENDER STOPPED: " << m_name;
-        m_isBlocked = true;
         //m_mltConsumer->set("refresh", 0);
         m_mltConsumer->stop();
         // delete m_mltConsumer;
@@ -1283,36 +1322,24 @@ void Render::pause()
     m_mltConsumer->purge();
 }
 
-void Render::switchPlay()
+void Render::switchPlay(bool play)
 {
     if (!m_mltProducer || !m_mltConsumer)
         return;
     if (m_isZoneMode) resetZoneMode();
-    if (m_mltProducer->get_speed() == 0.0) {
+    if (play && m_mltProducer->get_speed() == 0.0) {
         m_isBlocked = false;
         if (m_name == "clip" && m_framePosition == (int) m_mltProducer->get_out()) m_mltProducer->seek(0);
         m_mltProducer->set_speed(1.0);
         m_mltConsumer->set("refresh", 1);
-    } else {
+    } else if (!play) {
         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();
-        //kDebug()<<" *********  RENDER PAUSE: "<<m_mltProducer->get_speed();
-        //m_mltConsumer->set("refresh", 0);
-        /*mlt_position position = mlt_producer_position( m_mltProducer->get_producer() );
-        m_mltProducer->set_speed(0);
-        m_mltProducer->seek( position );
-               //m_mltProducer->seek((int) m_framePosition);
-               m_isBlocked = false;*/
+        //m_mltConsumer->purge();
     }
-    /*if (speed == 0.0) {
-    m_mltProducer->seek((int) m_framePosition + 1);
-        m_mltConsumer->purge();
-    }*/
-    //refresh();
 }
 
 void Render::play(double speed)
@@ -1620,7 +1647,7 @@ Mlt::Producer *Render::checkSlowMotionProducer(Mlt::Producer *prod, QDomElement
     if (strobe > 1) url.append("&strobe=" + QString::number(strobe));
     Mlt::Producer *slowprod = m_slowmotionProducers.value(url);
     if (!slowprod || slowprod->get_producer() == NULL) {
-        slowprod = new Mlt::Producer(*m_mltProfile, "framebuffer", url.toUtf8().constData());
+        slowprod = new Mlt::Producer(*m_mltProfile, 0, ("framebuffer:" + url).toUtf8().constData());
         if (strobe > 1) slowprod->set("strobe", strobe);
         QString id = prod->get("id");
         if (id.contains('_')) id = id.section('_', 0, 0);
@@ -1793,7 +1820,7 @@ bool Render::mltUpdateClip(ItemInfo info, QDomElement element, Mlt::Producer *pr
         return false;
     }
     Mlt::Tractor tractor(service);
-    Mlt::Producer trackProducer(tractor.track(info.track));
+    Mlt::Producer trackProducer(tractor.track(tractor.count() - 1 - info.track));
     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
     int startPos = info.startPos.frames(m_fps);
     int clipIndex = trackPlaylist.get_clip_index_at(startPos);
@@ -2449,7 +2476,6 @@ bool Render::mltAddEffect(Mlt::Service service, EffectsParameterList params, int
     // create filter
     QString tag =  params.paramValue("tag");
     kDebug() << " / / INSERTING EFFECT: " << tag << ", REGI: " << region;
-    if (tag.startsWith("ladspa")) tag = "ladspa";
     char *filterTag = qstrdup(tag.toUtf8().constData());
     char *filterId = qstrdup(params.paramValue("id").toUtf8().constData());
     QHash<QString, QString>::Iterator it;
@@ -2631,10 +2657,12 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par
     if (!params.paramValue("keyframes").isEmpty() || /*it.key().startsWith("#") || */tag.startsWith("ladspa") || tag == "sox" || tag == "autotrack_rectangle" || params.hasParam("region")) {
         // This is a keyframe effect, to edit it, we remove it and re-add it.
         bool success = mltRemoveEffect(track, position, index, false);
-        if (!success) kDebug() << "// ERROR Removing effect : " << index;
-        if (position < GenTime()) success = mltAddTrackEffect(track, params);
-        else success = mltAddEffect(track, position, params);
-        if (!success) kDebug() << "// ERROR Adding effect : " << index;
+//         if (!success) kDebug() << "// ERROR Removing effect : " << index;
+        if (position < GenTime())
+            success = mltAddTrackEffect(track, params);
+        else
+            success = mltAddEffect(track, position, params);
+//         if (!success) kDebug() << "// ERROR Adding effect : " << index;
         return success;
     }
     if (position < GenTime()) {
@@ -2653,33 +2681,22 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par
         return false;
     }
 
-    Mlt::Service clipService(clip->get_service());
     int duration = clip->get_playtime();
     bool doRefresh = true;
     // Check if clip is visible in monitor
     int diff = trackPlaylist.clip_start(clipIndex) + duration - m_mltProducer->position();
-    if (diff < 0 || diff > duration) doRefresh = false;
-    delete clip;
+    if (diff < 0 || diff > duration)
+        doRefresh = false;
     m_isBlocked = true;
     int ct = 0;
-    /* kDebug() << "EDITING FILTER: "<<index <<", "<<tag;
-    kDebug() << "EFFect stack: ++++++++++++++++++++++++++";
-    while (filter) {
-        kDebug() << "Filter: "<< filter->get("kdenlive_id") <<", IX: "<<filter->get("kdenlive_ix");
-        ct++;
-        filter = clipService.filter(ct);
-    }
-    kDebug() << "++++++++++++++++++++++++++";
-    ct = 0;
-    filter = clipService.filter(ct); */
 
-    Mlt::Filter *filter = clipService.filter(ct);
+    Mlt::Filter *filter = clip->filter(ct);
     while (filter) {
         if (filter->get_int("kdenlive_ix") == index.toInt()) {
             break;
         }
         ct++;
-        filter = clipService.filter(ct);
+        filter = clip->filter(ct);
     }
 
     if (!filter) {
@@ -2697,6 +2714,11 @@ bool Render::mltEditEffect(int track, GenTime position, EffectsParameterList par
     for (int j = 0; j < params.count(); j++) {
         filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData());
     }
+
+    if (params.paramValue("id") == "pan_zoom")
+        filter->set_in_and_out(clip->get_in(), clip->get_out() + 1);
+
+    delete clip;
     mlt_service_unlock(service.get_service());
 
     m_isBlocked = false;
@@ -3824,12 +3846,12 @@ const QList <Mlt::Producer *> Render::producersList()
         delete tt;
         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 *c = trackPlaylist.get_clip(i);
             Mlt::Producer *nprod = new Mlt::Producer(c->get_parent());
             if (nprod) {
-                if (!nprod->is_blank() && !ids.contains(nprod->get("id"))) {
+                QString prodId = nprod->get("id");
+                if (!prodId.startsWith("slowmotion") && !prodId.isEmpty() && !nprod->is_blank() && !ids.contains(prodId)) {
                     ids.append(nprod->get("id"));
                     prods.append(nprod);
                 } else delete nprod;
@@ -4000,17 +4022,7 @@ void Render::mltDeleteTrack(int ix)
     tractor.removeChild(track);
     //kDebug() << "/////////// RESULT SCENE: \n" << doc.toString();
     setSceneList(doc.toString(), m_framePosition);
-
-    /*    if (m_mltProducer != NULL) {
-            Mlt::Producer parentProd(m_mltProducer->parent());
-            if (parentProd.get_producer() != NULL) {
-                Mlt::Service service(parentProd.get_service());
-                if (service.type() == tractor_type) {
-                    Mlt::Tractor tractor(service);
-                    mltCheckLength(&tractor);
-                }
-            }
-        }*/
+    emit refreshDocumentProducers(false);
 }
 
 
@@ -4139,6 +4151,11 @@ void Render::sendFrameUpdate()
     }
 }
 
+Mlt::Producer* Render::getProducer()
+{
+    return m_mltProducer;
+}
+
 
 #include "renderer.moc"