]> git.sesse.net Git - kdenlive/blobdiff - testingArea/audioOffset.cpp
Const'ref
[kdenlive] / testingArea / audioOffset.cpp
index 2f8351a869881c77dc1cd4463043ec4f9f034206..f71b105231abff9bf53893809ab33cd9e3d836c2 100644 (file)
@@ -1,68 +1,96 @@
+/*
+Copyright (C) 2012  Simon A. Eugster (Granjow)  <simon.eu@gmail.com>
+This file is part of kdenlive. See www.kdenlive.org.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+*/
 
 #include <QMap>
 #include <QFile>
+#include <QTime>
+#include <QImage>
+#include <QDebug>
+#include <QFileInfo>
+#include <QDateTime>
+#include <QStringList>
+#include <QCoreApplication>
 #include <mlt++/Mlt.h>
 #include <iostream>
 #include <cstdlib>
+#include <cmath>
+
+#include "../src/lib/audio/audioInfo.h"
+#include "../src/lib/audio/audioStreamInfo.h"
+#include "../src/lib/audio/audioEnvelope.h"
+#include "../src/lib/audio/audioCorrelation.h"
 
-int info(char *filename)
+void printUsage(const char *path)
 {
+    std::cout << "This executable takes two audio/video files A and B and determines " << std::endl
+              << "how much B needs to be shifted in order to be synchronized with A." << std::endl << std::endl
+              << path << " <main audio file> <second audio file>" << std::endl
+              << "\t-h, --help\n\t\tDisplay this help" << std::endl
+              << "\t--fft\n\t\tUse Fourier Transform (FFT) to calculate the offset. This only takes" << std::endl
+              << "\t\tO(n log n) time compared to O(n²) when using normal correlation and should be " << std::endl
+              << "\t\tfaster for large data (several minutes)." << std::endl
+              << "\t--profile=<profile>\n\t\tUse the given profile for calculation (run: melt -query profiles)" << std::endl
+              << "\t--no-images\n\t\tDo not save envelope and correlation images" << std::endl
+                 ;
+}
 
-    // Initialize MLT
-    Mlt::Factory::init(NULL);
+int main(int argc, char *argv[])
+{
+    QCoreApplication app(argc, argv);
+    QStringList args = app.arguments();
+    args.removeAt(0);
+
+    std::string profile = "atsc_1080p_24";
+    bool saveImages = true;
+    bool useFFT = false;
+
+    // Load arguments
+    foreach (const QString &str, args) {
+
+        if (str.startsWith("--profile=")) {
+            QString s = str;
+            s.remove(0, QString("--profile=").length());
+            profile = s.toStdString();
+            args.removeOne(str);
+
+        } else if (str == "-h" || str == "--help") {
+            printUsage(argv[0]);
+            return 0;
+
+        } else if (str == "--no-images") {
+            saveImages = false;
+            args.removeOne(str);
+
+        } else if (str == "--fft") {
+            useFFT = true;
+            args.removeOne(str);
+        }
 
-    // Load an arbitrary profile
-    Mlt::Profile prof("hdv_1080_25p");
+    }
 
+    if (args.length() < 2) {
+        printUsage(argv[0]);
+        return 1;
+    }
 
-    std::cout << "MLT initialized, profile loaded. Loading clips ..." << std::endl;
 
 
-    Mlt::Producer producer(prof, filename);
-    if (!producer.is_valid()) {
-        std::cout << filename << " is invalid." << std::endl;
-        return 2;
-    }
-    std::cout << "Successfully loaded producer " << filename << std::endl;
-
-    int streams = atoi(producer.get("meta.media.nb_streams"));
-    std::cout << "Number of streams: " << streams << std::endl;
-
-    int audioStream = -1;
-    for (int i = 0; i < streams; i++) {
-        std::string propertyName = QString("meta.media.%1.stream.type").arg(i).toStdString();
-        std::cout << "Producer " << i << ": " << producer.get(propertyName.c_str());
-        if (strcmp("audio", producer.get(propertyName.c_str())) == 0) {
-            std::cout << " (Using this stream)";
-            audioStream = i;
-        }
-        std::cout << std::endl;
-    }
+    std::string fileMain(args.at(0).toStdString());
+    args.removeFirst();
+    std::string fileSub = args.at(0).toStdString();
+    args.removeFirst();
 
-    if (audioStream >= 0) {
-        QMap<QString, QString> map;
-        map.insert("Sampling format", QString("meta.media.%1.codec.sample_fmt").arg(audioStream));
-        map.insert("Sampling rate", QString("meta.media.%1.codec.sample_rate").arg(audioStream));
-        map.insert("Bit rate", QString("meta.media.%1.codec.bit_rate").arg(audioStream));
-        map.insert("Channels", QString("meta.media.%1.codec.channels").arg(audioStream));
-        map.insert("Codec", QString("meta.media.%1.codec.name").arg(audioStream));
-        map.insert("Codec, long name", QString("meta.media.%1.codec.long_name").arg(audioStream));
-
-        std::cout << "Audio properties (stream " << audioStream << ")" << std::endl;
-        foreach (QString key, map.keys()) {
-            std::string value = map.value(key).toStdString();
-            std::cout << "\t" << key.toStdString() << ": " << producer.get(value.c_str())
-                      << "  (" << value << ")" << std::endl;
-        }
-    }
 
-    return 0;
-}
+    qDebug() << "Unused arguments: " << args;
+
 
-int main(int argc, char *argv[])
-{
-    char *fileMain;
-    char *fileSub;
     if (argc > 2) {
         fileMain = argv[1];
         fileSub = argv[2];
@@ -70,64 +98,83 @@ int main(int argc, char *argv[])
         std::cout << "Usage: " << argv[0] << " <main audio file> <second audio file>" << std::endl;
         return 0;
     }
-    std::cout << "Trying to align (1)\n\t" << fileSub << "\nto fit on (2)\n\t" << fileMain
-              << "\n, result will indicate by how much (1) has to be moved." << std::endl;
+    std::cout << "Trying to align (2)\n\t" << fileSub << "\nto fit on (1)\n\t" << fileMain
+              << "\n, result will indicate by how much (2) has to be moved." << std::endl
+              << "Profile used: " << profile << std::endl
+                 ;
+    if (useFFT) {
+        std::cout << "Will use FFT based correlation." << std::endl;
+    }
 
 
-    info(fileMain);
-    info(fileSub);
+    // Initialize MLT
+    Mlt::Factory::init(NULL);
 
-/*
-    Mlt::Frame *frame = producer.get_frame();
+    // Load an arbitrary profile
+    Mlt::Profile prof(profile.c_str());
 
+    // Load the MLT producers
+    Mlt::Producer prodMain(prof, fileMain.c_str());
+    if (!prodMain.is_valid()) {
+        std::cout << fileMain << " is invalid." << std::endl;
+        return 2;
+    }
+    Mlt::Producer prodSub(prof, fileSub.c_str());
+    if (!prodSub.is_valid()) {
+        std::cout << fileSub << " is invalid." << std::endl;
+        return 2;
+    }
 
-    float *data = (float*)frame->get_audio(format, samplingRate, channels, nSamples);
-    producer.set("video_index", "-1");
 
-    if (KdenliveSettings::normaliseaudiothumbs()) {
-        Mlt::Filter m_convert(prof, "volume");
-        m_convert.set("gain", "normalise");
-        producer.attach(m_convert);
+    // Build the audio envelopes for the correlation
+    AudioEnvelope *envelopeMain = new AudioEnvelope(fileMain.c_str(), &prodMain);
+    envelopeMain->loadEnvelope();
+    envelopeMain->loadStdDev();
+    envelopeMain->dumpInfo();
+
+    AudioEnvelope *envelopeSub = new AudioEnvelope(fileSub.c_str(), &prodSub);
+    envelopeSub->loadEnvelope();
+    envelopeSub->loadStdDev();
+    envelopeSub->dumpInfo();
+
+    // Calculate the correlation and hereby the audio shift
+    AudioCorrelation corr(envelopeMain);
+    int index = corr.addChild(envelopeSub, useFFT);
+
+    int shift = corr.getShift(index);
+    std::cout << " Should be shifted by " << shift << " frames: " << fileSub << std::endl
+              << "\trelative to " << fileMain << std::endl
+              << "\tin a " << prodMain.get_fps() << " fps profile (" << profile << ")." << std::endl;
+
+
+    if (saveImages) {
+        QString outImg = QString::fromLatin1("envelope-main-%1.png")
+                .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
+        envelopeMain->drawEnvelope().save(outImg);
+        std::cout << "Saved volume envelope as "
+                  << QFileInfo(outImg).absoluteFilePath().toStdString()
+                  << std::endl;
+        outImg = QString::fromLatin1("envelope-sub-%1.png")
+                .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
+        envelopeSub->drawEnvelope().save(outImg);
+        std::cout << "Saved volume envelope as "
+                  << QFileInfo(outImg).absoluteFilePath().toStdString()
+                  << std::endl;
+        outImg = QString::fromLatin1("correlation-%1.png")
+                .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
+        corr.info(index)->toImage().save(outImg);
+        std::cout << "Saved correlation image as "
+                  << QFileInfo(outImg).absoluteFilePath().toStdString()
+                  << std::endl;
     }
 
-    int last_val = 0;
-    int val = 0;
-    double framesPerSecond = mlt_producer_get_fps(producer.get_producer());
-    Mlt::Frame *mlt_frame;
 
-    for (int z = (int) frame; z < (int)(frame + lengthInFrames) && producer.is_valid() &&  !m_abortAudioThumb; z++) {
-        val = (int)((z - frame) / (frame + lengthInFrames) * 100.0);
-        if (last_val != val && val > 1) {
-            setThumbsProgress(i18n("Creating audio thumbnail for %1", url.fileName()), val);
-            last_val = val;
-        }
-        producer.seek(z);
-        mlt_frame = producer.get_frame();
-        if (mlt_frame && mlt_frame->is_valid()) {
-            int samples = mlt_sample_calculator(framesPerSecond, frequency, mlt_frame_get_position(mlt_frame->get_frame()));
-            qint16* pcm = static_cast<qint16*>(mlt_frame->get_audio(audioFormat, frequency, channels, samples));
-            for (int c = 0; c < channels; c++) {
-                QByteArray audioArray;
-                audioArray.resize(arrayWidth);
-                for (int i = 0; i < audioArray.size(); i++) {
-                    audioArray[i] = ((*(pcm + c + i * samples / audioArray.size())) >> 9) + 127 / 2 ;
-                }
-                f.write(audioArray);
-                storeIn[z][c] = audioArray;
-            }
-        } else {
-            f.write(QByteArray(arrayWidth, '\x00'));
-        }
-        delete mlt_frame;
-    }
-    f.close();
-    setThumbsProgress(i18n("Creating audio thumbnail for %1", url.fileName()), -1);
-    if (m_abortAudioThumb) {
-        f.remove();
-    } else {
-        clip->updateAudioThumbnail(storeIn);
-    }*/
+    //    Mlt::Factory::close();
+
 
     return 0;
 
 }
+
+
+