]> git.sesse.net Git - kdenlive/blobdiff - src/renderer.cpp
Many improvements to title clips (recreate when missing, fix text selection visible...
[kdenlive] / src / renderer.cpp
index 253a5545edd4427efbfac528cd4c69c19fe53466..74b6ceb2b870eaf7ee01f798f2d9d05a4fa6de80 100644 (file)
@@ -65,21 +65,19 @@ 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(-1), m_framePosition(0), m_generateScenelist(false), 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()));
 
     m_osdProfile =   KStandardDirs::locate("data", "kdenlive/profiles/metadata.properties");
     buildConsumer();
 
-    m_externalwinid = extid;
-    m_winid = winid;
     Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "colour", "black");
     m_mltProducer = producer;
     if (m_blackClip) delete m_blackClip;
@@ -122,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);
@@ -203,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
@@ -467,6 +469,9 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
 
     KUrl url = KUrl(xml.attribute("resource", QString::null));
     Mlt::Producer *producer;
+    if (xml.attribute("type").toInt() == TEXT && !QFile::exists(url.path())) {
+        return;
+    }
     if (xml.attribute("type").toInt() == COLOR) {
         char *tmp = decodedString("colour:" + xml.attribute("colour"));
         producer = new Mlt::Producer(*m_mltProfile, "fezzik", tmp);
@@ -478,14 +483,22 @@ 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("out")) producer->set_in_and_out(xml.attribute("in").toInt(), xml.attribute("out").toInt());
 
@@ -501,7 +514,6 @@ 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();
 
@@ -560,7 +572,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);
 
@@ -581,6 +593,11 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
 
     AVFormatContext *context = (AVFormatContext *) mlt_properties_get_data(properties, "video_context", NULL);
     if (context != NULL) {
+        /*if (context->duration == AV_NOPTS_VALUE) {
+        kDebug() << " / / / / / / / /ERRROR / / / CLIP HAS UNKNOWN DURATION";
+            emit removeInvalidClip(clipId);
+            return;
+        }*/
         // Get the video_index
         int index = mlt_properties_get_int(properties, "video_index");
 
@@ -667,12 +684,12 @@ void Render::initSceneList() {
 /** Create the producer from the Westley QDomDocument */
 void Render::setProducer(Mlt::Producer *producer, int position) {
     if (m_winid == -1) return;
-    m_generateScenelist = true;
 
     if (m_mltConsumer) {
         m_mltConsumer->stop();
     } else return;
 
+    m_isBlocked = true;
     if (m_mltProducer) {
         m_mltProducer->set_speed(0);
         delete m_mltProducer;
@@ -689,7 +706,7 @@ void Render::setProducer(Mlt::Producer *producer, int position) {
         m_mltProducer->seek(position);
         emit rendererPosition(position);
     }
-    m_generateScenelist = false;
+    m_isBlocked = false;
 }
 
 
@@ -702,18 +719,10 @@ void Render::setSceneList(QDomDocument list, int position) {
 /** Create the producer from the Westley QDomDocument */
 void Render::setSceneList(QString playlist, int position) {
     if (m_winid == -1) return;
-    m_generateScenelist = true;
+    m_isBlocked = true;
 
     kWarning() << "//////  RENDER, SET SCENE LIST: " << playlist;
 
-
-    /*
-        if (!clip.is_valid()) {
-     kWarning()<<" ++++ WARNING, UNABLE TO CREATE MLT PRODUCER";
-     m_generateScenelist = false;
-     return;
-        }*/
-
     if (m_mltConsumer) {
         m_mltConsumer->stop();
         //m_mltConsumer->set("refresh", 0);
@@ -764,10 +773,12 @@ void Render::setSceneList(QString playlist, int position) {
     kDebug() << "// NEW SCENE LIST DURATION SET TO: " << m_mltProducer->get_playtime();
     connectPlaylist();
     if (position != 0) {
-        m_mltProducer->seek(position);
-        emit rendererPosition(position);
+        //TODO: seek to correct place after opening project.
+        //  Needs to be done from another place since it crashes here.
+        //m_mltProducer->seek(position);
+        //emit rendererPosition(position);
     }
-    m_generateScenelist = false;
+    m_isBlocked = false;
 
 }
 
@@ -803,7 +814,6 @@ void Render::saveSceneList(QString path, QDomElement kdenliveData) {
     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()) {}
     if (!kdenliveData.isNull()) {
@@ -826,6 +836,38 @@ void Render::saveSceneList(QString path, QDomElement kdenliveData) {
 }
 
 
+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;
 }
@@ -901,7 +943,7 @@ void Render::start() {
         return;
     }
 
-    if (m_mltConsumer->is_stopped()) {
+    if (m_mltConsumer && m_mltConsumer->is_stopped()) {
         kDebug() << "-----  MONITOR: " << m_name << " WAS STOPPED";
         if (m_mltConsumer->start() == -1) {
             KMessageBox::error(qApp->activeWindow(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it."));
@@ -938,14 +980,17 @@ void Render::stop() {
         m_isBlocked = true;
         m_mltConsumer->set("refresh", 0);
         m_mltConsumer->stop();
+        // delete m_mltConsumer;
+        // m_mltConsumer = NULL;
     }
     kDebug() << "/////////////   RENDER STOP2-------";
     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();
+        //m_mltProducer->set("out", m_mltProducer->get_length() - 1);
+        //kDebug() << m_mltProducer->get_length();
     }
     kDebug() << "/////////////   RENDER STOP3-------";
 }
@@ -954,6 +999,7 @@ 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));
     }
@@ -961,19 +1007,20 @@ void Render::stop(const GenTime & startTime) {
 }
 
 void Render::switchPlay() {
-    if (!m_mltProducer)
+    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() );
@@ -990,10 +1037,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);
@@ -1002,44 +1049,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();
 }
@@ -1051,7 +1102,7 @@ void Render::askForRefresh() {
 
 void Render::doRefresh() {
     // Use a Timer so that we don't refresh too much
-    m_mltConsumer->set("refresh", 1);
+    if (!m_isBlocked && m_mltConsumer) m_mltConsumer->set("refresh", 1);
 }
 
 void Render::refresh() {
@@ -1063,17 +1114,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;
@@ -1091,7 +1131,6 @@ const QString & Render::rendererName() const {
 
 
 void Render::emitFrameNumber(double position) {
-    //if (m_generateScenelist) return;
     m_framePosition = position;
     emit rendererPosition((int) position);
     //if (qApp->activeWindow()) QApplication::postEvent(qApp->activeWindow(), new PositionChangeEvent( GenTime((int) position, m_fps), m_monitorId));
@@ -1099,8 +1138,10 @@ void Render::emitFrameNumber(double position) {
 
 void Render::emitConsumerStopped() {
     // This is used to know when the playing stopped
-    if (m_mltProducer && !m_generateScenelist) {
+    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));
@@ -1217,8 +1258,8 @@ void Render::mltInsertClip(ItemInfo info, QDomElement element, Mlt::Producer *pr
     mlt_service_lock(service.get_service());
     Mlt::Producer trackProducer(tractor.track(info.track));
     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
-
-    Mlt::Producer *clip = prod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps) - 1);
+    //kDebug()<<"/// INSERT cLIP: "<<info.cropStart.frames(m_fps)<<", "<<info.startPos.frames(m_fps)<<"-"<<info.endPos.frames(m_fps);
+    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)
@@ -2275,7 +2316,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"