Commit 91d64a57 authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Job fixes

parent 4ba9c744
......@@ -68,7 +68,7 @@ void AbstractProjectItem::setRefCount(uint count)
{
m_usage = count;
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<AbstractProjectItem>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<AbstractProjectItem>(shared_from_this()), AbstractProjectItem::UsageCount);
}
uint AbstractProjectItem::refCount() const
......@@ -80,14 +80,14 @@ void AbstractProjectItem::addRef()
{
m_usage++;
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<AbstractProjectItem>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<AbstractProjectItem>(shared_from_this()), AbstractProjectItem::UsageCount);
}
void AbstractProjectItem::removeRef()
{
m_usage--;
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<AbstractProjectItem>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<AbstractProjectItem>(shared_from_this()), AbstractProjectItem::UsageCount);
}
const QString &AbstractProjectItem::clipId() const
......@@ -282,14 +282,10 @@ QString AbstractProjectItem::lastParentId() const
void AbstractProjectItem::updateParent(std::shared_ptr<TreeItem> newParent)
{
bool reload = !m_lastParentId.isEmpty();
//bool reload = !m_lastParentId.isEmpty();
m_lastParentId.clear();
if (newParent) {
m_lastParentId = std::static_pointer_cast<AbstractProjectItem>(newParent)->clipId();
}
TreeItem::updateParent(newParent);
if (reload && itemType() != ProjectItemType::ProjectFolderType) {
pCore->jobManager()->startJob<ThumbJob>({clipId()}, {}, QString(), 150, -1, true);
pCore->jobManager()->startJob<AudioThumbJob>({clipId()}, {}, QString());
}
}
......@@ -85,6 +85,7 @@ ProjectClip::ProjectClip(const QString &id, const QIcon &thumb, std::shared_ptr<
QMetaObject::invokeMethod(m_markerModel.get(), "importFromJson", Qt::QueuedConnection, Q_ARG(const QString &, markers), Q_ARG(bool, true),
Q_ARG(bool, false));
}
connectEffectStack();
}
// static
......@@ -121,7 +122,6 @@ ProjectClip::ProjectClip(const QString &id, const QDomElement &description, cons
m_name = i18n("Untitled");
}
connect(m_markerModel.get(), &MarkerListModel::modelChanged, [&]() { setProducerProperty(QStringLiteral("kdenlive:markers"), m_markerModel->toJson()); });
connectEffectStack();
}
std::shared_ptr<ProjectClip> ProjectClip::construct(const QString &id, const QDomElement &description, const QIcon &thumb,
......@@ -331,7 +331,9 @@ void ProjectClip::setThumbnail(const QImage &img)
}
m_thumbnail = QIcon(thumb);
updateTimelineClips(QVector<int>() << TimelineModel::ReloadThumb);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()));
if (auto ptr = m_model.lock()) {
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataThumbnail);
}
}
QPixmap ProjectClip::thumbnail(int width, int height)
......@@ -343,6 +345,7 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
{
qDebug() << "################### ProjectClip::setproducer";
updateProducer(std::move(producer));
connectEffectStack();
// Update info
if (m_name.isEmpty()) {
......@@ -365,7 +368,7 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshPanel(m_binId);
}
if (auto ptr = m_model.lock()) {
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataDuration);
}
// Make sure we have a hash for this clip
getFileHash();
......@@ -562,7 +565,7 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
if (properties.contains(QStringLiteral("templatetext"))) {
m_description = properties.value(QStringLiteral("templatetext"));
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::ClipStatus);
refreshPanel = true;
}
timelineProperties << QStringLiteral("force_aspect_ratio") << QStringLiteral("video_index") << QStringLiteral("audio_index")
......@@ -616,7 +619,7 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
if (properties.contains(QStringLiteral("length")) || properties.contains(QStringLiteral("kdenlive:duration"))) {
m_duration = getStringDuration();
if (auto ptr = m_model.lock())
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataDuration);
refreshOnly = false;
reload = true;
}
......@@ -625,7 +628,7 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
m_name = properties.value(QStringLiteral("kdenlive:clipname"));
refreshPanel = true;
if (auto ptr = m_model.lock()) {
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()));
std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()), AbstractProjectItem::DataName);
}
// update timeline clips
updateTimelineClips(QVector<int>() << TimelineModel::NameRole);
......
......@@ -290,21 +290,21 @@ QMimeData *ProjectItemModel::mimeData(const QModelIndexList &indices) const
return mimeData;
}
void ProjectItemModel::onItemUpdated(std::shared_ptr<AbstractProjectItem> item)
void ProjectItemModel::onItemUpdated(std::shared_ptr<AbstractProjectItem> item, int role)
{
auto tItem = std::static_pointer_cast<TreeItem>(item);
auto ptr = tItem->parentItem().lock();
if (ptr) {
auto index = getIndexFromItem(tItem);
emit dataChanged(index, index);
emit dataChanged(index, index, QVector<int>() << role);
}
}
void ProjectItemModel::onItemUpdated(const QString &binId)
void ProjectItemModel::onItemUpdated(const QString &binId, int role)
{
std::shared_ptr<AbstractProjectItem> item = getItemByBinId(binId);
if (item) {
onItemUpdated(item);
onItemUpdated(item, role);
}
}
std::shared_ptr<ProjectClip> ProjectItemModel::getClipByBinID(const QString &binId)
......@@ -528,7 +528,7 @@ bool ProjectItemModel::requestAddBinClip(QString &id, const QDomElement &descrip
qDebug() << "/////////// added " << res;
if (res) {
int loadJob = pCore->jobManager()->startJob<LoadJob>({id}, {}, QString(), description);
pCore->jobManager()->startJob<ThumbJob>({id}, {loadJob}, QString(), 150, -1, true);
pCore->jobManager()->startJob<ThumbJob>({id}, {loadJob}, QString(), 150, 0, true);
pCore->jobManager()->startJob<AudioThumbJob>({id}, {loadJob}, QString());
}
return res;
......
......@@ -198,8 +198,8 @@ protected:
public slots:
/** @brief An item in the list was modified, notify */
void onItemUpdated(std::shared_ptr<AbstractProjectItem> item);
void onItemUpdated(const QString &binId);
void onItemUpdated(std::shared_ptr<AbstractProjectItem> item, int role);
void onItemUpdated(const QString &binId, int role);
/** @brief Check whether a given id is currently used or not*/
bool isIdFree(const QString &id) const;
......
......@@ -138,7 +138,7 @@ void ProjectSubClip::setThumbnail(const QImage &img)
{
QPixmap thumb = roundedPixmap(QPixmap::fromImage(img));
m_thumbnail = QIcon(thumb);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectSubClip>(shared_from_this()));
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectSubClip>(shared_from_this()), AbstractProjectItem::DataThumbnail);
}
QPixmap ProjectSubClip::thumbnail(int width, int height)
......
......@@ -155,6 +155,8 @@ void Core::initGUI(const QUrl &Url)
}
m_projectManager = new ProjectManager(this);
// Job manger must be created before bin to correctly connect
m_jobManager.reset(new JobManager(this));
m_binWidget = new Bin(m_projectItemModel);
m_binController = std::make_shared<BinController>();
m_library = new LibraryWidget(m_projectManager);
......@@ -169,7 +171,6 @@ void Core::initGUI(const QUrl &Url)
connect(m_binController.get(), &BinController::abortAudioThumbs, m_binWidget, &Bin::abortAudioThumbs);
connect(m_binController.get(), &BinController::setDocumentNotes, m_projectManager, &ProjectManager::setDocumentNotes);
m_monitorManager = new MonitorManager(this);
m_jobManager.reset(new JobManager());
// Producer queue, creating MLT::Producers on request
/*
m_producerQueue = new ProducerQueue(m_binController);
......
......@@ -47,10 +47,10 @@ public:
STABILIZEJOB = 3,
TRANSCODEJOB = 4,
FILTERCLIPJOB = 5,
THUMBJOB = 5,
ANALYSECLIPJOB = 6,
LOADJOB = 7,
AUDIOTHUMBJOB = 8
THUMBJOB = 6,
ANALYSECLIPJOB = 7,
LOADJOB = 8,
AUDIOTHUMBJOB = 9
};
AbstractClipJob(JOBTYPE type, const QString &id, QObject *parent = nullptr);
virtual ~AbstractClipJob();
......
......@@ -237,6 +237,7 @@ bool AudioThumbJob::startJob()
if (m_binClip->audioChannels() == 0 || m_binClip->audioThumbCreated()) {
// nothing to do
m_done = true;
m_successful = true;
return true;
}
m_prod = m_binClip->originalProducer();
......
......@@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "jobmanager.h"
#include "bin/projectitemmodel.h"
#include "bin/abstractprojectitem.h"
#include "core.h"
#include "macros.hpp"
#include "undohelper.hpp"
......@@ -31,8 +32,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QThread>
int JobManager::m_currentId = 0;
JobManager::JobManager()
: QAbstractListModel()
JobManager::JobManager(QObject *parent)
: QAbstractListModel(parent)
, m_lock(QReadWriteLock::Recursive)
{
}
......@@ -113,11 +114,12 @@ void JobManager::updateJobCount()
int count = 0;
for (const auto &j : m_jobs) {
if (!j.second->m_future.isFinished() && !j.second->m_future.isCanceled()) {
for (int i = 0; i < j.second->m_future.future().resultCount(); ++i) {
count++;
/*for (int i = 0; i < j.second->m_future.future().resultCount(); ++i) {
if (j.second->m_future.future().isResultReadyAt(i)) {
count++;
}
}
}*/
}
}
// Set jobs count
......@@ -189,21 +191,27 @@ void JobManager::slotCancelJobs()
void JobManager::createJob(std::shared_ptr<Job_t> job, const std::vector<int> &parents)
{
qDebug() << "################### Createq JOB" << job->m_id;
qDebug() << "################### Created JOB" << job->m_id<<", TYPE: "<<job->m_type;
bool ok = false;
// wait for parents to finish
while (!ok) {
ok = true;
for (int p : parents) {
if (!m_jobs[p]->m_processed) {
ok = false;
break;
}
if (!m_jobs[p]->m_completionMutex.tryLock()) {
ok = false;
qDebug()<<"********\nWAITING FOR JOB COMPLETION MUTEX!!: "<<job->m_id<<" : "<<m_jobs[p]->m_id<<"="<<m_jobs[p]->m_type;
break;
} else {
qDebug()<<">>>>>>>>>>\nJOB COMPLETION MUTEX DONE: "<<job->m_id;
m_jobs[p]->m_completionMutex.unlock();
}
}
if (!ok) {
QThread::sleep(1);
QThread::msleep(10);
}
}
qDebug() << "################### Create JOB STARTING" << job->m_id;
......@@ -213,25 +221,30 @@ void JobManager::createJob(std::shared_ptr<Job_t> job, const std::vector<int> &p
auto binId = it.first;
connect(job->m_job[i].get(), &AbstractClipJob::jobProgress, [job, i, binId](int p) {
job->m_progress[i] = std::max(job->m_progress[i], p);
pCore->projectItemModel()->onItemUpdated(binId);
pCore->projectItemModel()->onItemUpdated(binId, AbstractProjectItem::JobProgress);
});
}
QWriteLocker locker(&m_lock);
job->m_actualFuture = QtConcurrent::mapped(job->m_job, AbstractClipJob::execute);
job->m_future.setFuture(job->m_actualFuture);
connect(&job->m_future, &QFutureWatcher<bool>::started, this, &JobManager::updateJobCount);
connect(&job->m_future, &QFutureWatcher<bool>::finished, [ this, id = job->m_id ]() { slotManageFinishedJob(id); });
connect(&job->m_future, &QFutureWatcher<bool>::canceled, [ this, id = job->m_id ]() { slotManageCanceledJob(id); });
connect(&job->m_future, &QFutureWatcher<bool>::started, this, &JobManager::updateJobCount);
connect(&job->m_future, &QFutureWatcher<bool>::finished, this, &JobManager::updateJobCount);
connect(&job->m_future, &QFutureWatcher<bool>::canceled, this, &JobManager::updateJobCount);
qDebug() << "################### Create JOB READY TO EXEC" << job->m_id<<", JOBS: "<<job->m_job.size();
//AbstractClipJob::execute(job->m_job.front());
job->m_actualFuture = QtConcurrent::mapped(job->m_job, AbstractClipJob::execute);
job->m_future.setFuture(job->m_actualFuture);
qDebug() << "################### Create JOB READY EXEC DONE" << job->m_id;
//connect(&job->m_future, &QFutureWatcher<bool>::finished, this, &JobManager::updateJobCount);
//connect(&job->m_future, &QFutureWatcher<bool>::canceled, this, &JobManager::updateJobCount);
// In the unlikely event that the job finished before the signal connection was made, we check manually for finish and cancel
if (job->m_future.isFinished()) {
/*if (job->m_future.isFinished()) {
emit job->m_future.finished();
slotManageFinishedJob(job->m_id);
}
if (job->m_future.isCanceled()) {
emit job->m_future.canceled();
}
slotManageCanceledJob(job->m_id);
}*/
}
void JobManager::slotManageCanceledJob(int id)
......@@ -243,7 +256,7 @@ void JobManager::slotManageCanceledJob(int id)
m_jobs[id]->m_completionMutex.unlock();
// send notification to refresh view
for (const auto &it : m_jobs[id]->m_indices) {
pCore->projectItemModel()->onItemUpdated(it.first);
pCore->projectItemModel()->onItemUpdated(it.first, AbstractProjectItem::JobStatus);
}
updateJobCount();
}
......@@ -253,10 +266,10 @@ void JobManager::slotManageFinishedJob(int id)
QWriteLocker locker(&m_lock);
Q_ASSERT(m_jobs.count(id) > 0);
if (m_jobs[id]->m_processed) return;
m_jobs[id]->m_processed = true;
// send notification to refresh view
for (const auto &it : m_jobs[id]->m_indices) {
pCore->projectItemModel()->onItemUpdated(it.first);
pCore->projectItemModel()->onItemUpdated(it.first, AbstractProjectItem::JobStatus);
}
bool ok = true;
for (bool res : m_jobs[id]->m_future.future()) {
......@@ -268,6 +281,7 @@ void JobManager::slotManageFinishedJob(int id)
for (const auto &j : m_jobs[id]->m_job) {
ok = ok && j->commitResult(undo, redo);
}
m_jobs[id]->m_processed = true;
if (!ok) {
qDebug() << "ERROR: Job " << id << " failed";
m_jobs[id]->m_failed = true;
......
......@@ -71,7 +71,7 @@ class JobManager : public QAbstractListModel, public enable_shared_from_this_vir
Q_OBJECT
public:
explicit JobManager();
explicit JobManager(QObject *parent);
virtual ~JobManager();
/** @brief Start a job
......
......@@ -58,6 +58,7 @@ const QString ThumbJob::getDescription() const
bool ThumbJob::startJob()
{
qDebug()<<"&&&&&&&&&&&&&&&&&& THUMB JOB STARTING: "<<m_clipId<<"\n\n&&&&&&&&&&&&&&&&&&&&&&&";
if (m_done) {
return true;
}
......@@ -70,6 +71,7 @@ bool ThumbJob::startJob()
}
if (m_binClip->clipType() == ClipType::Audio) {
// Don't create thumbnail for audio clips
m_done = true;
return true;
}
m_prod = m_binClip->thumbProducer();
......@@ -93,10 +95,12 @@ bool ThumbJob::startJob()
QScopedPointer<Mlt::Frame> frame(m_prod->get_frame());
frame->set("deinterlace_method", "onefield");
frame->set("top_field_first", -1);
frame->set("rescale.interp", "nearest");
if ((frame != nullptr) && frame->is_valid()) {
m_result = KThumb::getFrame(frame.data(), m_fullWidth, m_imageHeight, true);
m_done = true;
}
qDebug()<<"&&&&&&&&&&&&&&&&&& THUMB JOB DONE: "<<m_clipId<<"\n\n&&&&&&&&&&&&&&&&&&&&&&&";
return m_done;
}
......@@ -108,9 +112,7 @@ bool ThumbJob::commitResult(Fun &undo, Fun &redo)
return false;
}
m_resultConsumed = true;
if (!m_inCache) {
ThumbnailCache::get()->storeThumbnail(m_binClip->clipId(), m_frameNumber, m_result, m_persistent);
}
qDebug()<<"&&&&&&&&&&&&&&&&&& THUMB JOB RESULTS COMMITTED: "<<m_clipId<<"\n\n&&&&&&&&&&&&&&&&&&&&&&&";
// TODO a refactor of ProjectClip and ProjectSubClip should make that possible without branching (both classes implement setThumbnail)
bool ok = false;
......@@ -152,5 +154,8 @@ bool ThumbJob::commitResult(Fun &undo, Fun &redo)
UPDATE_UNDO_REDO_NOLOCK(operation, reverse, undo, redo);
}
}
if (!m_inCache) {
ThumbnailCache::get()->storeThumbnail(m_binClip->clipId(), m_frameNumber, m_result, m_persistent);
}
return 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