]> git.sesse.net Git - kdenlive/blobdiff - src/renderer.cpp
Add, edit and delete markers from clip properties dialog
[kdenlive] / src / renderer.cpp
index 8d370c240cf9d810c81ac13dd90634d9870d9926..04f30cf01cc904d1a1d55e5f99515e038d23484f 100644 (file)
@@ -42,9 +42,14 @@ extern "C" {
 #include "renderer.h"
 #include "kdenlivesettings.h"
 #include "kthumb.h"
-//#include <ffmpeg/avformat.h>
+
 #include <mlt++/Mlt.h>
 
+#if LIBAVCODEC_VERSION_MAJOR > 51 || (LIBAVCODEC_VERSION_MAJOR > 50 && LIBAVCODEC_VERSION_MINOR > 54)
+// long_name was added in FFmpeg avcodec version 51.55
+#define ENABLE_FFMPEG_CODEC_DESCRIPTION 1
+#endif
+
 static void consumer_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 ?
     //if (self->isBlocked) return;
@@ -422,10 +427,15 @@ void Render::getFileProperties(const QDomElement &xml, int clipId) {
             else
                 filePropertyMap["type"] = "video";
 
-            // Generate thumbnail for this frame
-            QPixmap pixmap = KThumb::getFrame(&producer, 0, width, height);
 
-            emit replyGetImage(clipId, 0, pixmap, width, height);
+            QPixmap pix(width, height);
+            mlt_image_format format = mlt_image_rgb24a;
+            const uint8_t *thumb = frame->get_image(format, width, height);
+            QImage image(thumb, width, height, QImage::Format_ARGB32);
+            if (!image.isNull()) {
+                pix = pix.fromImage(image);
+            } else pix.fill(Qt::black);
+            emit replyGetImage(clipId, 0, pix, width, height);
 
         } else if (frame->get_int("test_audio") == 0) {
             QPixmap pixmap(KStandardDirs::locate("appdata", "graphics/music.png"));
@@ -442,15 +452,27 @@ void Render::getFileProperties(const QDomElement &xml, int clipId) {
     if (context != NULL) {
         // Get the video_index
         int index = mlt_properties_get_int(properties, "video_index");
-        if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
-            filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->name;
+
+#if ENABLE_FFMPEG_CODEC_DESCRIPTION
+        if (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)
+                filePropertyMap["videocodec"] = context->streams[ index ]->codec->codec->name;
     }
     context = (AVFormatContext *) mlt_properties_get_data(properties, "audio_context", NULL);
     if (context != NULL) {
         // Get the video_index
         int index = mlt_properties_get_int(properties, "audio_index");
-        if (context->streams && context->streams [index] && context->streams[ index ]->codec && context->streams[ index ]->codec->codec->name)
-            filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->name;
+
+#if ENABLE_FFMPEG_CODEC_DESCRIPTION
+        if (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)
+                filePropertyMap["audiocodec"] = context->streams[ index ]->codec->codec->name;
     }
 #endif
     // metadata
@@ -516,7 +538,7 @@ void Render::setSceneList(QString playlist, int position) {
     if (m_winid == -1) return;
     m_generateScenelist = true;
 
-    //kWarning() << "//////  RENDER, SET SCENE LIST: " << playlist;
+    // kWarning() << "//////  RENDER, SET SCENE LIST: " << playlist;
 
 
     /*
@@ -956,7 +978,7 @@ void Render::mltCheckLength(bool reload) {
     Mlt::Producer blackTrackProducer(tractor.track(0));
     Mlt::Playlist blackTrackPlaylist((mlt_playlist) blackTrackProducer.get_service());
     double blackDuration = Mlt::Producer(blackTrackPlaylist.get_producer()).get_playtime() - 1;
-    kDebug() << " / / /DURATON FOR TRACK 0 = " << blackDuration;
+
     if (blackDuration != duration) {
         blackTrackPlaylist.remove_region(0, (int)blackDuration);
         int i = 0;
@@ -965,17 +987,19 @@ void Render::mltCheckLength(bool reload) {
         QDomElement black = doc.createElement("producer");
         black.setAttribute("mlt_service", "colour");
         black.setAttribute("colour", "black");
+        //black.setAttribute("id", "black");
         black.setAttribute("in", "0");
         black.setAttribute("out", "13999");
-        while (dur > 14000) { // <producer mlt_service=\"colour\" colour=\"black\" in=\"0\" out=\"13999\" />
+        while (dur > 14000) {
             mltInsertClip(0, GenTime(i * 14000, m_fps), black);
             dur = dur - 14000;
             i++;
         }
-        black.setAttribute("out", QString::number(dur));
-        mltInsertClip(0, GenTime(), black);
-
-        m_mltProducer->set("out", duration);
+        if (dur > 0) {
+            black.setAttribute("out", QString::number(dur));
+            mltInsertClip(0, GenTime(i * 14000, m_fps), black);
+        }
+        //m_mltProducer->set("out", duration);
         emit durationChanged((int)duration);
     }
 }
@@ -990,9 +1014,10 @@ void Render::mltInsertClip(int track, GenTime position, QDomElement element) {
         kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////";
         return;
     }
+
     Mlt::Service service(parentProd.get_service());
     Mlt::Tractor tractor(service);
-
+    mlt_service_lock(service.get_service());
     Mlt::Producer trackProducer(tractor.track(track));
     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
 
@@ -1003,11 +1028,11 @@ void Render::mltInsertClip(int track, GenTime position, QDomElement element) {
     Mlt::Producer clip(*m_mltProfile, "westley-xml", tmp);
     //clip.set_in_and_out(in.frames(m_fps), out.frames(m_fps));
     delete[] tmp;
-
     trackPlaylist.insert_at((int) position.frames(m_fps), clip, 1);
+    mlt_service_unlock(service.get_service());
     if (track != 0) mltCheckLength();
-    tractor.multitrack()->refresh();
-    tractor.refresh();
+    //tractor.multitrack()->refresh();
+    //tractor.refresh();
 }
 
 void Render::mltCutClip(int track, GenTime position) {
@@ -1177,22 +1202,22 @@ void Render::mltEditEffect(int track, GenTime position, QMap <QString, QString>
 
     if (!filter) {
         kDebug() << "WARINIG, FILTER FOR EDITING NOT FOUND, ADDING IT!!!!!";
-       // filter was not found, it was probably a disabled filter, so add it to the correct place...
-       int ct = 0;
-       filter = clipService.filter(ct);
-       QList <Mlt::Filter *> filtersList;
-       while (filter) {
-           if (QString(filter->get("kdenlive_ix")).toInt() > index.toInt()) {
-               filtersList.append(filter);
-               clipService.detach(*filter);
-           } else ct++;
-           filter = clipService.filter(ct);
-       }
+        // filter was not found, it was probably a disabled filter, so add it to the correct place...
+        int ct = 0;
+        filter = clipService.filter(ct);
+        QList <Mlt::Filter *> filtersList;
+        while (filter) {
+            if (QString(filter->get("kdenlive_ix")).toInt() > index.toInt()) {
+                filtersList.append(filter);
+                clipService.detach(*filter);
+            } else ct++;
+            filter = clipService.filter(ct);
+        }
         mltAddEffect(track, position, args);
 
-       for (int i = 0; i < filtersList.count(); i++) {
-           clipService.attach(*(filtersList.at(i)));
-       }
+        for (int i = 0; i < filtersList.count(); i++) {
+            clipService.attach(*(filtersList.at(i)));
+        }
 
         m_isBlocked = false;
         return;
@@ -1212,7 +1237,7 @@ void Render::mltEditEffect(int track, GenTime position, QMap <QString, QString>
 
 void Render::mltMoveEffect(int track, GenTime position, int oldPos, int newPos) {
 
-    kDebug() << "MOVING EFFECT FROM " << oldPos<< ", TO: " << newPos;
+    kDebug() << "MOVING EFFECT FROM " << oldPos << ", TO: " << newPos;
     Mlt::Service service(m_mltProducer->parent().get_service());
 
     Mlt::Tractor tractor(service);
@@ -1231,51 +1256,50 @@ void Render::mltMoveEffect(int track, GenTime position, int oldPos, int newPos)
     Mlt::Filter *filter = clipService.filter(ct);
     bool found = false;
     if (newPos > oldPos) {
-       while (filter) {
-           if (!found && QString(filter->get("kdenlive_ix")).toInt() == oldPos) {
-               filter->set("kdenlive_ix", newPos);
-               filtersList.append(filter);
-               clipService.detach(*filter);
-               filter = clipService.filter(ct);
-               while (filter && QString(filter->get("kdenlive_ix")).toInt() <= newPos) {
-                   filter->set("kdenlive_ix", QString(filter->get("kdenlive_ix")).toInt() - 1);
-                   ct++;
-                   filter = clipService.filter(ct);
-               }
-               found = true;
-           }
-           if (filter && QString(filter->get("kdenlive_ix")).toInt() > newPos) {
-               filtersList.append(filter);
-               clipService.detach(*filter);
-           } else ct++;
-           filter = clipService.filter(ct);
-       }
-    }
-    else {
-       while (filter) {
-           if (QString(filter->get("kdenlive_ix")).toInt() == oldPos) {
-               filter->set("kdenlive_ix", newPos);
-               filtersList.append(filter);
-               clipService.detach(*filter);
-           } else ct++;
-           filter = clipService.filter(ct);
-       }
-
-       ct = 0;
-       filter = clipService.filter(ct);
-       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);
-               filtersList.append(filter);
-               clipService.detach(*filter);
-           } else ct++;
-           filter = clipService.filter(ct);
-       }
+        while (filter) {
+            if (!found && QString(filter->get("kdenlive_ix")).toInt() == oldPos) {
+                filter->set("kdenlive_ix", newPos);
+                filtersList.append(filter);
+                clipService.detach(*filter);
+                filter = clipService.filter(ct);
+                while (filter && QString(filter->get("kdenlive_ix")).toInt() <= newPos) {
+                    filter->set("kdenlive_ix", QString(filter->get("kdenlive_ix")).toInt() - 1);
+                    ct++;
+                    filter = clipService.filter(ct);
+                }
+                found = true;
+            }
+            if (filter && QString(filter->get("kdenlive_ix")).toInt() > newPos) {
+                filtersList.append(filter);
+                clipService.detach(*filter);
+            } else ct++;
+            filter = clipService.filter(ct);
+        }
+    } else {
+        while (filter) {
+            if (QString(filter->get("kdenlive_ix")).toInt() == oldPos) {
+                filter->set("kdenlive_ix", newPos);
+                filtersList.append(filter);
+                clipService.detach(*filter);
+            } else ct++;
+            filter = clipService.filter(ct);
+        }
+
+        ct = 0;
+        filter = clipService.filter(ct);
+        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);
+                filtersList.append(filter);
+                clipService.detach(*filter);
+            } else ct++;
+            filter = clipService.filter(ct);
+        }
     }
-    
+
     for (int i = 0; i < filtersList.count(); i++) {
-       clipService.attach(*(filtersList.at(i)));
+        clipService.attach(*(filtersList.at(i)));
     }
 
     m_isBlocked = false;
@@ -1382,11 +1406,10 @@ void Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn
     Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service());
     int clipIndex = trackPlaylist.get_clip_index_at(moveStart + 1);
 
-    Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
-    trackPlaylist.consolidate_blanks(0);
-    //mlt_events_block( MLT_PRODUCER_PROPERTIES(clipProducer.get_producer()), NULL );
-
     if (endTrack == startTrack) {
+        mlt_service_lock(service.get_service());
+        Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
+        trackPlaylist.consolidate_blanks(0);
         if (!trackPlaylist.is_blank_at(moveEnd)) {
             kWarning() << "// ERROR, CLIP COLLISION----------";
             int ix = trackPlaylist.get_clip_index_at(moveEnd);
@@ -1394,30 +1417,33 @@ void Render::mltMoveClip(int startTrack, int endTrack, int moveStart, int moveEn
         }
         trackPlaylist.insert_at(moveEnd, clipProducer, 1);
         trackPlaylist.consolidate_blanks(0);
+        mlt_service_unlock(service.get_service());
     } else {
+        Mlt::Producer clipProducer(trackPlaylist.replace_with_blank(clipIndex));
         trackPlaylist.consolidate_blanks(0);
+
         Mlt::Producer destTrackProducer(tractor.track(endTrack));
         Mlt::Playlist destTrackPlaylist((mlt_playlist) destTrackProducer.get_service());
         destTrackPlaylist.consolidate_blanks(1);
         destTrackPlaylist.insert_at(moveEnd, clipProducer, 1);
         destTrackPlaylist.consolidate_blanks(0);
     }
-
     mltCheckLength();
     m_isBlocked = false;
     m_mltConsumer->set("refresh", 1);
-    //mlt_events_unblock( MLT_PRODUCER_PROPERTIES(clipProducer.get_producer()), NULL );
 }
 
-void Render::mltMoveTransition(QString type, int startTrack, int trackOffset, GenTime oldIn, GenTime oldOut, GenTime newIn, GenTime newOut) {
-    m_isBlocked = true;
+void Render::mltMoveTransition(QString type, int startTrack, int newTrack, int newTransitionTrack, GenTime oldIn, GenTime oldOut, GenTime newIn, GenTime newOut) {
+
     Mlt::Service service(m_mltProducer->parent().get_service());
     Mlt::Tractor tractor(service);
     Mlt::Field *field = tractor.field();
 
+    mlt_service_lock(service.get_service());
     m_mltConsumer->set("refresh", 0);
-    mlt_service serv = m_mltProducer->parent().get_service();
+    m_isBlocked = true;
 
+    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");
@@ -1425,7 +1451,7 @@ void Render::mltMoveTransition(QString type, int startTrack, int trackOffset, Ge
     int old_pos = (int)(oldIn.frames(m_fps) + oldOut.frames(m_fps)) / 2;
 
     int new_in = (int)newIn.frames(m_fps);
-    int new_out = (int)newOut.frames(m_fps) - 1;
+    int new_out = (int)newOut.frames(m_fps);
 
     while (mlt_type == "transition") {
         mlt_transition tr = (mlt_transition) nextservice;
@@ -1435,21 +1461,24 @@ void Render::mltMoveTransition(QString type, int startTrack, int trackOffset, Ge
 
         if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) {
             mlt_transition_set_in_and_out(tr, new_in, new_out);
-            if (trackOffset != 0) {
+            if (newTrack - startTrack != 0) {
+                kDebug() << "///// TRANSITION CHANGE TRACK. CUrrent (b): " << currentTrack << "x" << mlt_transition_get_a_track(tr) << ", NEw: " << newTrack << "x" << newTransitionTrack;
+
                 mlt_properties properties = MLT_TRANSITION_PROPERTIES(tr);
-                mlt_properties_set_int(properties, "a_track", mlt_transition_get_a_track(tr) + trackOffset);
-                mlt_properties_set_int(properties, "b_track", mlt_transition_get_b_track(tr) + trackOffset);
+                mlt_properties_set_int(properties, "a_track", newTransitionTrack);
+                mlt_properties_set_int(properties, "b_track", newTrack);
                 //kDebug() << "set new start & end :" << new_in << new_out<< "TR OFFSET: "<<trackOffset<<", TRACKS: "<<mlt_transition_get_a_track(tr)<<"x"<<mlt_transition_get_b_track(tr);
             }
-
             break;
         }
         nextservice = mlt_service_producer(nextservice);
+        if (nextservice == NULL) break;
         properties = MLT_SERVICE_PROPERTIES(nextservice);
         mlt_type = mlt_properties_get(properties, "mlt_type");
         resource = mlt_properties_get(properties, "mlt_service");
     }
     m_isBlocked = false;
+    mlt_service_unlock(service.get_service());
     m_mltConsumer->set("refresh", 1);
 }
 
@@ -1486,6 +1515,8 @@ void Render::mltUpdateTransitionParams(QString type, int a_track, int b_track, G
         int currentIn = (int) mlt_transition_get_in(tr);
         int currentOut = (int) mlt_transition_get_out(tr);
 
+        // kDebug()<<"Looking for transition : " << currentIn <<"x"<<currentOut<< ", OLD oNE: "<<in_pos<<"x"<<out_pos;
+
         if (resource == type && b_track == currentTrack && currentIn == in_pos && currentOut == out_pos) {
             QMap<QString, QString> map = mltGetTransitionParamsFromXml(xml);
             QMap<QString, QString>::Iterator it;
@@ -1505,6 +1536,7 @@ void Render::mltUpdateTransitionParams(QString type, int a_track, int b_track, G
             break;
         }
         nextservice = mlt_service_producer(nextservice);
+        if (nextservice == NULL) break;
         properties = MLT_SERVICE_PROPERTIES(nextservice);
         mlt_type = mlt_properties_get(properties, "mlt_type");
         resource = mlt_properties_get(properties, "mlt_service");
@@ -1540,6 +1572,7 @@ void Render::mltDeleteTransition(QString tag, int a_track, int b_track, GenTime
             break;
         }
         nextservice = mlt_service_producer(nextservice);
+        if (nextservice == NULL) break;
         properties = MLT_SERVICE_PROPERTIES(nextservice);
         mlt_type = mlt_properties_get(properties, "mlt_type");
         resource = mlt_properties_get(properties, "mlt_service");