Commit 3dcf36a6 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Various small fixes for proxy status and job (Fixes #1426)

Small improvements to thumbnail cache
parent 93118c5d
......@@ -4500,12 +4500,12 @@ void Bin::reloadAllProducers(bool reloadThumbs)
}
}
if (!xml.isNull()) {
clip->setClipStatus(FileStatus::StatusWaiting);
pCore->taskManager.discardJobs({ObjectType::BinClip, clip->clipId().toInt()}, AbstractTask::NOJOBTYPE, true);
clip->discardAudioThumb();
if (reloadThumbs) {
ThumbnailCache::get()->invalidateThumbsForClip(clip->clipId());
}
clip->setClipStatus(FileStatus::StatusWaiting);
pCore->taskManager.discardJobs({ObjectType::BinClip, clip->clipId().toInt()}, AbstractTask::NOJOBTYPE, true, {AbstractTask::TRANSCODEJOB,AbstractTask::PROXYJOB,AbstractTask::AUDIOTHUMBJOB});
ClipLoadTask::start({ObjectType::BinClip,clip->clipId().toInt()}, xml, false, -1, -1, this);
}
}
......
......@@ -1258,12 +1258,6 @@ double ProjectClip::getOriginalFps() const
return originalFps();
}
bool ProjectClip::hasProxy() const
{
QString proxy = getProducerProperty(QStringLiteral("kdenlive:proxy"));
return proxy.size() > 2;
}
void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool refreshPanel)
{
qDebug() << "// SETTING CLIP PROPERTIES: " << properties;
......
......@@ -147,9 +147,6 @@ public:
/** @brief Callculate a file hash from a path. */
static const QPair<QByteArray, qint64> calculateHash(const QString &path);
/** @brief Returns true if we are using a proxy for this clip. */
bool hasProxy() const;
/** Cache for every audio Frame with 10 Bytes */
/** format is frame -> channel ->bytes */
bool audioThumbCreated() const;
......
......@@ -1411,7 +1411,7 @@ void KdenliveDoc::loadDocumentProperties()
void KdenliveDoc::updateProjectProfile(bool reloadProducers, bool reloadThumbs)
{
pCore->taskManager.slotCancelJobs();
pCore->taskManager.slotCancelJobs({AbstractTask::PROXYJOB,AbstractTask::AUDIOTHUMBJOB,AbstractTask::TRANSCODEJOB});
double fps = pCore->getCurrentFps();
double fpsChanged = m_timecode.fps() / fps;
m_timecode.setFormat(fps);
......@@ -1430,8 +1430,8 @@ void KdenliveDoc::resetProfile(bool reloadThumbs)
void KdenliveDoc::slotSwitchProfile(const QString &profile_path, bool reloadThumbs)
{
// Discard all current jobs
pCore->taskManager.slotCancelJobs();
// Discard all current jobs except proxy and audio thumbs
pCore->taskManager.slotCancelJobs({AbstractTask::PROXYJOB,AbstractTask::AUDIOTHUMBJOB,AbstractTask::TRANSCODEJOB});
pCore->setCurrentProfile(profile_path);
updateProjectProfile(true, reloadThumbs);
// In case we only have one clip in timeline,
......@@ -1496,7 +1496,7 @@ void KdenliveDoc::switchProfile(ProfileParam* pf, const QString clipName)
switch (answer) {
case KMessageBox::Yes:
// Discard all current jobs
pCore->taskManager.slotCancelJobs();
pCore->taskManager.slotCancelJobs({AbstractTask::PROXYJOB,AbstractTask::AUDIOTHUMBJOB,AbstractTask::TRANSCODEJOB});
KdenliveSettings::setDefault_profile(profile->path());
pCore->setCurrentProfile(profile->path());
updateProjectProfile(true, true);
......@@ -1531,7 +1531,7 @@ void KdenliveDoc::switchProfile(ProfileParam* pf, const QString clipName)
.arg(QString::number(double(profile->m_frame_rate_num) / profile->m_frame_rate_den, 'f', 2));
QString profilePath = ProfileRepository::get()->saveProfile(profile.get());
// Discard all current jobs
pCore->taskManager.slotCancelJobs();
pCore->taskManager.slotCancelJobs({AbstractTask::PROXYJOB,AbstractTask::AUDIOTHUMBJOB,AbstractTask::TRANSCODEJOB});
pCore->setCurrentProfile(profilePath);
updateProjectProfile(true, true);
emit docModified(true);
......
......@@ -73,7 +73,7 @@ void AbstractTask::cancelJob(bool softDelete)
if (softDelete) {
m_softDelete.testAndSetAcquire(0, 1);
}
qDebug()<<"====== SETTING TASK CANCELED: "<<m_isCanceled;
qDebug()<<"====== SETTING TASK CANCELED: "<<m_isCanceled<<", TYPE: "<<m_type;
emit jobCanceled();
}
......
......@@ -38,9 +38,9 @@ void TaskManager::updateConcurrency()
m_transcodePool.setMaxThreadCount(KdenliveSettings::proxythreads());
}
void TaskManager::discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type, bool softDelete)
void TaskManager::discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type, bool softDelete, const QVector<AbstractTask::JOBTYPE> exceptions)
{
qDebug()<<"========== READY FOR TASK DELETION ON: "<<owner.second;
qDebug()<<"========== READY FOR TASK DISCARD ON: "<<owner.second;
m_tasksListLock.lockForRead();
// See if there is already a task for this MLT service and resource.
if (m_taskList.find(owner.second) == m_taskList.end()) {
......@@ -52,6 +52,10 @@ void TaskManager::discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type,
for (AbstractTask* t : taskList) {
if ((type == AbstractTask::NOJOBTYPE || type == t->m_type) && t->m_progress < 100) {
// If so, then just add ourselves to be notified upon completion.
if (exceptions.contains(t->m_type)) {
// Don't abort
continue;
}
t->cancelJob(softDelete);
qDebug()<<"========== DELETING JOB!!!!";
// Block until the task is finished
......@@ -120,19 +124,23 @@ void TaskManager::taskDone(int cid, AbstractTask *task)
}
void TaskManager::slotCancelJobs()
void TaskManager::slotCancelJobs(const QVector<AbstractTask::JOBTYPE> exceptions)
{
m_tasksListLock.lockForRead();
// See if there is already a task for this MLT service and resource.
for (const auto &task : m_taskList) {
for (AbstractTask* t : task.second) {
// If so, then just add ourselves to be notified upon completion.
t->cancelJob();
if (!exceptions.contains(t->m_type)) {
// If so, then just add ourselves to be notified upon completion.
t->cancelJob();
}
}
}
m_tasksListLock.unlock();
m_taskPool.waitForDone();
m_transcodePool.waitForDone();
if (exceptions.isEmpty()) {
m_taskPool.waitForDone();
m_transcodePool.waitForDone();
}
updateJobCount();
}
......
......@@ -41,7 +41,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, bool softDelete = false);
void discardJobs(const ObjectId &owner, AbstractTask::JOBTYPE type = AbstractTask::NOJOBTYPE, bool softDelete = false, const QVector<AbstractTask::JOBTYPE> exceptions = {});
/** @brief Check if there is a pending / running job a clip.
* @param owner the owner item for this task
......@@ -68,7 +68,7 @@ public:
public slots:
/** @brief Discard all running jobs. */
void slotCancelJobs();
void slotCancelJobs(const QVector<AbstractTask::JOBTYPE> exceptions = {});
private slots:
/** @brief Update number of running jobs. */
......
......@@ -109,7 +109,7 @@ int main(int argc, char *argv[])
#endif
#if defined(Q_OS_WIN) || defined (Q_OS_MACOS)
const QStringList themes {"/icons/breeze/breeze-icons.rcc", "/icons/breeze-dark/breeze-icons-dark.rcc"};
for(const QString theme : themes ) {
for(const QString &theme : themes ) {
const QString themePath = QStandardPaths::locate(QStandardPaths::AppDataLocation, theme);
if (!themePath.isEmpty()) {
const QString iconSubdir = theme.left(theme.lastIndexOf('/'));
......
......@@ -178,12 +178,14 @@ void ClipController::getInfoForProducer()
proxy.prepend(pCore->currentDoc()->documentRoot());
m_properties->set("kdenlive:proxy", proxy.toUtf8().constData());
}
// This is a proxy producer, read original url from kdenlive property
path = m_properties->get("kdenlive:originalurl");
if (QFileInfo(path).isRelative()) {
path.prepend(pCore->currentDoc()->documentRoot());
if (proxy == path) {
// This is a proxy producer, read original url from kdenlive property
path = m_properties->get("kdenlive:originalurl");
if (QFileInfo(path).isRelative()) {
path.prepend(pCore->currentDoc()->documentRoot());
}
m_usesProxy = true;
}
m_usesProxy = true;
} else if (m_service != QLatin1String("color") && m_service != QLatin1String("colour") && !path.isEmpty() && QFileInfo(path).isRelative() &&
path != QLatin1String("<producer>")) {
path.prepend(pCore->currentDoc()->documentRoot());
......@@ -336,7 +338,7 @@ void ClipController::updateProducer(const std::shared_ptr<Mlt::Producer> &produc
Mlt::Properties passProperties;
// Keep track of necessary properties
QString proxy = producer->get("kdenlive:proxy");
if (proxy.length() > 2) {
if (proxy.length() > 2 && producer->get("resource") == proxy) {
// This is a proxy producer, read original url from kdenlive property
m_usesProxy = true;
} else {
......@@ -1022,3 +1024,10 @@ const QString ClipController::getOriginalUrl()
}
return path;
}
bool ClipController::hasProxy() const
{
QString proxy = getProducerProperty(QStringLiteral("kdenlive:proxy"));
//qDebug()<<"::: PROXY: "<<proxy<<" = "<<clipUrl();
return proxy.size() > 2 && proxy == clipUrl();
}
......@@ -207,6 +207,8 @@ public:
int audioStreamsCount() const;
/** @brief Get the path to the original clip url (in case it is proxied) */
const QString getOriginalUrl();
/** @brief Returns true if we are using a proxy for this clip. */
bool hasProxy() const;
protected:
/** @brief Mutex to protect the producer properties on read/write */
......
......@@ -440,7 +440,7 @@ ClipPropertiesController::ClipPropertiesController(ClipController *controller, Q
// Proxy codec label
QLabel *lab = new QLabel(this);
pbox->setObjectName(QStringLiteral("kdenlive:proxy"));
bool hasProxy = proxy.length() > 2;
bool hasProxy = m_controller->hasProxy();
if (hasProxy) {
bg->setToolTip(proxy);
bool proxyReady = (QFileInfo(proxy).fileName() == QFileInfo(m_properties->get("resource")).fileName());
......
......@@ -1292,13 +1292,14 @@ void TimelineController::switchGuide(int frame, bool deleteOnly, bool showGui)
void TimelineController::addAsset(const QVariantMap &data)
{
QString effect = data.value(QStringLiteral("kdenlive/effect")).toString();
const auto selection = m_model->getCurrentSelection();
bool audioEffect = EffectsRepository::get()->isAudioEffect(effect);
int affectedClips = 0;
int cid = -1;
if (!selection.empty()) {
QList<int> effectSelection;
int affectedClips = 0;
int cid = -1;
QString effect = data.value(QStringLiteral("kdenlive/effect")).toString();
bool audioEffect = EffectsRepository::get()->isAudioEffect(effect);
for (int id : selection) {
if (m_model->isClip(id) && audioEffect == m_model->m_allClips.at(id)->isAudioOnly()) {
effectSelection << id;
......
......@@ -115,6 +115,7 @@ bool ThumbnailCache::hasThumbnail(const QString &binId, int pos, bool volatileOn
if (!ok || volatileOnly) {
return false;
}
locker.unlock();
QDir thumbFolder = getDir(pos < 0, &ok);
return ok && thumbFolder.exists(key);
}
......@@ -132,7 +133,10 @@ QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly
}
QDir thumbFolder = getDir(true, &ok);
if (ok && thumbFolder.exists(key)) {
m_storedOnDisk[binId].push_back(-1);
if (std::find(m_storedOnDisk[binId].begin(), m_storedOnDisk[binId].end(), -1) != m_storedOnDisk[binId].end()) {
m_storedOnDisk[binId].push_back(-1);
}
locker.unlock();
return QImage(thumbFolder.absoluteFilePath(key));
}
return QImage();
......@@ -140,7 +144,6 @@ QImage ThumbnailCache::getAudioThumbnail(const QString &binId, bool volatileOnly
const QList <QUrl> ThumbnailCache::getAudioThumbPath(const QString &binId) const
{
QReadLocker locker(&m_mutex);
bool ok = false;
auto key = getAudioKey(binId, &ok);
QDir thumbFolder = getDir(true, &ok);
......@@ -174,6 +177,7 @@ QImage ThumbnailCache::getThumbnail(QString hash, const QString &binId, int pos,
if(m_storedOnDisk.find(binId) == m_storedOnDisk.end() || std::find(m_storedOnDisk[binId].begin(), m_storedOnDisk[binId].end(), pos) == m_storedOnDisk[binId].end()) {
m_storedOnDisk[binId].push_back(pos);
}
locker.unlock();
return QImage(thumbFolder.absoluteFilePath(hash));
}
return QImage();
......@@ -195,6 +199,7 @@ QImage ThumbnailCache::getThumbnail(const QString &binId, int pos, bool volatile
if(m_storedOnDisk.find(binId) == m_storedOnDisk.end() || std::find(m_storedOnDisk[binId].begin(), m_storedOnDisk[binId].end(), pos) == m_storedOnDisk[binId].end()) {
m_storedOnDisk[binId].push_back(pos);
}
locker.unlock();
return QImage(thumbFolder.absoluteFilePath(key));
}
return QImage();
......@@ -208,24 +213,25 @@ void ThumbnailCache::storeThumbnail(const QString &binId, int pos, const QImage
if (!ok) {
return;
}
// if volatile cache also contains this entry, update it
if (m_volatileCache->contains(key)) {
m_volatileCache->remove(key);
} else {
m_storedVolatile[binId].push_back(pos);
}
m_volatileCache->insert(key, img, (int)img.sizeInBytes());
if (persistent) {
QDir thumbFolder = getDir(false, &ok);
if (ok) {
if (!img.save(thumbFolder.absoluteFilePath(key))) {
qDebug() << ".............\n!!!!!!!! ERROR SAVING THUMB in: "<<thumbFolder.absoluteFilePath(key);
}
if (m_storedOnDisk.find(binId) == m_storedOnDisk.end() || std::find(m_storedOnDisk[binId].begin(), m_storedOnDisk[binId].end(), pos) == m_storedOnDisk[binId].end()) {
m_storedOnDisk[binId].push_back(pos);
}
m_mutex.unlock();
if (!img.save(thumbFolder.absoluteFilePath(key))) {
qDebug() << ".............\n!!!!!!!! ERROR SAVING THUMB in: "<<thumbFolder.absoluteFilePath(key);
}
}
}
// if volatile cache also contains this entry, update it
if (m_volatileCache->contains(key)) {
m_volatileCache->remove(key);
} else {
m_storedVolatile[binId].push_back(pos);
}
m_volatileCache->insert(key, img, (int)img.sizeInBytes());
}
bool ThumbnailCache::checkIntegrity() const
......@@ -278,19 +284,29 @@ void ThumbnailCache::invalidateThumbsForClip(const QString &binId)
}
bool ok = false;
// Video thumbs
QDir thumbFolder = getDir(false, &ok);
if (ok && m_storedOnDisk.find(binId) != m_storedOnDisk.end()) {
QStringList files;
if (m_storedOnDisk.find(binId) != m_storedOnDisk.end()) {
// Remove persistent cache
for (const auto &pos : m_storedOnDisk.at(binId)) {
if (pos >= 0) {
auto key = getKey(binId, pos, &ok);
if (ok) {
QFile::remove(thumbFolder.absoluteFilePath(key));
files << key;
}
}
}
m_storedOnDisk.erase(binId);
}
// Release mutex before deleting files
locker.unlock();
if (!files.isEmpty()) {
QDir thumbFolder = getDir(false, &ok);
if (ok) {
while (!files.isEmpty()) {
thumbFolder.remove(files.takeFirst());
}
}
}
}
void ThumbnailCache::clearCache()
......
Supports Markdown
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