X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=testingArea%2FaudioOffset.cpp;h=f71b105231abff9bf53893809ab33cd9e3d836c2;hb=c3302003093710ee247ad84c0fe2ef3c579d417f;hp=2f8351a869881c77dc1cd4463043ec4f9f034206;hpb=90c14d4bb82610998ec08178dfea570fbe56c61f;p=kdenlive diff --git a/testingArea/audioOffset.cpp b/testingArea/audioOffset.cpp index 2f8351a8..f71b1052 100644 --- a/testingArea/audioOffset.cpp +++ b/testingArea/audioOffset.cpp @@ -1,68 +1,96 @@ +/* +Copyright (C) 2012 Simon A. Eugster (Granjow) +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 #include +#include +#include +#include +#include +#include +#include +#include #include #include #include +#include + +#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 << "
" << 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=\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 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] << "
" << 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(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; } + + +