File indexing completed on 2024-04-21 04:52:40

0001 /*
0002     SPDX-FileCopyrightText: 2012 Simon A. Eugster (Granjow)  <simon.eu@gmail.com>
0003     This file is part of kdenlive. See www.kdenlive.org.
0004 
0005     SPDX-License-Identifier: GPL-3.0-or-later
0006 */
0007 
0008 #include <QCoreApplication>
0009 #include <QDateTime>
0010 #include <QDebug>
0011 #include <QFile>
0012 #include <QFileInfo>
0013 #include <QStringList>
0014 #include <cmath>
0015 #include <cstdlib>
0016 #include <iostream>
0017 #include <mlt++/Mlt.h>
0018 
0019 #include "../src/lib/audio/audioCorrelation.h"
0020 #include "../src/lib/audio/audioEnvelope.h"
0021 #include "../src/lib/audio/audioInfo.h"
0022 #include "../src/lib/audio/audioStreamInfo.h"
0023 
0024 void printUsage(const char *path)
0025 {
0026     std::cout << "This executable takes two audio/video files A and B and determines " << std::endl
0027               << "how much B needs to be shifted in order to be synchronized with A." << std::endl
0028               << std::endl
0029               << path << " <main audio file> <second audio file>" << std::endl
0030               << "\t-h, --help\n\t\tDisplay this help" << std::endl
0031               << "\t--fft\n\t\tUse Fourier Transform (FFT) to calculate the offset. This only takes" << std::endl
0032               << "\t\tO(n log n) time compared to O(n²) when using normal correlation and should be " << std::endl
0033               << "\t\tfaster for large data (several minutes)." << std::endl
0034               << "\t--profile=<profile>\n\t\tUse the given profile for calculation (run: melt -query profiles)" << std::endl
0035               << "\t--no-images\n\t\tDo not save envelope and correlation images" << std::endl;
0036 }
0037 
0038 int main(int argc, char *argv[])
0039 {
0040     QCoreApplication app(argc, argv);
0041     QStringList args = app.arguments();
0042     args.removeAt(0);
0043 
0044     std::string profile = "atsc_1080p_24";
0045     bool saveImages = true;
0046     bool useFFT = false;
0047 
0048     // Load arguments
0049     foreach (const QString &str, args) {
0050 
0051         if (str.startsWith(QLatin1String("--profile="))) {
0052             QString s = str;
0053             s.remove(0, QString("--profile=").length());
0054             profile = s.toStdString();
0055             args.removeOne(str);
0056 
0057         } else if (str == "-h" || str == "--help") {
0058             printUsage(argv[0]);
0059             return 0;
0060 
0061         } else if (str == "--no-images") {
0062             saveImages = false;
0063             args.removeOne(str);
0064 
0065         } else if (str == "--fft") {
0066             useFFT = true;
0067             args.removeOne(str);
0068         }
0069     }
0070 
0071     if (args.length() < 2) {
0072         printUsage(argv[0]);
0073         return 1;
0074     }
0075 
0076     std::string fileMain(args.at(0).toStdString());
0077     args.removeFirst();
0078     std::string fileSub = args.at(0).toStdString();
0079     args.removeFirst();
0080 
0081     qDebug() << "Unused arguments: " << args;
0082 
0083     if (argc > 2) {
0084         fileMain = argv[1];
0085         fileSub = argv[2];
0086     } else {
0087         std::cout << "Usage: " << argv[0] << " <main audio file> <second audio file>" << std::endl;
0088         return 0;
0089     }
0090     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."
0091               << std::endl
0092               << "Profile used: " << profile << std::endl;
0093     if (useFFT) {
0094         std::cout << "Will use FFT based correlation." << std::endl;
0095     }
0096 
0097     // Initialize MLT
0098     Mlt::Factory::init(NULL);
0099 
0100     // Load an arbitrary profile
0101     Mlt::Profile prof(profile.c_str());
0102 
0103     // Load the MLT producers
0104     Mlt::Producer prodMain(prof, fileMain.c_str());
0105     if (!prodMain.is_valid()) {
0106         std::cout << fileMain << " is invalid." << std::endl;
0107         return 2;
0108     }
0109     Mlt::Producer prodSub(prof, fileSub.c_str());
0110     if (!prodSub.is_valid()) {
0111         std::cout << fileSub << " is invalid." << std::endl;
0112         return 2;
0113     }
0114 
0115     // Build the audio envelopes for the correlation
0116     AudioEnvelope *envelopeMain = new AudioEnvelope(fileMain.c_str(), &prodMain);
0117     envelopeMain->loadEnvelope();
0118     envelopeMain->loadStdDev();
0119     envelopeMain->dumpInfo();
0120 
0121     AudioEnvelope *envelopeSub = new AudioEnvelope(fileSub.c_str(), &prodSub);
0122     envelopeSub->loadEnvelope();
0123     envelopeSub->loadStdDev();
0124     envelopeSub->dumpInfo();
0125 
0126     // Calculate the correlation and hereby the audio shift
0127     AudioCorrelation corr(envelopeMain);
0128     int index = 0;
0129     corr.addChild(envelopeSub /*, useFFT*/);
0130 
0131     int shift = corr.getShift(index);
0132     std::cout << " Should be shifted by " << shift << " frames: " << fileSub << std::endl
0133               << "\trelative to " << fileMain << std::endl
0134               << "\tin a " << prodMain.get_fps() << " fps profile (" << profile << ")." << std::endl;
0135 
0136     if (saveImages) {
0137         QString outImg = QString::fromLatin1("envelope-main-%1.png").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
0138         envelopeMain->drawEnvelope().save(outImg);
0139         std::cout << "Saved volume envelope as " << QFileInfo(outImg).absoluteFilePath().toStdString() << std::endl;
0140         outImg = QString::fromLatin1("envelope-sub-%1.png").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
0141         envelopeSub->drawEnvelope().save(outImg);
0142         std::cout << "Saved volume envelope as " << QFileInfo(outImg).absoluteFilePath().toStdString() << std::endl;
0143         outImg = QString::fromLatin1("correlation-%1.png").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh:mm:ss"));
0144         corr.info(index)->toImage().save(outImg);
0145         std::cout << "Saved correlation image as " << QFileInfo(outImg).absoluteFilePath().toStdString() << std::endl;
0146     }
0147 
0148     //    Mlt::Factory::close();
0149 
0150     return 0;
0151 }