1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
/*
SPDX-FileCopyrightText: 2012 Simon A. Eugster (Granjow) <simon.eu@gmail.com>
This file is part of kdenlive. See www.kdenlive.org.
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <QCoreApplication>
#include <QDateTime>
#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QStringList>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <mlt++/Mlt.h>
#include "../src/lib/audio/audioCorrelation.h"
#include "../src/lib/audio/audioEnvelope.h"
#include "../src/lib/audio/audioInfo.h"
#include "../src/lib/audio/audioStreamInfo.h"
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;
}
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(QLatin1String("--profile="))) {
QString s = str;
s.remove(0, QStringLiteral("--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);
}
}
if (args.length() < 2) {
printUsage(argv[0]);
return 1;
}
std::string fileMain(args.at(0).toStdString());
args.removeFirst();
std::string fileSub = args.at(0).toStdString();
args.removeFirst();
qDebug() << "Unused arguments: " << args;
if (argc > 2) {
fileMain = argv[1];
fileSub = argv[2];
} else {
std::cout << "Usage: " << argv[0] << " <main audio file> <second audio file>" << std::endl;
return 0;
}
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;
}
// Initialize MLT
Mlt::Factory::init(NULL);
// 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;
}
// 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 = 0;
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;
}
// Mlt::Factory::close();
return 0;
}
|