Fix a few bugs in timeline preview, add support for undo (only 1 step supported)

Ref: T1949
parent 91b04310
......@@ -82,7 +82,8 @@ KdenliveDoc::KdenliveDoc(const QUrl &url, const QUrl &projectFolder, QUndoGroup
m_notesWidget(notes->widget()),
m_commandStack(new QUndoStack(undoGroup)),
m_modified(false),
m_projectFolder(projectFolder)
m_projectFolder(projectFolder),
m_undoPreviewIndex(-1)
{
// init m_profile struct
m_profile.frame_rate_num = 0;
......@@ -98,7 +99,7 @@ KdenliveDoc::KdenliveDoc(const QUrl &url, const QUrl &projectFolder, QUndoGroup
m_clipManager = new ClipManager(this);
connect(m_clipManager, SIGNAL(displayMessage(QString,int)), parent, SLOT(slotGotProgressInfo(QString,int)));
bool success = false;
connect(m_commandStack, SIGNAL(indexChanged(int)), this, SLOT(slotModified()));
connect(m_commandStack, SIGNAL(indexChanged(int)), this, SLOT(slotModified(int)));
connect(m_render, SIGNAL(setDocumentNotes(QString)), this, SLOT(slotSetDocumentNotes(QString)));
connect(pCore->producerQueue(), &ProducerQueue::switchProfile, this, &KdenliveDoc::switchProfile);
//connect(m_commandStack, SIGNAL(cleanChanged(bool)), this, SLOT(setModified(bool)));
......@@ -844,9 +845,15 @@ void KdenliveDoc::setUrl(const QUrl &url)
m_url = url;
}
void KdenliveDoc::slotModified()
void KdenliveDoc::slotModified(int ix)
{
setModified(m_commandStack->isClean() == false);
if (m_undoPreviewIndex != -1 && ix == m_undoPreviewIndex - 1) {
restoreTimelinePreviews();
} else if (ix < m_undoPreviewIndex - 1) {
// Restore preview files if any
m_undoPreviewIndex = -1;
}
}
void KdenliveDoc::setModified(bool mod)
......@@ -1605,13 +1612,47 @@ void KdenliveDoc::doAddAction(const QString &name, QAction *a)
void KdenliveDoc::invalidatePreviews(QList <int> chunks)
{
QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
bool redo = true;
if (m_commandStack->index() > m_undoPreviewIndex) {
m_undoPreviewIndex = m_commandStack->index();
} else {
redo = false;
}
m_undoChunks = chunks;
// Clear all previous undo files
if (redo && dir.cd("undo")) {
dir.removeRecursively();
dir.cdUp();
}
dir.mkdir("undo");
QString documentId = m_documentProperties.value(QStringLiteral("documentid"));
QString ext = m_documentProperties.value(QStringLiteral("previewextension"));
foreach(int i, chunks) {
QFile::remove(dir.absoluteFilePath(documentId + QString("-%1.%2").arg(i).arg(KdenliveSettings::tl_extension())));
QString current = documentId + QString("-%1.%2").arg(i).arg(ext);
if (redo)
dir.rename(current, "undo/" + current);
else
dir.remove(current);
}
setModified(true);
}
void KdenliveDoc::restoreTimelinePreviews()
{
QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
QString documentId = m_documentProperties.value(QStringLiteral("documentid"));
QString ext = m_documentProperties.value(QStringLiteral("previewextension"));
foreach(int i, m_undoChunks) {
QString current = documentId + QString("-%1.%2").arg(i).arg(ext);
dir.remove(current);
dir.rename("undo/" + current, current);
}
dir.rmdir("undo");
emit reloadChunks(m_undoChunks);
m_undoPreviewIndex = -1;
m_undoChunks.clear();
}
void KdenliveDoc::previewProgress(int p)
{
pCore->window()->setPreviewProgress(p);
......
......@@ -185,6 +185,8 @@ private:
/** @brief The project folder, used to store project files (titles, effects...). */
QUrl m_projectFolder;
int m_undoPreviewIndex;
QList <int> m_undoChunks;
QMap <QString, QString> m_documentProperties;
QMap <QString, QString> m_documentMetadata;
......@@ -203,6 +205,8 @@ private:
void loadDocumentProperties();
/** @brief update document properties to reflect a change in the current profile */
void updateProjectProfile(bool reloadProducers = false);
/** @brief Undo stack changed, restore timeline preview files if any*/
void restoreTimelinePreviews();
public slots:
void slotCreateTextTemplateClip(const QString &group, const QString &groupId, QUrl path);
......@@ -221,7 +225,7 @@ private slots:
void slotClipModified(const QString &path);
void slotClipMissing(const QString &path);
void slotProcessModifiedClips();
void slotModified();
void slotModified(int ix);
void slotSetDocumentNotes(const QString &notes);
void switchProfile(MltVideoProfile profile, const QString &id, const QDomElement &xml);
void slotSwitchProfile();
......@@ -244,6 +248,9 @@ signals:
void reloadEffects();
/** @brief Fps was changed, update timeline */
void updateFps(bool changed);
/** @brief Some timeline preview chunks restored, reload them */
void reloadChunks(QList <int> chunks);
};
#endif
......
......@@ -222,20 +222,6 @@
<default>false</default>
</entry>
<entry name="tl_profile" type="UInt">
<label>default timeline preview encoding profile.</label>
<default>0</default>
</entry>
<entry name="tl_parameters" type="String">
<label>Default timeline preview format.</label>
<default></default>
</entry>
<entry name="tl_extension" type="String">
<label>Default timeline preview file extension.</label>
<default></default>
</entry>
</group>
<group name="sdl">
......
......@@ -690,17 +690,6 @@ MainWindow::MainWindow(const QString &MltPath, const QUrl &Url, const QString &
KdenliveSettings::setV4l_extension(data.section(';', 1, 1));
}
}
if (KdenliveSettings::tl_parameters().isEmpty() || KdenliveSettings::tl_extension().isEmpty()) {
KConfigGroup group(&conf, "timelinepreview");
QMap< QString, QString > values = group.entryMap();
QMapIterator<QString, QString> i(values);
if (i.hasNext()) {
i.next();
QString data = i.value();
KdenliveSettings::setTl_parameters(data.section(';', 0, 0));
KdenliveSettings::setTl_extension(data.section(';', 1, 1));
}
}
if (KdenliveSettings::grab_parameters().isEmpty() || KdenliveSettings::grab_extension().isEmpty()) {
KConfigGroup group(&conf, "screengrab");
QMap< QString, QString > values = group.entryMap();
......
......@@ -510,7 +510,7 @@ void CustomRuler::activateZone()
update();
}
void CustomRuler::updatePreview(int frame, bool rendered)
void CustomRuler::updatePreview(int frame, bool rendered, bool refresh)
{
if (rendered) {
m_renderingPreviews << frame;
......@@ -519,7 +519,8 @@ void CustomRuler::updatePreview(int frame, bool rendered)
m_renderingPreviews.removeAll(frame);
m_dirtyRenderingPreviews << frame;
}
update(frame * m_factor - offset(), MAX_HEIGHT - 3, KdenliveSettings::timelinechunks() * m_factor + 1, 3);
if (refresh)
update(frame * m_factor - offset(), MAX_HEIGHT - 3, KdenliveSettings::timelinechunks() * m_factor + 1, 3);
}
const QStringList CustomRuler::previewChunks() const
......
......@@ -50,7 +50,7 @@ public:
void updateProjectFps(const Timecode &t);
void updateFrameSize();
void activateZone();
void updatePreview(int frame, bool rendered = true);
void updatePreview(int frame, bool rendered = true, bool refresh = true);
/** @brief Returns a list of rendered timeline preview chunks */
const QStringList previewChunks() const;
/** @brief Returns a list of dirty timeline preview chunks (that need to be generated) */
......
......@@ -144,9 +144,13 @@ Timeline::Timeline(KdenliveDoc *doc, const QList<QAction *> &actions, const QLis
connect(m_trackview->horizontalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(slotUpdateVerticalScroll(int,int)));
connect(m_trackview, SIGNAL(mousePosition(int)), this, SIGNAL(mousePosition(int)));
connect(m_doc->renderer(), &Render::previewRender, this, &Timeline::gotPreviewRender);
connect(m_doc, &KdenliveDoc::reloadChunks, this, &Timeline::slotReloadChunks);
m_previewTimer.setSingleShot(true);
m_previewTimer.setInterval(3000);
connect(&m_previewTimer, &QTimer::timeout, this, &Timeline::startPreviewRender);
m_previewGatherTimer.setSingleShot(true);
m_previewGatherTimer.setInterval(200);
connect(&m_previewGatherTimer, &QTimer::timeout, this, &Timeline::slotProcessDirtyChunks);
}
Timeline::~Timeline()
......@@ -1759,11 +1763,12 @@ void Timeline::gotPreviewRender(int frame, const QString &file, int progress)
if (trackPlaylist.is_blank_at(frame)) {
Mlt::Producer prod(*m_tractor->profile(), 0, file.toUtf8().constData());
if (prod.is_valid()) {
m_ruler->updatePreview(frame);
m_ruler->updatePreview(frame, true, true);
prod.set("mlt_service", "avformat-novalidate");
trackPlaylist.insert_at(frame, &prod, 1);
}
}
trackPlaylist.consolidate_blanks();
m_tractor->unlock();
m_doc->previewProgress(progress);
m_doc->setModified(true);
......@@ -1780,7 +1785,7 @@ void Timeline::addPreviewRange(bool add)
frames << i * chunkSize;
}
m_ruler->addChunks(frames, add);
if (KdenliveSettings::autopreview())
if (add && KdenliveSettings::autopreview())
m_previewTimer.start();
}
......@@ -1841,9 +1846,15 @@ void Timeline::invalidatePreview(int startFrame, int endFrame)
delete prod;
m_ruler->updatePreview(i * chunkSize, false);
}
m_ruler->update();
trackPlaylist.consolidate_blanks();
m_tractor->unlock();
m_doc->invalidatePreviews(list);
m_previewGatherTimer.start();
}
void Timeline::slotProcessDirtyChunks()
{
m_doc->invalidatePreviews(m_ruler->getDirtyChunks());
if (KdenliveSettings::autopreview())
m_previewTimer.start();
}
......@@ -1853,6 +1864,7 @@ void Timeline::loadPreviewRender()
QString documentId = m_doc->getDocumentProperty(QStringLiteral("documentid"));
QString chunks = m_doc->getDocumentProperty(QStringLiteral("previewchunks"));
QString dirty = m_doc->getDocumentProperty(QStringLiteral("dirtypreviewchunks"));
QString ext = m_doc->getDocumentProperty(QStringLiteral("previewextension"));
if (!chunks.isEmpty() || !dirty.isEmpty()) {
if (!m_hasOverlayTrack) {
// Create overlay track
......@@ -1863,12 +1875,12 @@ void Timeline::loadPreviewRender()
m_tractor->unlock();
m_hasOverlayTrack = true;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) );
QStringList previewChunks = chunks.split(",", QString::SkipEmptyParts);
QStringList dirtyChunks = dirty.split(",", QString::SkipEmptyParts);
foreach(const QString frame, previewChunks) {
int pos = frame.toInt();
const QString fileName = dir.absoluteFilePath(documentId + QString("-%1.%2").arg(pos).arg(KdenliveSettings::tl_extension()));
const QString fileName = dir.absoluteFilePath(documentId + QString("-%1.%2").arg(pos).arg(ext));
if (QFile::exists(fileName)) {
gotPreviewRender(pos, fileName, 1000);
} else dirtyChunks << frame;
......@@ -1877,6 +1889,7 @@ void Timeline::loadPreviewRender()
foreach(const QString i, dirtyChunks) {
m_ruler->updatePreview(i.toInt(), false);
}
m_ruler->update();
}
}
}
......@@ -1893,3 +1906,34 @@ void Timeline::updatePreviewSettings(const QString &profile)
m_doc->setDocumentProperty(QStringLiteral("previewextension"), ext);
}
}
void Timeline::slotReloadChunks(QList <int> chunks)
{
bool timer = false;
if (m_previewTimer.isActive()) {
m_previewTimer.stop();
timer = true;
}
QString documentId = m_doc->getDocumentProperty(QStringLiteral("documentid"));
QString ext = m_doc->getDocumentProperty(QStringLiteral("previewextension"));
QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
Mlt::Producer *overlayTrack = m_tractor->track(tracksCount());
m_tractor->lock();
Mlt::Playlist trackPlaylist((mlt_playlist) overlayTrack->get_service());
delete overlayTrack;
foreach(int ix, chunks) {
if (trackPlaylist.is_blank_at(ix)) {
const QString fileName = dir.absoluteFilePath(documentId + QString("-%1.%2").arg(ix).arg(ext));
Mlt::Producer prod(*m_tractor->profile(), 0, fileName.toUtf8().constData());
if (prod.is_valid()) {
m_ruler->updatePreview(ix, true, true);
prod.set("mlt_service", "avformat-novalidate");
trackPlaylist.insert_at(ix, &prod, 1);
}
}
}
trackPlaylist.consolidate_blanks();
m_tractor->unlock();
if (timer)
m_previewTimer.start();
}
......@@ -209,6 +209,8 @@ private:
int m_verticalZoom;
QString m_documentErrors;
QList <QAction *> m_trackActions;
/** @brief sometimes grouped commands quickly send invalidate commands, so wait a little bit before processing*/
QTimer m_previewGatherTimer;
QTimer m_previewTimer;
void adjustTrackHeaders();
......@@ -251,6 +253,8 @@ private slots:
void slotEnableZone(bool enable);
void gotPreviewRender(int frame, const QString &file, int progress);
void invalidatePreview(int startFrame, int endFrame);
void slotReloadChunks(QList <int> chunks);
void slotProcessDirtyChunks();
signals:
void mousePosition(int);
......
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