Commit 891149f2 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Fix project clips disappearing on proxy creation.

Related to #986
parent fd6e429e
Pipeline #62378 passed with stage
in 8 minutes and 10 seconds
......@@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "effects/effectstack/model/effectstackmodel.hpp"
#include "jobs/transcodetask.h"
#include "jobs/taskmanager.h"
#include "jobs/abstracttask.h"
#include "jobs/cliploadtask.h"
#include "kdenlive_debug.h"
#include "kdenlivesettings.h"
......@@ -1246,7 +1247,7 @@ Bin::Bin(std::shared_ptr<ProjectItemModel> model, QWidget *parent)
connect(m_discardCurrentClipJobs, &QAction::triggered, this, [&]() {
const QString currentId = m_monitor->activeClipId();
if (!currentId.isEmpty()) {
pCore->taskManager.discardJobs({ObjectType::BinClip,currentId.toInt()});
pCore->taskManager.discardJobs({ObjectType::BinClip,currentId.toInt()}, AbstractTask::NOJOBTYPE, true);
}
});
connect(m_cancelJobs, &QAction::triggered, [&]() {
......@@ -4061,7 +4062,7 @@ void Bin::reloadAllProducers(bool reloadThumbs)
}
if (!xml.isNull()) {
clip->setClipStatus(FileStatus::StatusWaiting);
pCore->taskManager.discardJobs({ObjectType::BinClip, clip->clipId().toInt()});
pCore->taskManager.discardJobs({ObjectType::BinClip, clip->clipId().toInt()}, AbstractTask::NOJOBTYPE, true);
clip->discardAudioThumb();
// We need to set a temporary id before all outdated producers are replaced;
//int jobId = pCore->jobManager()->startJob<LoadJob>({clip->clipId()}, -1, QString(), xml);
......
......@@ -377,14 +377,15 @@ void ProjectClip::reloadProducer(bool refreshOnly, bool isProxy, bool forceAudio
// We thus set up a thumb job. We must make sure that there is no pending LOADJOB
// Clear cache first
ThumbnailCache::get()->invalidateThumbsForClip(clipId());
pCore->taskManager.discardJobs({ObjectType::BinClip, m_binId.toInt()}, AbstractTask::LOADJOB, true);
pCore->taskManager.discardJobs({ObjectType::BinClip, m_binId.toInt()}, AbstractTask::CACHEJOB);
pCore->taskManager.discardJobs({ObjectType::BinClip, m_binId.toInt()}, AbstractTask::LOADJOB);
m_thumbsProducer.reset();
ClipLoadTask::start({ObjectType::BinClip,m_binId.toInt()}, QDomElement(), true, -1, -1, this);
} else {
// If another load job is running?
pCore->taskManager.discardJobs({ObjectType::BinClip, m_binId.toInt()});
if (QFile::exists(m_path) && !hasProxy()) {
pCore->taskManager.discardJobs({ObjectType::BinClip, m_binId.toInt()}, AbstractTask::LOADJOB, true);
pCore->taskManager.discardJobs({ObjectType::BinClip, m_binId.toInt()}, AbstractTask::CACHEJOB);
if (QFile::exists(m_path) && (!isProxy && !hasProxy())) {
clearBackupProperties();
}
QDomDocument doc;
......@@ -405,7 +406,6 @@ void ProjectClip::reloadProducer(bool refreshOnly, bool isProxy, bool forceAudio
hashChanged = true;
}
}
}
ThumbnailCache::get()->invalidateThumbsForClip(clipId());
if (forceAudioReload || (!isProxy && hashChanged)) {
......@@ -534,9 +534,26 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
updateParent(parentItem().lock());
ClipLoadTask::start({ObjectType::BinClip,m_binId.toInt()}, QDomElement(), true, -1, -1, this);
AudioLevelsTask::start({ObjectType::BinClip, m_binId.toInt()}, this, false);
pCore->bin()->reloadMonitorIfActive(clipId());
for (auto &p : m_audioProducers) {
m_effectStack->removeService(p.second);
}
for (auto &p : m_videoProducers) {
m_effectStack->removeService(p.second);
}
for (auto &p : m_timewarpProducers) {
m_effectStack->removeService(p.second);
}
// Release audio producers
m_audioProducers.clear();
m_videoProducers.clear();
m_timewarpProducers.clear();
emit refreshPropertiesPanel();
replaceInTimeline();
updateTimelineClips({TimelineModel::IsProxyRole});
bool generateProxy = false;
QList<std::shared_ptr<ProjectClip>> clipList;
if (pCore->currentDoc()->getDocumentProperty(QStringLiteral("enableproxy")).toInt() == 1) {
QList<std::shared_ptr<ProjectClip>> clipList;
// automatic proxy generation enabled
if (m_clipType == ClipType::Image && pCore->currentDoc()->getDocumentProperty(QStringLiteral("generateimageproxy")).toInt() == 1) {
if (getProducerIntProperty(QStringLiteral("meta.media.width")) >= KdenliveSettings::proxyimageminsize() &&
......@@ -572,31 +589,17 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
}
}
if (!clipList.isEmpty()) {
pCore->currentDoc()->slotProxyCurrentItem(true, clipList, false);
generateProxy = true;
}
}
pCore->bin()->reloadMonitorIfActive(clipId());
for (auto &p : m_audioProducers) {
m_effectStack->removeService(p.second);
}
for (auto &p : m_videoProducers) {
m_effectStack->removeService(p.second);
}
for (auto &p : m_timewarpProducers) {
m_effectStack->removeService(p.second);
}
// Release audio producers
m_audioProducers.clear();
m_videoProducers.clear();
m_timewarpProducers.clear();
emit refreshPropertiesPanel();
if (KdenliveSettings::hoverPreview() && (m_clipType == ClipType::AV || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist)) {
if (!generateProxy && KdenliveSettings::hoverPreview() && (m_clipType == ClipType::AV || m_clipType == ClipType::Video || m_clipType == ClipType::Playlist)) {
QTimer::singleShot(1000, this, [this]() {
CacheTask::start({ObjectType::BinClip,m_binId.toInt()}, 30, 0, 0, this);
});
}
replaceInTimeline();
updateTimelineClips({TimelineModel::IsProxyRole});
if (generateProxy) {
QMetaObject::invokeMethod(pCore->currentDoc(), "slotProxyCurrentItem", Q_ARG(bool,true), Q_ARG(QList<std::shared_ptr<ProjectClip>>,clipList), Q_ARG(bool,false));
}
return true;
}
......@@ -2056,3 +2059,10 @@ void ProjectClip::setInvalid()
{
m_isInvalid = true;
}
void ProjectClip::updateProxyProducer(const QString &path)
{
setProducerProperty(QStringLiteral("_overwriteproxy"), QString());
setProducerProperty(QStringLiteral("resource"), path);
reloadProducer(false, true);
}
......@@ -80,7 +80,7 @@ protected:
public:
~ProjectClip() override;
void reloadProducer(bool refreshOnly = false, bool isProxy = false, bool forceAudioReload = false);
void reloadProducer(bool refreshOnly = false, bool isProxy = false, bool forceAudioReload = false) override;
/** @brief Returns a unique hash identifier used to store clip thumbnails. */
// virtual void hash() = 0;
......@@ -280,6 +280,9 @@ public slots:
void setThumbnail(const QImage &, int in, int out);
void setThumbProducer(std::shared_ptr<Mlt::Producer>prod);
/** @brief A proxy clip is available or disabled, update path and reload */
void updateProxyProducer(const QString &path);
/**
* Imports effect from a given producer
* @param producer Producer containing the effects
......
......@@ -39,6 +39,7 @@ AbstractTask::AbstractTask(const ObjectId &owner, JOBTYPE type, QObject* object)
, m_object(object)
, m_progress(0)
, m_isCanceled(false)
, m_softDelete(false)
, m_isForce(false)
, m_running(false)
, m_type(type)
......@@ -64,9 +65,12 @@ AbstractTask::AbstractTask(const ObjectId &owner, JOBTYPE type, QObject* object)
}
}
void AbstractTask::cancelJob()
void AbstractTask::cancelJob(bool softDelete)
{
m_isCanceled.testAndSetAcquire(0, 1);
if (softDelete) {
m_softDelete.testAndSetAcquire(0, 1);
}
qDebug()<<"====== SETTING TACK CANCELED: "<<m_isCanceled;
emit jobCanceled();
}
......
......@@ -58,6 +58,7 @@ protected:
int m_progress;
bool m_successful;
QAtomicInt m_isCanceled;
QAtomicInt m_softDelete;
bool m_isForce;
bool m_running;
void run() override;
......@@ -67,7 +68,7 @@ private:
//QString cacheKey();
JOBTYPE m_type;
int m_priority;
void cancelJob();
void cancelJob(bool softDelete = false);
signals:
void jobCanceled();
......
......@@ -688,10 +688,12 @@ void ClipLoadTask::abort()
{
Fun undo = []() { return true; };
Fun redo = []() { return true; };
auto binClip = pCore->projectItemModel()->getClipByBinID(QString::number(m_owner.second));
if (binClip) {
binClip->setInvalid();
pCore->projectItemModel()->requestBinClipDeletion(binClip, undo, redo);
if (!m_softDelete) {
auto binClip = pCore->projectItemModel()->getClipByBinID(QString::number(m_owner.second));
if (binClip) {
binClip->setInvalid();
pCore->projectItemModel()->requestBinClipDeletion(binClip, undo, redo);
}
}
pCore->taskManager.taskDone(m_owner.second, this);
}
......@@ -65,6 +65,9 @@ void ProxyTask::run()
}
m_running = true;
auto binClip = pCore->projectItemModel()->getClipByBinID(QString::number(m_owner.second));
if (binClip == nullptr) {
return;
}
const QString dest = binClip->getProducerProperty(QStringLiteral("kdenlive:proxy"));
QFileInfo fInfo(dest);
if (binClip->getProducerIntProperty(QStringLiteral("_overwriteproxy")) == 0 && fInfo.exists() && fInfo.size() > 0) {
......@@ -72,28 +75,10 @@ void ProxyTask::run()
m_progress = 100;
pCore->taskManager.taskDone(m_owner.second, this);
QMetaObject::invokeMethod(m_object, "updateJobProgress");
auto operation = [clipId = QString::number(m_owner.second)]() {
auto binClip = pCore->projectItemModel()->getClipByBinID(clipId);
if (binClip) {
binClip->setProducerProperty(QStringLiteral("_overwriteproxy"), QString());
const QString dest = binClip->getProducerProperty(QStringLiteral("kdenlive:proxy"));
binClip->setProducerProperty(QStringLiteral("resource"), dest);
pCore->bin()->reloadClip(clipId);
}
return true;
};
auto reverse = [clipId = QString::number(m_owner.second)]() {
auto binClip = pCore->projectItemModel()->getClipByBinID(clipId);
if (binClip) {
const QString dest = binClip->getProducerProperty(QStringLiteral("kdenlive:originalurl"));
binClip->setProducerProperty(QStringLiteral("resource"), dest);
pCore->bin()->reloadClip(clipId);
}
return true;
};
bool ok = operation();
QMetaObject::invokeMethod(binClip.get(), "updateProxyProducer", Qt::QueuedConnection, Q_ARG(const QString&,dest));
return;
}
ClipType::ProducerType type = binClip->clipType();
m_progress = 0;
bool result = false;
......@@ -379,29 +364,12 @@ void ProxyTask::run()
// File was not created
result = false;
m_errorMessage.append(i18n("Failed to create proxy clip."));
binClip->setProducerProperty(QStringLiteral("kdenlive:proxy"), QStringLiteral("-"));
} else {
if (binClip) {
binClip->setProducerProperty(QStringLiteral("kdenlive:proxy"), QStringLiteral("-"));
}
} else if (binClip) {
// Job successful
auto operation = [clipId = QString::number(m_owner.second)]() {
auto binClip = pCore->projectItemModel()->getClipByBinID(clipId);
if (binClip) {
binClip->setProducerProperty(QStringLiteral("_overwriteproxy"), QString());
const QString dest = binClip->getProducerProperty(QStringLiteral("kdenlive:proxy"));
binClip->setProducerProperty(QStringLiteral("resource"), dest);
pCore->bin()->reloadClip(clipId);
}
return true;
};
auto reverse = [clipId = QString::number(m_owner.second)]() {
auto binClip = pCore->projectItemModel()->getClipByBinID(clipId);
if (binClip) {
const QString dest = binClip->getProducerProperty(QStringLiteral("kdenlive:originalurl"));
binClip->setProducerProperty(QStringLiteral("resource"), dest);
pCore->bin()->reloadClip(clipId);
}
return true;
};
bool ok = operation();
QMetaObject::invokeMethod(binClip.get(), "updateProxyProducer", Qt::QueuedConnection, Q_ARG(const QString&,dest));
}
} else {
// Proxy process crashed
......
......@@ -48,7 +48,7 @@ TaskManager::~TaskManager()
slotCancelJobs();
}
void TaskManager::discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type)
void TaskManager::discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type, bool softDelete)
{
qDebug()<<"========== READY FOR TASK DELETION ON: "<<owner.second;
m_tasksListLock.lockForRead();
......@@ -60,9 +60,9 @@ void TaskManager::discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type)
std::vector<AbstractTask*> taskList = m_taskList.at(owner.second);
m_tasksListLock.unlock();
for (AbstractTask* t : taskList) {
if (type == AbstractTask::NOJOBTYPE || type == t->m_type) {
if ((type == AbstractTask::NOJOBTYPE || type == t->m_type) && t->m_progress < 100) {
// If so, then just add ourselves to be notified upon completion.
t->cancelJob();
t->cancelJob(softDelete);
qDebug()<<"========== DELETING JOB!!!!";
// Block until the task is finished
//t->m_runMutex.lock();
......
......@@ -55,7 +55,7 @@ public:
* @param owner the owner item for this task
* @param type The type of job that you want to abort, leave to NOJOBTYPE to abort all jobs
*/
void discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type = AbstractTask::NOJOBTYPE);
void discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type = AbstractTask::NOJOBTYPE, bool softDelete = false);
/** @brief Check if there is a pending / running job a clip.
* @param owner the owner item for this task
......
......@@ -96,6 +96,8 @@ public:
/** @brief Returns this clip's producer. */
virtual std::shared_ptr<Mlt::Producer> thumbProducer() = 0;
virtual void reloadProducer(bool refreshOnly = false, bool isProxy = false, bool forceAudioReload = false) = 0;
/** @brief Rename an audio stream. */
virtual void renameAudioStream(int id, QString name) = 0;
......
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