Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 1a7d2eee authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle

Improve audio clips display: proper thumbnails and monitor view

parent 3fb2ba13
Pipeline #10102 passed with stage
in 26 minutes and 57 seconds
......@@ -71,6 +71,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QUrl>
#include <QVBoxLayout>
#include <utility>
/**
* @class BinItemDelegate
* @brief This class is responsible for drawing items in the QTreeView.
......@@ -699,7 +700,6 @@ Bin::Bin(std::shared_ptr<ProjectItemModel> model, QWidget *parent)
setFocusPolicy(Qt::ClickFocus);
connect(m_itemModel.get(), &ProjectItemModel::refreshPanel, this, &Bin::refreshPanel);
connect(m_itemModel.get(), &ProjectItemModel::refreshAudioThumbs, this, &Bin::doRefreshAudioThumbs);
connect(m_itemModel.get(), &ProjectItemModel::refreshClip, this, &Bin::refreshClip);
connect(m_itemModel.get(), &ProjectItemModel::emitMessage, this, &Bin::emitMessage);
......@@ -2197,13 +2197,6 @@ void Bin::refreshClip(const QString &id)
}
}
void Bin::doRefreshAudioThumbs(const QString &id)
{
if (m_monitor->activeClipId() == id) {
slotSendAudioThumb(id);
}
}
void Bin::slotCreateProjectClip()
{
auto *act = qobject_cast<QAction *>(sender());
......@@ -3085,16 +3078,6 @@ QStringList Bin::getProxyHashList()
return list;
}
void Bin::slotSendAudioThumb(const QString &id)
{
std::shared_ptr<ProjectClip> clip = m_itemModel->getClipByBinID(id);
if ((clip != nullptr) && clip->audioThumbCreated()) {
m_monitor->prepareAudioThumb(clip->audioChannels(), clip->audioFrameCache);
} else {
m_monitor->prepareAudioThumb(0);
}
}
bool Bin::isEmpty() const
{
if (m_itemModel->getRootFolder() == nullptr) {
......
......@@ -304,9 +304,6 @@ private slots:
/** @brief Rename a Bin Item. */
void slotRenameItem();
void doRefreshPanel(const QString &id);
/** @brief Send audio thumb data to monitor for display. */
void slotSendAudioThumb(const QString &id);
void doRefreshAudioThumbs(const QString &id);
/** @brief Enable item view and hide message */
void slotMessageActionTriggered();
/** @brief Request editing of title or slideshow clip */
......
......@@ -197,9 +197,6 @@ void ProjectClip::updateAudioThumbnail(QList<double> audioLevels)
{
audioFrameCache = audioLevels;
m_audioThumbCreated = true;
if (auto ptr = m_model.lock()) {
emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshAudioThumbs(m_binId);
}
}
bool ProjectClip::audioThumbCreated() const
......@@ -1195,7 +1192,7 @@ void ProjectClip::discardAudioThumb()
pCore->jobManager()->discardJobs(clipId(), AbstractClipJob::AUDIOTHUMBJOB);
}
const QString ProjectClip::getAudioThumbPath()
const QString ProjectClip::getAudioThumbPath(bool miniThumb)
{
if (audioInfo() == nullptr) {
return QString();
......@@ -1211,6 +1208,10 @@ const QString ProjectClip::getAudioThumbPath()
return QString();
}
QString audioPath = thumbFolder.absoluteFilePath(clipHash);
if (miniThumb) {
audioPath.append(QStringLiteral(".png"));
return audioPath;
}
if (audioStream > 0) {
audioPath.append(QLatin1Char('_') + QString::number(audioInfo()->audio_index()));
}
......
......@@ -185,7 +185,7 @@ public:
/** @brief Delete cached audio thumb - needs to be recreated */
void discardAudioThumb();
/** @brief Get path for this clip's audio thumbnail */
const QString getAudioThumbPath();
const QString getAudioThumbPath(bool miniThumb = false);
/** @brief Returns true if this producer has audio and can be splitted on timeline*/
bool isSplittable() const;
......@@ -283,6 +283,7 @@ signals:
void thumbReady(int, const QImage &);
/** @brief Clip is ready, load properties. */
void loadPropertiesPanel();
void audioThumbReady();
};
#endif
This diff is collapsed.
......@@ -24,6 +24,7 @@
#include "abstractclipjob.h"
#include <memory>
#include <QImage>
/* @brief This class represents the job that corresponds to computing the audio thumb of a clip (waveform)
*/
......@@ -63,11 +64,14 @@ protected:
private:
std::shared_ptr<ProjectClip> m_binClip;
std::shared_ptr<Mlt::Producer> m_prod;
QString m_miniThumbPath;
QString m_cachePath;
QSize m_thumbSize;
bool m_dataInCache;
bool m_thumbInCache;
bool m_done{false}, m_successful{false};
int m_channels, m_frequency, m_lengthInFrames, m_audioStream;
QList <double>m_audioLevels;
QProcess *m_ffmpegProcess;
std::unique_ptr<QProcess> m_ffmpegProcess;
};
......@@ -81,9 +81,9 @@ bool ThumbJob::startJob()
return true;
}
m_inCache = false;
if (ThumbnailCache::get()->hasThumbnail(m_binClip->clipId(), m_frameNumber, !m_persistent)) {
if (ThumbnailCache::get()->hasThumbnail(m_clipId, m_frameNumber, !m_persistent)) {
m_done = true;
m_result = ThumbnailCache::get()->getThumbnail(m_binClip->clipId(), m_frameNumber);
m_result = ThumbnailCache::get()->getThumbnail(m_clipId, m_frameNumber);
m_inCache = true;
return true;
}
......@@ -129,7 +129,7 @@ bool ThumbJob::commitResult(Fun &undo, Fun &redo)
p.setPen(Qt::white);
p.drawText(0, 0, m_fullWidth, m_imageHeight, Qt::AlignCenter, i18n("Invalid"));
} else {
ThumbnailCache::get()->storeThumbnail(m_binClip->clipId(), m_frameNumber, m_result, m_persistent);
ThumbnailCache::get()->storeThumbnail(m_clipId, m_frameNumber, m_result, m_persistent);
}
}
m_resultConsumed = true;
......
......@@ -354,7 +354,7 @@
<entry name="window_background" type="Color">
<label>Background color for OpenGL monitor.</label>
<default>#999999</default>
<default>#535353</default>
</entry>
<entry name="volume" type="Int">
......
This diff is collapsed.
......@@ -114,7 +114,6 @@ public:
void lockMonitor();
void releaseMonitor();
int realTime() const;
void setAudioThumb(int channels = 0, const QList <double>&audioCache = QList<double>());
int droppedFrames() const;
void resetDrops();
bool checkFrameNumber(int pos, int offset);
......@@ -158,7 +157,6 @@ public slots:
void setZoom(float zoom);
void setOffsetX(int x, int max);
void setOffsetY(int y, int max);
void slotSwitchAudioOverlay(bool enable);
void slotZoom(bool zoomIn);
void initializeGL();
void releaseAnalyse();
......@@ -189,7 +187,6 @@ signals:
void seekPosition(int);
void consumerPosition(int);
void activateMonitor();
void buildAudioThumb(int channels = 0, const QList <double>&audioCache = QList<double>());
protected:
Mlt::Filter *m_glslManager;
......@@ -230,16 +227,13 @@ private:
bool m_isZoneMode;
bool m_isLoopMode;
QPoint m_offset;
bool m_audioWaveDisplayed;
MonitorProxy *m_proxy;
std::shared_ptr<Mlt::Producer> m_blackClip;
static void on_frame_show(mlt_consumer, void *self, mlt_frame frame);
static void on_audio_frame_show(mlt_consumer, void *self, mlt_frame frame);
static void on_frame_render(mlt_consumer, GLWidget *widget, mlt_frame frame);
static void on_gl_frame_show(mlt_consumer, void *self, mlt_frame frame_ptr);
static void on_gl_nosync_frame_show(mlt_consumer, void *self, mlt_frame frame_ptr);
void createAudioOverlay(bool isAudio);
void removeAudioOverlay();
void adjustAudioOverlay(bool isAudio);
QOpenGLFramebufferObject *m_fbo;
void refreshSceneLayout();
void resetZoneMode();
......@@ -315,6 +309,7 @@ public:
QSemaphore *semaphore() { return &m_semaphore; }
QOpenGLContext *context() const { return m_context; }
Q_INVOKABLE void showFrame(Mlt::Frame frame);
Q_INVOKABLE void showAudioFrame(Mlt::Frame frame);
Q_INVOKABLE void showGLFrame(Mlt::Frame frame);
Q_INVOKABLE void showGLNoSyncFrame(Mlt::Frame frame);
......
......@@ -39,6 +39,7 @@
#include "scopes/monitoraudiolevel.h"
#include "timeline2/model/snapmodel.hpp"
#include "transitions/transitionsrepository.hpp"
#include "utils/thumbnailcache.hpp"
#include "klocalizedstring.h"
#include <KDualAction>
......@@ -502,12 +503,6 @@ void Monitor::setupMenu(QMenu *goMenu, QMenu *overlayMenu, QAction *playZone, QA
m_contextMenu->addMenu(overlayMenu);
}
QAction *overlayAudio = m_contextMenu->addAction(QIcon(), i18n("Overlay audio waveform"));
overlayAudio->setCheckable(true);
connect(overlayAudio, &QAction::toggled, m_glMonitor, &GLWidget::slotSwitchAudioOverlay);
overlayAudio->setChecked(KdenliveSettings::displayAudioOverlay());
m_configMenu->addAction(overlayAudio);
QAction *switchAudioMonitor = m_configMenu->addAction(i18n("Show Audio Levels"), this, SLOT(slotSwitchAudioMonitor()));
switchAudioMonitor->setCheckable(true);
switchAudioMonitor->setChecked((KdenliveSettings::monitoraudio() & m_id) != 0);
......@@ -792,13 +787,11 @@ void Monitor::slotSwitchFullScreen(bool minimizeOnly)
} else {
m_videoWidget->setParent(qApp->desktop()->screen(0));
}
m_qmlManager->enableAudioThumbs(false);
m_videoWidget->showFullScreen();
} else {
m_videoWidget->setParent(m_glWidget);
//m_videoWidget->move(this->pos());
m_videoWidget->showNormal();
m_qmlManager->enableAudioThumbs(true);
auto *lay = (QGridLayout *)m_glWidget->layout();
lay->addWidget(m_videoWidget, 0, 0);
}
......@@ -872,18 +865,6 @@ void Monitor::slotStartDrag()
drag->exec(Qt::MoveAction);
}
void Monitor::enterEvent(QEvent *event)
{
m_qmlManager->enableAudioThumbs(true);
QWidget::enterEvent(event);
}
void Monitor::leaveEvent(QEvent *event)
{
m_qmlManager->enableAudioThumbs(false);
QWidget::leaveEvent(event);
}
// virtual
void Monitor::mouseMoveEvent(QMouseEvent *event)
{
......@@ -1349,6 +1330,7 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
{
if (m_controller) {
m_glMonitor->resetZoneMode();
disconnect(m_controller.get(), &ProjectClip::audioThumbReady, this, &Monitor::prepareAudioThumb);
disconnect(m_controller->getMarkerModel().get(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &)), this,
SLOT(checkOverlay()));
disconnect(m_controller->getMarkerModel().get(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(checkOverlay()));
......@@ -1358,6 +1340,7 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
m_snaps.reset(new SnapModel());
m_glMonitor->getControllerProxy()->resetZone();
if (controller) {
connect(m_controller.get(), &ProjectClip::audioThumbReady, this, &Monitor::prepareAudioThumb);
connect(m_controller->getMarkerModel().get(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &)), this,
SLOT(checkOverlay()));
connect(m_controller->getMarkerModel().get(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(checkOverlay()));
......@@ -1384,18 +1367,18 @@ void Monitor::slotOpenClip(const std::shared_ptr<ProjectClip> &controller, int i
if (m_playAction->isActive()) {
m_playAction->setActive(false);
}
m_glMonitor->setProducer(m_controller->originalProducer(), isActive(), in);
m_audioMeterWidget->audioChannels = controller->audioInfo() ? controller->audioInfo()->channels() : 0;
if (KdenliveSettings::displayClipMonitorInfo() & 0x10) {
m_glMonitor->setAudioThumb(controller->audioChannels(), controller->audioFrameCache);
if (!m_controller->hasVideo() || KdenliveSettings::displayClipMonitorInfo() & 0x10) {
m_glMonitor->getControllerProxy()->setAudioThumb(ThumbnailCache::get()->getAudioThumbPath(m_controller->clipId()));
}
m_controller->getMarkerModel()->registerSnapModel(m_snaps);
m_glMonitor->getControllerProxy()->setClipProperties(controller->clipType(), controller->hasAudioAndVideo(), controller->clipName());
m_glMonitor->setProducer(m_controller->originalProducer(), isActive(), in);
// hasEffects = controller->hasEffects();
} else {
loadQmlScene(MonitorSceneDefault);
m_glMonitor->setProducer(nullptr, isActive());
m_glMonitor->setAudioThumb();
m_glMonitor->getControllerProxy()->setAudioThumb();
m_audioMeterWidget->audioChannels = 0;
m_glMonitor->getControllerProxy()->setClipProperties(ClipType::Unknown, false, QString());
}
......@@ -1994,9 +1977,11 @@ void Monitor::slotEditInlineMarker()
}
}
void Monitor::prepareAudioThumb(int channels, const QList <double>&audioCache)
void Monitor::prepareAudioThumb()
{
m_glMonitor->buildAudioThumb(channels, audioCache);
if (m_controller) {
m_glMonitor->getControllerProxy()->setAudioThumb(ThumbnailCache::get()->getAudioThumbPath(m_controller->clipId()));
}
}
void Monitor::slotSwitchAudioMonitor()
......
......@@ -132,7 +132,7 @@ public:
QAction *recAction();
void refreshIcons();
/** @brief Send audio thumb data to qml for on monitor display */
void prepareAudioThumb(int channels, const QList <double>&audioCache = QList <double>());
void prepareAudioThumb();
void connectAudioSpectrum(bool activate);
/** @brief Set a property on the Qml scene **/
void setQmlProperty(const QString &name, const QVariant &value);
......@@ -168,8 +168,6 @@ protected:
* Ctrl + wheel moves by a second, without Ctrl it moves by a single frame. */
void wheelEvent(QWheelEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
virtual QStringList mimeTypes() const;
private:
......
......@@ -309,3 +309,9 @@ void MonitorProxy::setClipProperties(ClipType::ProducerType type, bool hasAV, co
emit clipTypeChanged();
}
}
void MonitorProxy::setAudioThumb(const QString thumbPath)
{
m_audioThumb = thumbPath;
emit audioThumbChanged();
}
......@@ -42,6 +42,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(QString 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
* */
......@@ -90,6 +91,7 @@ public:
Q_INVOKABLE QString toTimecode(int frames) const;
Q_INVOKABLE double fps() const;
void setClipProperties(ClipType::ProducerType type, bool hasAV, const QString clipName);
void setAudioThumb(const QString thumbPath = QString());
signals:
void positionChanged();
......@@ -110,6 +112,7 @@ signals:
void clipHasAVChanged();
void clipNameChanged();
void clipTypeChanged();
void audioThumbChanged();
private:
GLWidget *q;
......@@ -118,6 +121,7 @@ private:
int m_zoneIn;
int m_zoneOut;
bool m_hasAV;
QString m_audioThumb;
QString m_markerComment;
QString m_clipName;
int m_clipType;
......
......@@ -20,11 +20,11 @@
***************************************************************************/
#include "qmlmanager.h"
#include "qml/qmlaudiothumb.h"
#include <QFontDatabase>
#include <QQmlContext>
#include <QQuickView>
#include <QQuickItem>
QmlManager::QmlManager(QQuickView *view)
: QObject(view)
......@@ -33,14 +33,6 @@ QmlManager::QmlManager(QQuickView *view)
{
}
void QmlManager::enableAudioThumbs(bool enable)
{
auto *audioThumbDisplay = m_view->rootObject()->findChild<QmlAudioThumb *>(QStringLiteral("audiothumb"));
if (audioThumbDisplay) {
audioThumbDisplay->setProperty("stateVisible", enable);
}
}
MonitorSceneType QmlManager::sceneType() const
{
return m_sceneType;
......
......@@ -39,8 +39,6 @@ class QmlManager : public QObject
public:
explicit QmlManager(QQuickView *view);
/** @brief Show / hide audio thumbnail preview */
void enableAudioThumbs(bool enable);
/** @brief return current active scene type */
MonitorSceneType sceneType() const;
/** @brief Set a property on the root item */
......
......@@ -2,7 +2,6 @@ import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import Kdenlive.Controls 1.0
import QtQuick 2.6
import AudioThumb 1.0
import com.enums 1.0
Item {
......@@ -158,10 +157,9 @@ Item {
id: monitorOverlay
anchors.fill: parent
QmlAudioThumb {
Item {
id: audioThumb
objectName: "audiothumb"
property bool stateVisible: (clipMonitorRuler.containsMouse || barOverArea.mouseY >= root.height * 0.7)
property bool stateVisible: (clipMonitorRuler.containsMouse || (barOverArea.containsMouse && barOverArea.mouseY >= root.height * 0.7))
anchors {
left: parent.left
bottom: parent.bottom
......@@ -180,6 +178,30 @@ Item {
transitions: [ Transition {
NumberAnimation { property: "opacity"; duration: 500}
} ]
Rectangle {
color: "black"
opacity: 0.5
anchors.fill: parent
}
Rectangle {
color: "yellow"
opacity: 0.3
height: parent.height
x: controller.zoneIn * timeScale
width: (controller.zoneOut - controller.zoneIn) * timeScale
visible: controller.zoneIn > 0 || controller.zoneOut < duration - 1
}
Image {
anchors.fill: parent
source: controller.audioThumb
asynchronous: true
}
Rectangle {
color: "red"
width: 1
height: parent.height
x: controller.position * timeScale
}
}
Text {
......
......@@ -2,7 +2,6 @@ import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import Kdenlive.Controls 1.0
import QtQuick 2.4
import AudioThumb 1.0
Item {
id: root
......
set(kdenlive_SRCS
${kdenlive_SRCS}
qml/qmlaudiothumb.cpp
PARENT_SCOPE)
/*
Copyright (C) 2015 Jean-Baptiste Mardelle <jb@kdenlive.org>
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 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qmlaudiothumb.h"
#include <QPainter>
QmlAudioThumb::QmlAudioThumb(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
}
void QmlAudioThumb::setImage(const QImage &img)
{
m_img = img;
update();
}
void QmlAudioThumb::paint(QPainter *painter)
{
painter->drawImage(boundingRect(), m_img);
}
/*
Copyright (C) 2015 Jean-Baptiste Mardelle <jb@kdenlive.org>
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 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QMLAUDIOTHUMBS_H
#define QMLAUDIOTHUMBS_H
#include <QImage>
#include <QQuickPaintedItem>
class QPainter;
class QmlAudioThumb : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit QmlAudioThumb(QQuickItem *parent = nullptr);
void setImage(const QImage &img);
void paint(QPainter *painter) override;
private:
QImage m_img;
};
#endif
......@@ -104,17 +104,48 @@ bool ThumbnailCache::hasThumbnail(const QString &binId, int pos, bool volatileOn
{
QMutexLocker locker(&m_mutex);
bool ok = false;
auto key = getKey(binId, pos, &ok);
auto key = pos < 0 ? getAudioKey(binId, &ok) : getKey(binId, pos, &ok);
if (ok && m_volatileCache->contains(key)) {
return true;
}
if (!ok || volatileOnly) {
return false;
}
QDir thumbFolder = getDir(&ok);
QDir thumbFolder = getDir(pos < 0, &ok);
return ok && thumbFolder.exists(key);
}
QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly) const
{
QMutexLocker locker(&m_mutex);
bool ok = false;
auto key = getAudioKey(binId, &ok);
if (ok && m_volatileCache->contains(key)) {
return m_volatileCache->get(key);
}
if (!ok || volatileOnly) {
return QImage();
}
QDir thumbFolder = getDir(true, &ok);
if (ok && thumbFolder.exists(key)) {
m_storedOnDisk[binId].push_back(-1);
return QImage(thumbFolder.absoluteFilePath(key));
}
return QImage();
}
const QString 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 QStringLiteral("file://") + thumbFolder.absoluteFilePath(key);
}
return QString();
}
QImage ThumbnailCache::getThumbnail(const QString &binId, int pos, bool volatileOnly) const
{
QMutexLocker locker(&m_mutex);
......@@ -126,7 +157,7 @@ QImage ThumbnailCache::getThumbnail(const QString &binId, int pos, bool volatile
if (!ok || volatileOnly) {
return QImage();
}
QDir thumbFolder = getDir(&ok);
QDir thumbFolder = getDir(false, &ok);
if (ok && thumbFolder.exists(key)) {
m_storedOnDisk[binId].push_back(pos);
return QImage(thumbFolder.absoluteFilePath(key));
......@@ -143,7 +174,7 @@ void ThumbnailCache::storeThumbnail(const QString &binId, int pos, const QImage
return;
}
if (persistent) {
QDir thumbFolder = getDir(&ok);
QDir thumbFolder = getDir(false, &ok);
if (ok) {
if (!img.save(thumbFolder.absoluteFilePath(key))) {
qDebug() << ".............\nAAAAAAAAAAAARGH ERROR SAVING THUMB";
......@@ -166,7 +197,7 @@ void ThumbnailCache::storeThumbnail(const QString &binId, int pos, const QImage
void ThumbnailCache::saveCachedThumbs(QStringList keys)
{
bool ok;
QDir thumbFolder = getDir(&ok);
QDir thumbFolder = getDir(false, &ok);
if (!ok) {
return;
}
......@@ -195,17 +226,26 @@ void ThumbnailCache::invalidateThumbsForClip(const QString &binId)
m_storedVolatile.erase(binId);
}
bool ok = false;
QDir thumbFolder = getDir(&ok);
// Video thumbs
QDir thumbFolder = getDir(false, &ok);
QDir audioThumbFolder = getDir(true, &ok);
if (ok && m_storedOnDisk.find(binId) != m_storedOnDisk.end()) {
// Remove persistent cache
for (int pos : m_storedOnDisk.at(binId)) {
auto key = getKey(binId, pos, &ok);
if (ok) {
QFile::remove(thumbFolder.absoluteFilePath(key));
if (pos < 0) {
auto key = getAudioKey(binId, &ok);
if (ok) {
QFile::remove(audioThumbFolder.absoluteFilePath(key));
}
} else {
auto key = getKey(binId, pos, &ok);
if (ok) {
QFile::remove(thumbFolder.absoluteFilePath(key));
}
}
}
m_storedOnDisk.erase(binId);
}
}
}
// static
......@@ -217,7 +257,15 @@ QString ThumbnailCache::getKey(const QString &binId, int pos, bool *ok)
}
// static
QDir ThumbnailCache::getDir(bool *ok)
QString ThumbnailCache::getAudioKey(const QString &binId, bool *ok)
{
auto binClip =