Multi stream clips: display all active streams thumbnails in clip monitor

parent dea6b187
Pipeline #20051 passed with stage
in 9 minutes and 26 seconds
......@@ -295,13 +295,8 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
}
if (!enabledStreams.isEmpty()) {
// Only 1 stream wanted, easy
m_glMonitor->getControllerProxy()->setAudioStream(enabledStreams.first());
QMap <QString, QString> props;
props.insert(QStringLiteral("audio_index"), QString::number(enabledStreams.firstKey()));
if (enabledStreams.count() > 1) {
// Mix audio channels
}
QList <int> streams = enabledStreams.keys();
QStringList astreams;
for (const int st : streams) {
......@@ -311,7 +306,6 @@ Monitor::Monitor(Kdenlive::MonitorId id, MonitorManager *manager, QWidget *paren
m_controller->setProperties(props, true);
} else {
// No active stream
m_glMonitor->getControllerProxy()->setAudioStream(QString());
QMap <QString, QString> props;
props.insert(QStringLiteral("audio_index"), QStringLiteral("-1"));
props.insert(QStringLiteral("kdenlive:active_streams"), QStringLiteral("-1"));
......@@ -1462,7 +1456,13 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
if (audioStreamsInfo.size() > 1) {
// Multi stream clip
QMapIterator<int, QString> i(audioStreamsInfo);
QList <int> activeStreams = m_controller->activeStreams().keys();
QMap <int, QString> activeStreams = m_controller->activeStreams();
if (activeStreams.size() > 1) {
m_glMonitor->getControllerProxy()->setAudioStream(i18n("%1 audio streams", activeStreams.size()));
// TODO: Mix audio channels
} else {
m_glMonitor->getControllerProxy()->setAudioStream(m_controller->activeStreams().first());
}
QAction *ac;
while (i.hasNext()) {
i.next();
......@@ -1471,7 +1471,6 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
ac->setCheckable(true);
if (activeStreams.contains(i.key())) {
ac->setChecked(true);
m_glMonitor->getControllerProxy()->setAudioStream(ac->text().remove(QLatin1Char('&')));
}
}
ac = m_audioChannels->addAction(i18n("Merge all streams"));
......@@ -1517,7 +1516,7 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
}
m_audioMeterWidget->audioChannels = controller->audioInfo() ? controller->audioInfo()->channels() : 0;
if (!m_controller->hasVideo() || KdenliveSettings::displayClipMonitorInfo() & 0x10) {
m_glMonitor->getControllerProxy()->setAudioThumb(m_audioMeterWidget->audioChannels == 0 ? QUrl() : ThumbnailCache::get()->getAudioThumbPath(m_controller->clipId()));
m_glMonitor->getControllerProxy()->setAudioThumb(m_audioMeterWidget->audioChannels == 0 ? QList<QUrl>() : ThumbnailCache::get()->getAudioThumbPath(m_controller->clipId()));
}
m_controller->getMarkerModel()->registerSnapModel(m_snaps);
m_glMonitor->getControllerProxy()->setClipProperties(controller->clipId().toInt(), controller->clipType(), controller->hasAudioAndVideo(), controller->clipName());
......@@ -1549,7 +1548,13 @@ void Monitor::reloadActiveStream()
QList <int> activeStreams = m_controller->activeStreams().keys();
QMap <int, QString> streams = m_controller->audioStreams();
qDebug()<<"==== REFRESHING MONITOR STREAMS: "<<activeStreams;
bool displayedStream = false;
if (activeStreams.size() > 1) {
m_glMonitor->getControllerProxy()->setAudioStream(i18n("%1 audio streams", activeStreams.size()));
// TODO: Mix audio channels
} else {
m_glMonitor->getControllerProxy()->setAudioStream(m_controller->activeStreams().first());
}
prepareAudioThumb();
for (auto ac : acts) {
int val = ac->data().toInt();
if (streams.contains(val)) {
......@@ -1558,10 +1563,6 @@ void Monitor::reloadActiveStream()
}
if (activeStreams.contains(val)) {
ac->setChecked(true);
if (!displayedStream) {
m_glMonitor->getControllerProxy()->setAudioStream(ac->text().remove(QLatin1Char('&')));
displayedStream = true;
}
} else {
ac->setChecked(false);
}
......
......@@ -328,7 +328,7 @@ void MonitorProxy::setClipProperties(int clipId, ClipType::ProducerType type, bo
}
}
void MonitorProxy::setAudioThumb(const QUrl thumbPath)
void MonitorProxy::setAudioThumb(const QList <QUrl> thumbPath)
{
m_audioThumb = thumbPath;
emit audioThumbChanged();
......
......@@ -44,7 +44,7 @@ class MonitorProxy : public QObject
Q_PROPERTY(int zoneOut READ zoneOut WRITE setZoneOut NOTIFY zoneChanged)
Q_PROPERTY(int rulerHeight READ rulerHeight NOTIFY rulerHeightChanged)
Q_PROPERTY(QString markerComment READ markerComment NOTIFY markerCommentChanged)
Q_PROPERTY(QUrl audioThumb MEMBER m_audioThumb NOTIFY audioThumbChanged)
Q_PROPERTY(QList <QUrl> audioThumb MEMBER m_audioThumb NOTIFY audioThumbChanged)
Q_PROPERTY(int overlayType READ overlayType WRITE setOverlayType NOTIFY overlayTypeChanged)
/** @brief: Returns true if current clip in monitor has Audio and Video
* */
......@@ -91,7 +91,7 @@ public:
Q_INVOKABLE double fps() const;
QPoint profile();
void setClipProperties(int clipId, ClipType::ProducerType type, bool hasAV, const QString clipName);
void setAudioThumb(const QUrl thumbPath = QUrl());
void setAudioThumb(const QList <QUrl> thumbPath = QList <QUrl>());
void setAudioStream(const QString &name);
signals:
......@@ -125,7 +125,7 @@ private:
int m_zoneIn;
int m_zoneOut;
bool m_hasAV;
QUrl m_audioThumb;
QList <QUrl> m_audioThumb;
QString m_markerComment;
QString m_clipName;
QString m_clipStream;
......
......@@ -176,10 +176,28 @@ Item {
width: (controller.zoneOut - controller.zoneIn) * timeScale
visible: controller.zoneIn > 0 || controller.zoneOut < duration - 1
}
Image {
anchors.fill: parent
source: controller.audioThumb
asynchronous: true
Repeater {
id: streamThumb
model: controller.audioThumb.length
property double streamHeight: parent.height / streamThumb.count
Item {
anchors.fill: parent
Image {
anchors.left: parent.left
anchors.right: parent.right
height: streamThumb.streamHeight
y: model.index * height
source: controller.audioThumb[model.index]
asynchronous: true
}
Rectangle {
width: parent.width
y: (model.index + 1) * streamThumb.streamHeight
height: 1
visible: streamThumb.count > 1 && model.index < streamThumb.count - 1
color: 'black'
}
}
}
Rectangle {
color: "red"
......
......@@ -110,7 +110,7 @@ bool ThumbnailCache::hasThumbnail(const QString &binId, int pos, bool volatileOn
{
QMutexLocker locker(&m_mutex);
bool ok = false;
auto key = pos < 0 ? getAudioKey(binId, &ok) : getKey(binId, pos, &ok);
auto key = pos < 0 ? getAudioKey(binId, &ok).first() : getKey(binId, pos, &ok);
if (ok && m_volatileCache->contains(key)) {
return true;
}
......@@ -125,7 +125,7 @@ QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly
{
QMutexLocker locker(&m_mutex);
bool ok = false;
auto key = getAudioKey(binId, &ok);
auto key = getAudioKey(binId, &ok).first();
if (ok && m_volatileCache->contains(key)) {
return m_volatileCache->get(key);
}
......@@ -140,16 +140,21 @@ QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly
return QImage();
}
const QUrl ThumbnailCache::getAudioThumbPath(const QString &binId) const
const QList <QUrl> ThumbnailCache::getAudioThumbPath(const QString &binId) const
{
QMutexLocker locker(&m_mutex);
bool ok = false;
auto key = getAudioKey(binId, &ok);
QDir thumbFolder = getDir(true, &ok);
if (ok && thumbFolder.exists(key)) {
return QUrl::fromLocalFile(thumbFolder.absoluteFilePath(key));
QList <QUrl> pathList;
if (ok) {
for (const QString &p : key) {
if (thumbFolder.exists(p)) {
pathList <<QUrl::fromLocalFile(thumbFolder.absoluteFilePath(p));
}
}
}
return QUrl();
return pathList;
}
QImage ThumbnailCache::getThumbnail(const QString &binId, int pos, bool volatileOnly) const
......@@ -242,7 +247,9 @@ void ThumbnailCache::invalidateThumbsForClip(const QString &binId, bool reloadAu
if (reloadAudio) {
auto key = getAudioKey(binId, &ok);
if (ok) {
QFile::remove(audioThumbFolder.absoluteFilePath(key));
for (const QString &p : key) {
QFile::remove(audioThumbFolder.absoluteFilePath(p));
}
}
}
} else {
......@@ -277,18 +284,38 @@ QString ThumbnailCache::getKey(const QString &binId, int pos, bool *ok)
}
// static
QString ThumbnailCache::getAudioKey(const QString &binId, bool *ok)
QStringList ThumbnailCache::getAudioKey(const QString &binId, bool *ok)
{
auto binClip = pCore->projectItemModel()->getClipByBinID(binId);
*ok = binClip != nullptr;
if (ok) {
int audio = binClip->getProducerIntProperty(QStringLiteral("audio_index"));
if (audio > -1) {
return binClip->hash() + QLatin1Char('_') + QString::number(audio) + QStringLiteral(".png");
QString streams = binClip->getProducerProperty(QStringLiteral("kdenlive:active_streams"));
if (streams.isEmpty()) {
// activate all audio streams
QList <int> streamIxes = binClip->audioStreams().keys();
if (streamIxes.size() > 1) {
QStringList streamsList;
for (const int st : streamIxes) {
streamsList << QString("%1_%2.png").arg(binClip->hash()).arg(st);
}
return streamsList;
}
}
if (streams.size() == 1) {
int audio = binClip->getProducerIntProperty(QStringLiteral("audio_index"));
if (audio > -1) {
return {QString("%1_%2.png").arg(binClip->hash()).arg(audio)};
}
return {binClip->hash() + QStringLiteral(".png")};
}
QStringList streamsList;
QStringList streamIndexes = streams.split(QLatin1Char(';'));
for (const QString st : streamIndexes) {
streamsList << QString("%1_%2.png").arg(binClip->hash()).arg(st);
}
return binClip->hash() + QStringLiteral(".png");
return streamsList;
}
return QString();
return {};
}
// static
......
......@@ -61,7 +61,7 @@ public:
*/
QImage getThumbnail(const QString &binId, int pos, bool volatileOnly = false) const;
QImage getAudioThumbnail(const QString &binId, bool volatileOnly = false) const;
const QUrl getAudioThumbPath(const QString &binId) const;
const QList <QUrl> getAudioThumbPath(const QString &binId) const;
/* @brief Get a given thumbnail from the cache
@param binId is the id of the queried clip
......@@ -85,7 +85,7 @@ protected:
// Return the key associated to a thumbnail
static QString getKey(const QString &binId, int pos, bool *ok);
static QString getAudioKey(const QString &binId, bool *ok);
static QStringList getAudioKey(const QString &binId, bool *ok);
// Return the dir where the persistent cache lives
static QDir getDir(bool audio, bool *ok);
......
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