Improve zone invalidate on effect change, save and reload timeline previews

parent 2e3d964b
......@@ -1607,7 +1607,24 @@ void KdenliveDoc::doAddAction(const QString &name, QAction *a)
pCore->window()->actionCollection()->addAction(name, a);
}
void KdenliveDoc::previewRender()
void KdenliveDoc::loadPreviewRender()
{
QString documentId = m_documentProperties.value(QStringLiteral("documentid"));
QString chunks = m_documentProperties.value(QStringLiteral("previewchunks"));
if (!chunks.isEmpty()) {
QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
QStringList previewChunks = chunks.split(",");
foreach(const QString frame, previewChunks) {
int pos = frame.toInt() / KdenliveSettings::timelinechunks();
const QString fileName = dir.absoluteFilePath(documentId + QString("-%1.mp4").arg(pos));
if (QFile::exists(fileName)) {
emit previewRender(pos * KdenliveSettings::timelinechunks(), fileName, 100);
}
}
}
}
void KdenliveDoc::doPreviewRender()
{
QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
QString documentId = m_documentProperties.value(QStringLiteral("documentid"));
......
......@@ -159,8 +159,10 @@ public:
/** @brief Returns true if the profile file has changed. */
bool profileChanged(const QString &profile) const;
void doAddAction(const QString &name, QAction *a);
void previewRender();
void doPreviewRender();
void invalidatePreviews(QList <int> chunks);
/** @brief load existing timeline previews */
void loadPreviewRender();
private:
QUrl m_url;
......@@ -244,6 +246,8 @@ signals:
void reloadEffects();
/** @brief Fps was changed, update timeline */
void updateFps(bool changed);
/** @brief A timeline preview render is available */
void previewRender(int frame, const QString &file, int progress);
};
#endif
......
......@@ -163,6 +163,10 @@
<label>Default interpolation for keyframes.</label>
<default>1</default>
</entry>
<entry name="timelinechunks" type="Int">
<label>Default size of video chunks for timeline preview.</label>
<default>25</default>
</entry>
<entry name="videothumbnails" type="Bool">
<label>Display video thumbnails in timeline.</label>
......
......@@ -2180,7 +2180,7 @@ void MainWindow::slotLiftZone()
void MainWindow::slotPreviewRender()
{
if (pCore->projectManager()->current()) {
pCore->projectManager()->current()->previewRender();
pCore->projectManager()->current()->doPreviewRender();
}
}
......
......@@ -1614,9 +1614,9 @@ void Render::previewRendering(QPoint zone, const QString &cacheDir, const QStrin
}
QDir dir(cacheDir);
dir.mkpath(QStringLiteral("."));
// Data is rendered in 100 frames chunks
int startChunk = zone.x() / 100;
int endChunk = rintl(zone.y() / 100);
// Data is rendered in x frames chunks
int startChunk = zone.x() / KdenliveSettings::timelinechunks();
int endChunk = rintl(zone.y() / KdenliveSettings::timelinechunks());
// Save temporary scenelist
QString sceneListFile = dir.absoluteFilePath(documentId + ".mlt");
Mlt::Consumer xmlConsumer(*m_qmlView->profile(), "xml", sceneListFile.toUtf8().constData());
......@@ -1635,6 +1635,7 @@ void Render::previewRendering(QPoint zone, const QString &cacheDir, const QStrin
void Render::doPreviewRender(int start, int end, QDir folder, QString id, QString scene)
{
int progress;
int chunkSize = KdenliveSettings::timelinechunks();
for (int i = start; i <= end; ++i) {
if (m_abortPreview)
break;
......@@ -1646,14 +1647,14 @@ void Render::doPreviewRender(int start, int end, QDir folder, QString id, QStrin
}
if (folder.exists(fileName)) {
// This chunk already exists
emit previewRender(i * 100, folder.absoluteFilePath(fileName), progress);
emit previewRender(i * chunkSize, folder.absoluteFilePath(fileName), progress);
continue;
}
// Build rendering process
QStringList args;
args << scene;
args << "in=" + QString::number(i * 100);
args << "out=" + QString::number(i * 100 + 99);
args << "in=" + QString::number(i * chunkSize);
args << "out=" + QString::number(i * chunkSize + chunkSize - 1);
args << "-consumer" << "avformat:" + folder.absoluteFilePath(fileName);
args << "an=1";
int result = QProcess::execute(KdenliveSettings::rendererpath(), args);
......@@ -1661,7 +1662,7 @@ void Render::doPreviewRender(int start, int end, QDir folder, QString id, QStrin
// Something is wrong, abort
break;
}
emit previewRender(i * 100, folder.absoluteFilePath(fileName), progress);
emit previewRender(i * chunkSize, folder.absoluteFilePath(fileName), progress);
}
QFile::remove(scene);
m_abortPreview = false;
......
......@@ -477,7 +477,7 @@ void CustomRuler::paintEvent(QPaintEvent *e)
// draw Rendering preview zones
QColor preview(Qt::green);
foreach(int frame, m_renderingPreviews) {
QRect rec(frame * m_factor - m_offset, MAX_HEIGHT - 2, 99 * m_factor, 2);
QRect rec(frame * m_factor - m_offset, MAX_HEIGHT - 2, KdenliveSettings::timelinechunks() * m_factor, 2);
p.fillRect(rec, preview);
}
......@@ -494,7 +494,6 @@ void CustomRuler::paintEvent(QPaintEvent *e)
if (m_headPosition != SEEK_INACTIVE) {
p.fillRect(m_headPosition * m_factor - m_offset - 1, BIG_MARK_X + 1, 3, MAX_HEIGHT - BIG_MARK_X - 1, palette().linkVisited());
}
}
void CustomRuler::activateZone()
......@@ -509,5 +508,15 @@ void CustomRuler::updatePreview(int frame, bool rendered)
m_renderingPreviews << frame;
else
m_renderingPreviews.removeAll(frame);
update(frame * m_factor - offset(), MAX_HEIGHT - 2, (99) * m_factor, 2);
update(frame * m_factor - offset(), MAX_HEIGHT - 2, KdenliveSettings::timelinechunks() * m_factor, 2);
}
const QString CustomRuler::previewChunks() const
{
QStringList result;
foreach(int frame, m_renderingPreviews) {
result << QString::number(frame);
}
return result.join(QStringLiteral(","));
}
......@@ -51,6 +51,8 @@ public:
void updateFrameSize();
void activateZone();
void updatePreview(int frame, bool rendered = true);
/** @brief Returns a list of rendered timeline preview chunks */
const QString previewChunks() const;
protected:
void paintEvent(QPaintEvent * /*e*/);
......
......@@ -1499,7 +1499,7 @@ void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event)
item->insertKeyframe(item->getEffectAtIndex(item->selectedEffectIndex()), keyFramePos.frames(m_document->fps()), val);
//QString next = item->keyframes(item->selectedEffectIndex());
QDomElement newEffect = item->selectedEffect().cloneNode().toElement();
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false);
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, true);
m_commandStack->push(command);
updateEffect(item->track(), item->startPos(), item->selectedEffect());
emit clipItemSelected(item, item->selectedEffectIndex());
......@@ -1653,7 +1653,7 @@ void CustomTrackView::slotAttachKeyframeToEnd(bool attach)
QDomElement oldEffect = item->selectedEffect().cloneNode().toElement();
item->attachKeyframeToEnd(item->getEffectAtIndex(item->selectedEffectIndex()), attach);
QDomElement newEffect = item->selectedEffect().cloneNode().toElement();
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false);
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, false);
m_commandStack->push(command);
updateEffect(item->track(), item->startPos(), item->selectedEffect());
emit clipItemSelected(item, item->selectedEffectIndex());
......@@ -1666,7 +1666,7 @@ void CustomTrackView::slotEditKeyframeType(QAction *action)
QDomElement oldEffect = item->selectedEffect().cloneNode().toElement();
item->editKeyframeType(item->getEffectAtIndex(item->selectedEffectIndex()), type);
QDomElement newEffect = item->selectedEffect().cloneNode().toElement();
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false);
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, false);
m_commandStack->push(command);
updateEffect(item->track(), item->startPos(), item->selectedEffect());
emit clipItemSelected(item, item->selectedEffectIndex());
......@@ -2408,7 +2408,7 @@ void CustomTrackView::slotDeleteEffect(ClipItem *clip, int track, QDomElement ef
}
}
void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedEffect, bool updateEffectStack, bool replaceEffect)
void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedEffect, bool updateEffectStack, bool replaceEffect, bool refreshMonitor)
{
if (insertedEffect.isNull()) {
//qDebug()<<"// Trying to add null effect";
......@@ -2430,7 +2430,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
emit displayMessage(i18n("Problem editing effect"), ErrorMessage);
}
m_timeline->setTrackEffect(track, ix, effect);
if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio"))
if (refreshMonitor && effect.attribute(QStringLiteral("type")) != QLatin1String("audio"))
monitorRefresh(true);
emit updateTrackEffectState(track);
return;
......@@ -2477,7 +2477,7 @@ void CustomTrackView::updateEffect(int track, GenTime pos, QDomElement insertedE
bool success = m_timeline->track(clip->track())->editEffect(clip->startPos().seconds(), effectParams, replaceEffect);
if (success) {
clip->updateEffect(effect);
if (clip->hasVisibleVideo() && effect.attribute(QStringLiteral("type")) != QLatin1String("audio"))
if (refreshMonitor && clip->hasVisibleVideo() && effect.attribute(QStringLiteral("type")) != QLatin1String("audio"))
monitorRefresh(clip->info(), true);
if (updateEffectStack && clip->isSelected()) {
emit clipItemSelected(clip);
......@@ -2605,7 +2605,7 @@ void CustomTrackView::slotChangeEffectState(ClipItem *clip, int track, QList <in
speedEffectIndexes << effectIndexes.at(i);
QDomElement newEffect = effect.cloneNode().toElement();
newEffect.setAttribute(QStringLiteral("disable"), (int) disable);
EditEffectCommand *editcommand = new EditEffectCommand(this, clip->track(), clip->startPos(), effect, newEffect, effectIndexes.at(i), false, true);
EditEffectCommand *editcommand = new EditEffectCommand(this, clip->track(), clip->startPos(), effect, newEffect, effectIndexes.at(i), false, true, true);
m_commandStack->push(editcommand);
}
}
......@@ -2630,8 +2630,8 @@ void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int track, QList
void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, int track, QDomElement oldeffect, QDomElement effect, int ix, bool refreshEffectStack)
{
EditEffectCommand *command;
if (clip) command = new EditEffectCommand(this, clip->track(), clip->startPos(), oldeffect.cloneNode().toElement(), effect.cloneNode().toElement(), ix, refreshEffectStack, true);
else command = new EditEffectCommand(this, track, GenTime(-1), oldeffect.cloneNode().toElement(), effect.cloneNode().toElement(), ix, refreshEffectStack, true);
if (clip) command = new EditEffectCommand(this, clip->track(), clip->startPos(), oldeffect.cloneNode().toElement(), effect.cloneNode().toElement(), ix, refreshEffectStack, true, true);
else command = new EditEffectCommand(this, track, GenTime(-1), oldeffect.cloneNode().toElement(), effect.cloneNode().toElement(), ix, refreshEffectStack, true, true);
m_commandStack->push(command);
}
......@@ -2640,7 +2640,7 @@ void CustomTrackView::slotUpdateClipRegion(ClipItem *clip, int ix, QString regio
QDomElement effect = clip->getEffectAtIndex(ix);
QDomElement oldeffect = effect.cloneNode().toElement();
effect.setAttribute(QStringLiteral("region"), region);
EditEffectCommand *command = new EditEffectCommand(this, clip->track(), clip->startPos(), oldeffect, effect, ix, true, true);
EditEffectCommand *command = new EditEffectCommand(this, clip->track(), clip->startPos(), oldeffect, effect, ix, true, true, true);
m_commandStack->push(command);
}
......@@ -4836,7 +4836,7 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event)
QDomElement newEffect = item->selectedEffect().cloneNode().toElement();
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false);
EditEffectCommand *command = new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, true);
m_commandStack->push(command);
updateEffect(item->track(), item->startPos(), item->selectedEffect());
emit clipItemSelected(item);
......@@ -8363,7 +8363,7 @@ void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoComma
if (!effects.isEmpty()) {
QMap<int, QDomElement>::const_iterator i = effects.constBegin();
while (i != effects.constEnd()) {
new EditEffectCommand(this, item->track(), item->startPos(), i.value(), item->effect(i.key()), i.value().attribute(QStringLiteral("kdenlive_ix")).toInt(), true, true, command);
new EditEffectCommand(this, item->track(), item->startPos(), i.value(), item->effect(i.key()), i.value().attribute(QStringLiteral("kdenlive_ix")).toInt(), true, true, false, command);
++i;
}
}
......@@ -8390,7 +8390,7 @@ void CustomTrackView::slotGotFilterJobResults(const QString &/*id*/, int startPo
EffectsList::setParameter(newEffect, i.key(), i.value());
++i;
}
EditEffectCommand *command = new EditEffectCommand(this, clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true, true);
EditEffectCommand *command = new EditEffectCommand(this, clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true, true, true);
m_commandStack->push(command);
emit clipItemSelected(clip);
}
......
......@@ -90,7 +90,7 @@ public:
void slotAddGroupEffect(QDomElement effect, AbstractGroupItem *group, AbstractClipItem *dropTarget = NULL);
void addEffect(int track, GenTime pos, QDomElement effect);
void deleteEffect(int track, const GenTime &pos, const QDomElement &effect);
void updateEffect(int track, GenTime pos, QDomElement insertedEffect, bool refreshEffectStack = false, bool replaceEffect = false);
void updateEffect(int track, GenTime pos, QDomElement insertedEffect, bool refreshEffectStack = false, bool replaceEffect = false, bool refreshMonitor = true);
/** @brief Enable / disable a list of effects */
void updateEffectState(int track, GenTime pos, QList <int> effectIndexes, bool disable, bool updateEffectStack);
void moveEffect(int track, const GenTime &pos, const QList<int> &oldPos, const QList<int> &newPos);
......
......@@ -143,6 +143,7 @@ Timeline::Timeline(KdenliveDoc *doc, const QList<QAction *> &actions, bool *ok,
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::previewRender, this, &Timeline::gotPreviewRender);
}
Timeline::~Timeline()
......@@ -163,6 +164,7 @@ void Timeline::loadTimeline()
m_trackview->slotSelectTrack(m_trackview->getNextVideoTrack(1));
slotChangeZoom(m_doc->zoom().x(), m_doc->zoom().y());
slotSetZone(m_doc->zone(), false);
m_doc->loadPreviewRender();
}
QMap <QString, QString> Timeline::documentProperties()
......@@ -170,6 +172,7 @@ QMap <QString, QString> Timeline::documentProperties()
QMap <QString, QString> props = m_doc->documentProperties();
props.insert(QStringLiteral("audiotargettrack"), QString::number(audioTarget));
props.insert(QStringLiteral("videotargettrack"), QString::number(videoTarget));
props.insert(QStringLiteral("previewchunks"), m_ruler->previewChunks());
return props;
}
......@@ -1732,7 +1735,6 @@ void Timeline::slotEnableZone(bool enable)
void Timeline::gotPreviewRender(int frame, const QString &file, int progress)
{
m_ruler->updatePreview(frame);
if (!m_hasOverlayTrack) {
// Create overlay track
Mlt::Playlist overlay(*m_tractor->profile());
......@@ -1748,8 +1750,11 @@ void Timeline::gotPreviewRender(int frame, const QString &file, int progress)
delete overlayTrack;
if (trackPlaylist.is_blank_at(frame)) {
Mlt::Producer prod(*m_tractor->profile(), 0, file.toUtf8().constData());
prod.set("mlt_service", "avformat-novalidate");
trackPlaylist.insert_at(frame, &prod, 1);
if (prod.is_valid()) {
m_ruler->updatePreview(frame);
prod.set("mlt_service", "avformat-novalidate");
trackPlaylist.insert_at(frame, &prod, 1);
}
}
m_tractor->unlock();
m_doc->progressInfo(i18n("Rendering preview"), progress);
......@@ -1759,30 +1764,31 @@ void Timeline::gotPreviewRender(int frame, const QString &file, int progress)
void Timeline::invalidateRange(ItemInfo info)
{
if (info.isValid())
invalidatePreview(info.startPos.frames(m_doc->fps()), (info.endPos - info.startPos).frames(m_doc->fps()));
invalidatePreview(info.startPos.frames(m_doc->fps()), info.endPos.frames(m_doc->fps()));
else
invalidatePreview(0, m_trackview->duration());
}
void Timeline::invalidatePreview(int startFrame, int length)
void Timeline::invalidatePreview(int startFrame, int endFrame)
{
if (!m_hasOverlayTrack)
return;
int start = startFrame / 100;
int end = lrintf((startFrame + length) / 100);
int chunkSize = KdenliveSettings::timelinechunks();
int start = startFrame / chunkSize;
int end = lrintf(endFrame / chunkSize);
Mlt::Producer *overlayTrack = m_tractor->track(tracksCount());
m_tractor->lock();
Mlt::Playlist trackPlaylist((mlt_playlist) overlayTrack->get_service());
delete overlayTrack;
QList <int> list;
for (int i = start; i <=end; i++) {
int ix = trackPlaylist.get_clip_index_at(100 * i);
int ix = trackPlaylist.get_clip_index_at(chunkSize * i);
if (trackPlaylist.is_blank(ix))
continue;
list << i;
Mlt::Producer *prod = trackPlaylist.replace_with_blank(ix);
delete prod;
m_ruler->updatePreview(i * 100, false);
m_ruler->updatePreview(i * chunkSize, false);
}
trackPlaylist.consolidate_blanks();
m_tractor->unlock();
......
......@@ -238,7 +238,7 @@ private slots:
/** @brief Toggle use of timeline zone for editing.*/
void slotEnableZone(bool enable);
void gotPreviewRender(int frame, const QString &file, int progress);
void invalidatePreview(int startFrame, int length);
void invalidatePreview(int startFrame, int endFrame);
signals:
void mousePosition(int);
......
......@@ -262,7 +262,7 @@ void ConfigTracksCommand::redo()
if (m_oldState != m_newState) m_timeline->updateTrackState(m_ix, m_newState);
}
EditEffectCommand::EditEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, int stackPos, bool refreshEffectStack, bool doIt, QUndoCommand *parent) :
EditEffectCommand::EditEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, int stackPos, bool refreshEffectStack, bool doIt, bool refreshMonitor, QUndoCommand *parent) :
QUndoCommand(parent),
m_view(view),
m_track(track),
......@@ -272,7 +272,8 @@ EditEffectCommand::EditEffectCommand(CustomTrackView *view, const int track, con
m_stackPos(stackPos),
m_doIt(doIt),
m_refreshEffectStack(refreshEffectStack),
m_replaceEffect(false)
m_replaceEffect(false),
m_refreshMonitor(refreshMonitor)
{
QString effectName;
QDomElement namenode = effect.firstChildElement(QStringLiteral("name"));
......@@ -312,13 +313,13 @@ bool EditEffectCommand::mergeWith(const QUndoCommand * other)
// virtual
void EditEffectCommand::undo()
{
m_view->updateEffect(m_track, m_pos, m_oldeffect, true, m_replaceEffect);
m_view->updateEffect(m_track, m_pos, m_oldeffect, true, m_replaceEffect, m_refreshMonitor);
}
// virtual
void EditEffectCommand::redo()
{
if (m_doIt) {
m_view->updateEffect(m_track, m_pos, m_effect, m_refreshEffectStack, m_replaceEffect);
m_view->updateEffect(m_track, m_pos, m_effect, m_refreshEffectStack, m_replaceEffect, m_refreshMonitor);
}
m_doIt = true;
m_refreshEffectStack = true;
......
......@@ -168,7 +168,7 @@ private:
class EditEffectCommand : public QUndoCommand
{
public:
EditEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, int stackPos, bool refreshEffectStack, bool doIt, QUndoCommand *parent = 0);
EditEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, int stackPos, bool refreshEffectStack, bool doIt, bool refreshMonitor, QUndoCommand *parent = 0);
virtual int id() const;
virtual bool mergeWith(const QUndoCommand * command);
void undo();
......@@ -183,6 +183,7 @@ private:
bool m_doIt;
bool m_refreshEffectStack;
bool m_replaceEffect;
bool m_refreshMonitor;
};
class EditGuideCommand : public QUndoCommand
......
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