]> 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 0c44902e8143d519476e1e2c97173428d433966c..e0ce8c473dcc3e725db77668dbe7d0926fb98225 100644 (file)
@@ -499,6 +499,23 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId) {
         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());
@@ -601,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!!!!!!!!!!!!!!";
@@ -617,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
@@ -643,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() {
@@ -744,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()) {
@@ -785,55 +835,37 @@ 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.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();
 }
 
 
@@ -1276,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());
 
@@ -1313,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);
@@ -1334,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";
@@ -1392,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";
@@ -1527,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;
@@ -1601,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;
@@ -1732,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++;
@@ -1799,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;
@@ -1820,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;
 }
@@ -1884,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;
@@ -1892,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);
@@ -1932,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());
@@ -1950,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;
         }
@@ -2085,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;
         }
@@ -2112,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) {
@@ -2302,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();