Commit 9c9c327b authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle

Move audio max level to a job (was causing ui hang on project opening)

Remove audio balance filter in projects with > 2 audio channels
parent a12ba6df
Pipeline #38426 canceled with stage
......@@ -107,6 +107,7 @@ MixerWidget::MixerWidget(int tid, std::shared_ptr<Mlt::Tractor> service, const Q
, m_monitorFilter(nullptr)
, m_balanceFilter(nullptr)
, m_channels(pCore->audioChannels())
, m_balanceSlider(nullptr)
, m_maxLevels(qMax(30, (int)(service->get_fps() * 1.5)))
, m_solo(nullptr)
, m_record(nullptr)
......@@ -126,6 +127,7 @@ MixerWidget::MixerWidget(int tid, Mlt::Tractor *service, const QString &trackTag
, m_monitorFilter(nullptr)
, m_balanceFilter(nullptr)
, m_channels(pCore->audioChannels())
, m_balanceSlider(nullptr)
, m_maxLevels(qMax(30, (int)(service->get_fps() * 1.5)))
, m_solo(nullptr)
, m_record(nullptr)
......@@ -169,23 +171,27 @@ void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
m_volumeSlider->setValue(fromDB(val));
});
m_balanceSlider = new QSlider(Qt::Horizontal,this);
m_balanceSlider->setRange(-50, 50);
m_balanceSlider->setValue(0);
m_balanceSlider->setTickPosition(QSlider::TicksBelow);
m_balanceSlider->setTickInterval(50);
m_balanceSlider->setToolTip(i18n("Balance"));
QLabel *labelLeft = new QLabel(i18nc("Left", "L"), this);
labelLeft->setAlignment(Qt::AlignHCenter);
QLabel *labelRight = new QLabel(i18nc("Right", "R"), this);
labelLeft->setAlignment(Qt::AlignHCenter);
m_balanceSpin = new QSpinBox(this);
m_balanceSpin->setRange(-50, 50);
m_balanceSpin->setValue(0);
m_balanceSpin->setFrame(false);
m_balanceSpin->setToolTip(i18n("Balance"));
QLabel *labelLeft = nullptr;
QLabel *labelRight = nullptr;
if (m_channels == 2) {
m_balanceSlider = new QSlider(Qt::Horizontal,this);
m_balanceSlider->setRange(-50, 50);
m_balanceSlider->setValue(0);
m_balanceSlider->setTickPosition(QSlider::TicksBelow);
m_balanceSlider->setTickInterval(50);
m_balanceSlider->setToolTip(i18n("Balance"));
labelLeft = new QLabel(i18nc("Left", "L"), this);
labelLeft->setAlignment(Qt::AlignHCenter);
labelRight = new QLabel(i18nc("Right", "R"), this);
labelRight->setAlignment(Qt::AlignHCenter);
m_balanceSpin = new QSpinBox(this);
m_balanceSpin->setRange(-50, 50);
m_balanceSpin->setValue(0);
m_balanceSpin->setFrame(false);
m_balanceSpin->setToolTip(i18n("Balance"));
}
// Check if we already have build-in filters for this tractor
int max = service->filter_count();
......@@ -203,7 +209,7 @@ void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
double volume = m_levelFilter->get_double("level");
m_volumeSpin->setValue(volume);
m_volumeSlider->setValue(fromDB(volume));
} else if (filterService == QLatin1String("panner")) {
} else if (m_channels == 2 && filterService == QLatin1String("panner")) {
m_balanceFilter = fl;
int val = m_balanceFilter->get_double("start") * 100 - 50;
m_balanceSpin->setValue(val);
......@@ -219,7 +225,7 @@ void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
service->attach(*m_levelFilter.get());
}
}
if (m_balanceFilter == nullptr) {
if (m_balanceFilter == nullptr && m_channels == 2) {
m_balanceFilter.reset(new Mlt::Filter(service->get_profile(), "panner"));
if (m_balanceFilter->is_valid()) {
m_balanceFilter->set("internal_added", 237);
......@@ -245,7 +251,9 @@ void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
m_muteAction->setActiveIcon(QIcon::fromTheme(QStringLiteral("kdenlive-hide-audio")));
m_muteAction->setInactiveIcon(QIcon::fromTheme(QStringLiteral("kdenlive-show-audio")));
connect(m_balanceSlider, &QSlider::valueChanged, m_balanceSpin, &QSpinBox::setValue);
if (m_balanceSlider) {
connect(m_balanceSlider, &QSlider::valueChanged, m_balanceSpin, &QSpinBox::setValue);
}
connect(m_muteAction, &KDualAction::activeChangedByUser, this, [&](bool active) {
if (m_tid == -1) {
......@@ -337,17 +345,19 @@ void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
pCore->setDocumentModified();
}
});
connect(m_balanceSpin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
QSignalBlocker bk(m_balanceSlider);
m_balanceSlider->setValue(value);
if (m_balanceFilter != nullptr) {
m_balanceFilter->set("start", (value + 50) / 100.);
m_balanceFilter->set("disable", value == 0 ? 1 : 0);
m_levels.clear();
emit m_manager->purgeCache();
pCore->setDocumentModified();
}
});
if (m_balanceSlider) {
connect(m_balanceSpin, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, [&](int value) {
QSignalBlocker bk(m_balanceSlider);
m_balanceSlider->setValue(value);
if (m_balanceFilter != nullptr) {
m_balanceFilter->set("start", (value + 50) / 100.);
m_balanceFilter->set("disable", value == 0 ? 1 : 0);
m_levels.clear();
emit m_manager->purgeCache();
pCore->setDocumentModified();
}
});
}
QVBoxLayout *lay = new QVBoxLayout;
setContentsMargins(0, 0, 0, 0);
lay->setContentsMargins(0, 0, 0, 0);
......@@ -367,12 +377,14 @@ void MixerWidget::buildUI(Mlt::Tractor *service, const QString &trackTag)
}
buttonslay->addWidget(showEffects);
lay->addLayout(buttonslay);
QGridLayout *balancelay = new QGridLayout;
balancelay->addWidget(m_balanceSlider, 0, 0, 1, 3);
balancelay->addWidget(labelLeft, 1, 0, 1, 1);
balancelay->addWidget(m_balanceSpin, 1, 1, 1, 1);
balancelay->addWidget(labelRight, 1, 2, 1, 1);
lay->addLayout(balancelay);
if (m_balanceSlider) {
QGridLayout *balancelay = new QGridLayout;
balancelay->addWidget(m_balanceSlider, 0, 0, 1, 3);
balancelay->addWidget(labelLeft, 1, 0, 1, 1);
balancelay->addWidget(m_balanceSpin, 1, 1, 1, 1);
balancelay->addWidget(labelRight, 1, 2, 1, 1);
lay->addLayout(balancelay);
}
QHBoxLayout *hlay = new QHBoxLayout;
hlay->addWidget(m_audioMeterWidget.get());
hlay->addWidget(m_volumeSlider);
......
......@@ -210,38 +210,6 @@ QString ProjectClip::getXmlProperty(const QDomElement &producer, const QString &
void ProjectClip::updateAudioThumbnail()
{
if (m_hasAudio && m_service.startsWith(QLatin1String("avformat"))) {
int audioMax = getProducerIntProperty(QStringLiteral("kdenlive:audio_max"));
if (audioMax == 0) {
// Calculate max audio level with ffmpeg
QProcess ffmpeg;
QStringList args;
args << QStringLiteral("-i") << clipUrl() << QStringLiteral("-vn") << QStringLiteral("-af") << QStringLiteral("volumedetect") << QStringLiteral("-f") << QStringLiteral("null");
#ifdef Q_OS_WIN
args << QStringLiteral("-");
#else
args << QStringLiteral("/dev/stdout");
#endif
QObject::connect(&ffmpeg, &QProcess::readyReadStandardOutput, [&ffmpeg, this]() {
QString output = ffmpeg.readAllStandardOutput();
if (output.contains(QLatin1String("max_volume"))) {
output = output.section(QLatin1String("max_volume:"), 1).simplified();
output = output.section(QLatin1Char(' '), 0, 0);
bool ok;
double maxVolume = output.toDouble(&ok);
if (ok) {
int aMax = qMax(1, qAbs(qRound(maxVolume)));
setProducerProperty(QStringLiteral("kdenlive:audio_max"), aMax);
} else {
setProducerProperty(QStringLiteral("kdenlive:audio_max"), -1);
}
}
});
ffmpeg.setProcessChannelMode(QProcess::MergedChannels);
ffmpeg.start(KdenliveSettings::ffmpegpath(), args);
ffmpeg.waitForFinished(-1);
}
}
emit audioThumbReady();
if (m_clipType == ClipType::Audio) {
QImage thumb = ThumbnailCache::get()->getThumbnail(m_binId, 0);
......
......@@ -101,8 +101,6 @@ public:
KdenliveDoc *currentDoc();
/** @brief Returns project's timecode. */
Timecode timecode() const;
/** @brief Set current project modified. */
void setDocumentModified();
/** @brief Returns a pointer to the monitor manager. */
MonitorManager *monitorManager();
/** @brief Returns a pointer to the view of the project bin. */
......@@ -275,6 +273,8 @@ public slots:
void displayBinLogMessage(const QString &text, int type, const QString &logInfo);
/** @brief Create small thumbnails for luma used in compositions */
void buildLumaThumbs(const QStringList &values);
/** @brief Set current project modified. */
void setDocumentModified();
signals:
void coreIsReady();
......
......@@ -30,6 +30,7 @@
#include "lib/audio/audioStreamInfo.h"
#include "macros.hpp"
#include "utils/thumbnailcache.hpp"
#include <QScopedPointer>
#include <QTemporaryFile>
#include <QProcess>
......@@ -117,13 +118,40 @@ bool AudioThumbJob::computeWithFFMPEG()
// We only wanted the thumb generation
return m_done;
}
QString filePath = m_prod->get("kdenlive:originalurl");
if (filePath.isEmpty() || !QFile::exists(filePath)) {
filePath = m_prod->get("resource");
}
QString filePath = m_binClip->getOriginalUrl();
if (!QFile::exists(filePath)) {
return false;
}
int audioMax = m_binClip->getProducerIntProperty(QStringLiteral("kdenlive:audio_max"));
if (audioMax == 0) {
// Calculate max audio level with ffmpeg
QProcess ffmpeg;
QStringList args = {QStringLiteral("-i"), filePath, QStringLiteral("-vn"), QStringLiteral("-af"), QStringLiteral("volumedetect"), QStringLiteral("-f"), QStringLiteral("null")};
#ifdef Q_OS_WIN
args << QStringLiteral("-");
#else
args << QStringLiteral("/dev/stdout");
#endif
QObject::connect(&ffmpeg, &QProcess::readyReadStandardOutput, [&ffmpeg, this]() {
QString output = ffmpeg.readAllStandardOutput();
if (output.contains(QLatin1String("max_volume"))) {
output = output.section(QLatin1String("max_volume:"), 1).simplified();
output = output.section(QLatin1Char(' '), 0, 0);
bool ok;
double maxVolume = output.toDouble(&ok);
if (ok) {
int aMax = qMax(1, qAbs(qRound(maxVolume)));
m_binClip->setProducerProperty(QStringLiteral("kdenlive:audio_max"), aMax);
QMetaObject::invokeMethod(pCore.get(), "setDocumentModified", Qt::QueuedConnection);
} else {
m_binClip->setProducerProperty(QStringLiteral("kdenlive:audio_max"), -1);
}
}
});
ffmpeg.setProcessChannelMode(QProcess::MergedChannels);
ffmpeg.start(KdenliveSettings::ffmpegpath(), args);
ffmpeg.waitForFinished(-1);
}
int audioStreamIndex = m_binClip->getAudioStreamFfmpegIndex(m_audioStream);
if (!QFile::exists(m_cachePath) && !m_dataInCache) {
......
......@@ -1068,3 +1068,14 @@ int ClipController::audioStreamsCount() const
return 0;
}
const QString ClipController::getOriginalUrl()
{
QString path = m_properties->get("kdenlive:originalurl");
if (path.isEmpty()) {
path = m_path;
}
if (QFileInfo(path).isRelative()) {
path.prepend(pCore->currentDoc()->documentRoot());
}
return path;
}
......@@ -224,6 +224,8 @@ public:
QMap <int, QString> activeStreams() const;
/** @brief Returns the count of audio streams for this clip */
int audioStreamsCount() const;
/** @brief Get the path to the original clip url (in case it is proxied) */
const QString getOriginalUrl();
protected:
virtual void emitProducerChanged(const QString & /*unused*/, const std::shared_ptr<Mlt::Producer> & /*unused*/){};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment