aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <[email protected]>2016-05-16 23:05:26 +0200
committerJean-Baptiste Mardelle <[email protected]>2016-05-16 23:05:26 +0200
commitaf45b4916ad4c99241cb0a46db582d1b97e84fd8 (patch)
treeb0cf697f5421684474cdc7978696bf9520765ccf
parente65239079cf6ec9137c04780b5c703d5bf42cc07 (diff)
Preliminary implementation of timeline preview rendering
Available in Timeline menu > Timeline Preview Render, it renders chunks of 200 frames. Ref: T1949
-rw-r--r--src/doc/kdenlivedoc.cpp17
-rw-r--r--src/doc/kdenlivedoc.h2
-rw-r--r--src/kdenliveui.rc5
-rw-r--r--src/mainwindow.cpp18
-rw-r--r--src/mainwindow.h1
-rw-r--r--src/project/jobs/proxyclipjob.cpp1
-rw-r--r--src/renderer.cpp65
-rw-r--r--src/renderer.h10
-rw-r--r--src/timeline/customruler.cpp15
-rw-r--r--src/timeline/customruler.h3
-rw-r--r--src/timeline/timeline.cpp53
-rw-r--r--src/timeline/timeline.h2
-rw-r--r--src/timeline/track.cpp50
-rw-r--r--src/timeline/track.h1
14 files changed, 226 insertions, 17 deletions
diff --git a/src/doc/kdenlivedoc.cpp b/src/doc/kdenlivedoc.cpp
index 7ca06e9..ba8b571 100644
--- a/src/doc/kdenlivedoc.cpp
+++ b/src/doc/kdenlivedoc.cpp
@@ -1606,3 +1606,20 @@ void KdenliveDoc::doAddAction(const QString &name, QAction *a)
{
pCore->window()->actionCollection()->addAction(name, a);
}
+
+void KdenliveDoc::previewRender()
+{
+ QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
+ QString documentId = m_documentProperties.value(QStringLiteral("documentid"));
+ m_render->previewRendering(zone(), cacheDir, documentId);
+ emit progressInfo(i18n("Rendering preview"), 0);
+}
+
+void KdenliveDoc::invalidatePreviews(QList <int> chunks)
+{
+ QDir dir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
+ QString documentId = m_documentProperties.value(QStringLiteral("documentid"));
+ foreach(int i, chunks) {
+ QFile::remove(dir.absoluteFilePath(documentId + QString("-%1.mp4").arg(i)));
+ }
+}
diff --git a/src/doc/kdenlivedoc.h b/src/doc/kdenlivedoc.h
index 80c301b..2808600 100644
--- a/src/doc/kdenlivedoc.h
+++ b/src/doc/kdenlivedoc.h
@@ -159,6 +159,8 @@ 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 invalidatePreviews(QList <int> chunks);
private:
QUrl m_url;
diff --git a/src/kdenliveui.rc b/src/kdenliveui.rc
index e4c725b..8b00cc9 100644
--- a/src/kdenliveui.rc
+++ b/src/kdenliveui.rc
@@ -1,5 +1,5 @@
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
-<kpartgui name="kdenlive" version="117" translationDomain="kdenlive">
+<kpartgui name="kdenlive" version="119" translationDomain="kdenlive">
<ToolBar name="extraToolBar" >
<text>Extra Toolbar</text>
<Action name="project_render" />
@@ -76,7 +76,7 @@
<Action name="razor_tool" />
<Action name="spacer_tool" />
</Menu>
-
+
<Menu name="clip" ><text>Clip</text>
<Menu name="marker_menu" ><text>Markers</text>
<Action name="add_clip_marker" />
@@ -111,6 +111,7 @@
<Action name="remove_extract" />
<Action name="remove_lift" />
</Menu>
+ <Action name="prerender_timeline_zone" />
<Action name="resize_timeline_clip_start" />
<Action name="resize_timeline_clip_end" />
<Menu name="current_clip" ><text>Current clip</text>
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 2596cca..2d7af27 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -831,7 +831,7 @@ void MainWindow::setupActions()
setStatusBarStyleSheet(palette());
QString styleBorderless = QStringLiteral("QToolButton { border-width: 0px;margin: 1px 3px 0px;padding: 0px;}");
-
+
//create edit mode buttons
m_normalEditTool = new QAction(KoIconUtils::themedIcon(QStringLiteral("kdenlive-normal-edit")), i18n("Normal mode"), this);
m_normalEditTool->setShortcut(i18nc("Normal editing", "n"));
@@ -1014,6 +1014,9 @@ void MainWindow::setupActions()
statusBar()->addWidget(m_messageLabel, 10);
statusBar()->addWidget(m_statusProgressBar, 0);
+ QWidget *spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ statusBar()->addWidget(spacer, 10);
statusBar()->addPermanentWidget(toolbar);
m_timeFormatButton = new KSelectAction(QStringLiteral("00:00:00:00 / 00:00:00:00"), this);
@@ -1152,6 +1155,8 @@ void MainWindow::setupActions()
addAction(QStringLiteral("insert_to_in_point"), i18n("Insert Clip Zone in Timeline (Insert)"), this, SLOT(slotInsertClipInsert()), QIcon(), Qt::Key_V);
addAction(QStringLiteral("remove_extract"), i18n("Extract Timeline Zone"), this, SLOT(slotExtractZone()), QIcon(), Qt::SHIFT + Qt::Key_X);
addAction(QStringLiteral("remove_lift"), i18n("Lift Timeline Zone"), this, SLOT(slotLiftZone()), QIcon(), Qt::Key_Z);
+ addAction(QStringLiteral("prerender_timeline_zone"), i18n("Timeline Preview Render"), this, SLOT(slotPreviewRender()), QIcon());
+
addAction(QStringLiteral("select_timeline_clip"), i18n("Select Clip"), this, SLOT(slotSelectTimelineClip()), KoIconUtils::themedIcon(QStringLiteral("edit-select")), Qt::Key_Plus);
addAction(QStringLiteral("deselect_timeline_clip"), i18n("Deselect Clip"), this, SLOT(slotDeselectTimelineClip()), KoIconUtils::themedIcon(QStringLiteral("edit-select")), Qt::Key_Minus);
addAction(QStringLiteral("select_add_timeline_clip"), i18n("Add Clip To Selection"), this, SLOT(slotSelectAddTimelineClip()),
@@ -2168,6 +2173,13 @@ void MainWindow::slotLiftZone()
}
}
+void MainWindow::slotPreviewRender()
+{
+ if (pCore->projectManager()->current()) {
+ pCore->projectManager()->current()->previewRender();
+ }
+}
+
void MainWindow::slotSelectTimelineClip()
{
if (pCore->projectManager()->currentTimeline())
@@ -2333,10 +2345,10 @@ void MainWindow::slotGotProgressInfo(const QString &message, int progress, Messa
if (type == DefaultMessage) {
m_statusProgressBar->setValue(progress);
}
- m_messageLabel->setMessage(message, type);
+ m_messageLabel->setMessage(progress < 100 ? message : QString(), type);
if (progress >= 0) {
if (type == DefaultMessage) {
- m_statusProgressBar->setVisible(true);
+ m_statusProgressBar->setVisible(progress < 100);
}
} else {
m_statusProgressBar->setVisible(false);
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 4d5622d..28456da 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -319,6 +319,7 @@ private slots:
void slotInsertClipInsert();
void slotExtractZone();
void slotLiftZone();
+ void slotPreviewRender();
void slotSelectTimelineClip();
void slotSelectTimelineTransition();
void slotDeselectTimelineClip();
diff --git a/src/project/jobs/proxyclipjob.cpp b/src/project/jobs/proxyclipjob.cpp
index d34aed1..c22b905 100644
--- a/src/project/jobs/proxyclipjob.cpp
+++ b/src/project/jobs/proxyclipjob.cpp
@@ -167,7 +167,6 @@ void ProxyJob::startJob()
}
m_jobProcess->waitForFinished(400);
}
-
if (m_jobStatus != JobAborted) {
int result = m_jobProcess->exitStatus();
if (result == QProcess::NormalExit) {
diff --git a/src/renderer.cpp b/src/renderer.cpp
index 180cc51..2c0d009 100644
--- a/src/renderer.cpp
+++ b/src/renderer.cpp
@@ -72,7 +72,8 @@ Render::Render(Kdenlive::MonitorId rendererName, BinController *binController, G
m_isLoopMode(false),
m_blackClip(NULL),
m_isActive(false),
- m_isRefreshing(false)
+ m_isRefreshing(false),
+ m_abortPreview(false)
{
qRegisterMetaType<stringMap> ("stringMap");
analyseAudio = KdenliveSettings::monitor_audio();
@@ -101,6 +102,7 @@ Render::Render(Kdenlive::MonitorId rendererName, BinController *binController, G
Render::~Render()
{
+ m_abortPreview = true;
closeMlt();
}
@@ -111,6 +113,7 @@ void Render::closeMlt()
delete m_mltConsumer;
delete m_mltProducer;
delete m_blackClip;
+ m_previewThread.waitForFinished();
}
void Render::slotSwitchFullscreen()
@@ -2314,3 +2317,63 @@ void Render::updateSlowMotionProducers(const QString &id, QMap <QString, QString
}
}
}
+
+void Render::previewRendering(QPoint zone, const QString &cacheDir, const QString &documentId)
+{
+ if (m_previewThread.isRunning()) {
+ qDebug()<<"/ / /Already processing a preview render, abort";
+ return;
+ }
+ QDir dir(cacheDir);
+ dir.mkpath(QStringLiteral("."));
+ // Data is rendered in 200 frames chunks
+ int startChunk = zone.x() / 200;
+ int endChunk = rintl(zone.y() / 200);
+ // Save temporary scenelist
+ QString sceneListFile = dir.absoluteFilePath(documentId + ".mlt");
+ Mlt::Consumer xmlConsumer(*m_qmlView->profile(), "xml", sceneListFile.toUtf8().constData());
+ if (!xmlConsumer.is_valid())
+ return;
+ m_mltProducer->optimise();
+ xmlConsumer.set("terminate_on_pause", 1);
+ Mlt::Producer prod(m_mltProducer->get_producer());
+ if (!prod.is_valid())
+ return;
+ xmlConsumer.connect(prod);
+ xmlConsumer.run();
+ m_previewThread = QtConcurrent::run(this, &Render::doPreviewRender, startChunk, endChunk, dir, documentId, sceneListFile);
+}
+
+void Render::doPreviewRender(int start, int end, QDir folder, QString id, QString scene)
+{
+ int progress;
+ for (int i = start; i <= end; ++i) {
+ if (m_abortPreview)
+ break;
+ QString fileName = id + QString("-%1.mp4").arg(i);
+ if (end > start) {
+ progress = (double) (i - start + 1) / (end +1 - start) * 100;
+ } else {
+ progress = 100;
+ }
+ if (folder.exists(fileName)) {
+ // This chunk already exists
+ emit previewRender(i * 200, folder.absoluteFilePath(fileName), progress);
+ continue;
+ }
+ // Build rendering process
+ QStringList args;
+ args << scene;
+ args << "in=" + QString::number(i * 200);
+ args << "out=" + QString::number(i * 200 + 199);
+ args << "-consumer" << "avformat:" + folder.absoluteFilePath(fileName);
+ int result = QProcess::execute(KdenliveSettings::rendererpath(), args);
+ if (result < 0) {
+ // Something is wrong, abort
+ break;
+ }
+ emit previewRender(i * 200, folder.absoluteFilePath(fileName), progress);
+ }
+ QFile::remove(scene);
+ m_abortPreview = false;
+}
diff --git a/src/renderer.h b/src/renderer.h
index 58b6b36..ea4ae69 100644
--- a/src/renderer.h
+++ b/src/renderer.h
@@ -51,6 +51,7 @@
#include <QFuture>
#include <QSemaphore>
#include <QTimer>
+#include <QDir>
class KComboBox;
class BinController;
@@ -287,6 +288,7 @@ class Render: public AbstractRender
void prepareProfileReset(double fps);
void finishProfileReset();
void updateSlowMotionProducers(const QString &id, QMap <QString, QString> passProperties);
+ void previewRendering(QPoint zone, const QString &cacheDir, const QString &documentId);
private:
@@ -299,6 +301,7 @@ private:
Mlt::Producer * m_mltProducer;
Mlt::Event *m_showFrameEvent;
Mlt::Event *m_pauseEvent;
+ QFuture <void> m_previewThread;
BinController *m_binController;
GLWidget *m_qmlView;
double m_fps;
@@ -322,10 +325,9 @@ private:
bool m_isActive;
/** @brief True if the consumer is currently refreshing itself. */
bool m_isRefreshing;
-
+ bool m_abortPreview;
void closeMlt();
QMap<QString, Mlt::Producer *> m_slowmotionProducers;
-
/** @brief Build the MLT Consumer object with initial settings.
* @param profileName The MLT profile to use for the consumer */
@@ -339,12 +341,13 @@ private:
void cloneProperties(Mlt::Properties &dest, Mlt::Properties &source);
/** @brief Get a track producer from a clip's id */
Mlt::Producer *getProducerForTrack(Mlt::Playlist &trackPlaylist, const QString &clipId);
-
+
private slots:
/** @brief Refreshes the monitor display. */
void refresh();
void slotCheckSeeking();
+ void doPreviewRender(int start, int end, QDir folder, QString id, QString scene);
signals:
/** @brief The renderer stopped, either playing or rendering. */
@@ -381,6 +384,7 @@ signals:
void mltFrameReceived(Mlt::Frame *);
/** @brief We want to replace a clip with another, but before we need to change clip producer id so that there is no interference*/
void prepareTimelineReplacement(const QString &);
+ void previewRender(int frame, const QString &file, int progress);
public slots:
diff --git a/src/timeline/customruler.cpp b/src/timeline/customruler.cpp
index b964957..d5bd868 100644
--- a/src/timeline/customruler.cpp
+++ b/src/timeline/customruler.cpp
@@ -474,6 +474,13 @@ void CustomRuler::paintEvent(QPaintEvent *e)
p.drawPolyline(pa);
}
+ // draw Rendering preview zones
+ QColor preview(Qt::yellow);
+ foreach(int frame, m_renderingPreviews) {
+ QRect rec(frame * m_factor - m_offset, MAX_HEIGHT - 2, 199 * m_factor, 2);
+ p.fillRect(rec, preview);
+ }
+
// draw pointer
const int value = m_view->cursorPos() * m_factor - m_offset;
QPolygon pa(3);
@@ -496,3 +503,11 @@ void CustomRuler::activateZone()
update();
}
+void CustomRuler::updatePreview(int frame, bool rendered)
+{
+ if (rendered)
+ m_renderingPreviews << frame;
+ else
+ m_renderingPreviews.removeAll(frame);
+ update(frame * m_factor - offset(), MAX_HEIGHT - 2, (199) * m_factor, 2);
+}
diff --git a/src/timeline/customruler.h b/src/timeline/customruler.h
index e858293..9a466ef 100644
--- a/src/timeline/customruler.h
+++ b/src/timeline/customruler.h
@@ -50,6 +50,7 @@ public:
void updateProjectFps(const Timecode &t);
void updateFrameSize();
void activateZone();
+ void updatePreview(int frame, bool rendered = true);
protected:
void paintEvent(QPaintEvent * /*e*/);
@@ -82,7 +83,7 @@ private:
int m_startRate;
MOUSE_MOVE m_mouseMove;
QMenu *m_goMenu;
-
+ QList <int> m_renderingPreviews;
public slots:
void slotMoveRuler(int newPos);
diff --git a/src/timeline/timeline.cpp b/src/timeline/timeline.cpp
index f5d5049..e14ef22 100644
--- a/src/timeline/timeline.cpp
+++ b/src/timeline/timeline.cpp
@@ -142,6 +142,7 @@ Timeline::Timeline(KdenliveDoc *doc, const QList<QAction *> &actions, bool *ok,
connect(m_trackview->horizontalScrollBar(), SIGNAL(valueChanged(int)), m_ruler, SLOT(slotMoveRuler(int)));
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);
}
Timeline::~Timeline()
@@ -318,6 +319,7 @@ int Timeline::getTracks() {
}
connect(tk, &Track::newTrackDuration, this, &Timeline::checkDuration, Qt::DirectConnection);
connect(tk, SIGNAL(storeSlowMotion(QString,Mlt::Producer *)), m_doc->renderer(), SLOT(storeSlowmotionProducer(QString,Mlt::Producer *)));
+ connect(tk, &Track::invalidatePreview, this, &Timeline::invalidatePreview);
}
}
headers_container->setFixedWidth(headerWidth);
@@ -1715,3 +1717,54 @@ void Timeline::slotEnableZone(bool enable)
KdenliveSettings::setUseTimelineZoneToEdit(enable);
m_ruler->activateZone();
}
+
+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());
+ int trackIndex = tracksCount();
+ m_tractor->lock();
+ m_tractor->insert_track(overlay, trackIndex);
+ m_tractor->unlock();
+ m_hasOverlayTrack = true;
+ }
+ Mlt::Producer *overlayTrack = m_tractor->track(tracksCount());
+ m_tractor->lock();
+ Mlt::Playlist trackPlaylist((mlt_playlist) overlayTrack->get_service());
+ 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);
+ }
+ m_tractor->unlock();
+ m_doc->progressInfo(i18n("Rendering preview"), progress);
+ //m_doc->updatePreview(progress);
+}
+
+void Timeline::invalidatePreview(int startFrame, int length)
+{
+ if (!m_hasOverlayTrack)
+ return;
+ int start = startFrame / 200;
+ int end = lrintf((startFrame + length) / 200);
+ 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(200 * i);
+ if (trackPlaylist.is_blank(i))
+ continue;
+ list << i;
+ Mlt::Producer *prod = trackPlaylist.replace_with_blank(ix);
+ delete prod;
+ m_ruler->updatePreview(i * 200, false);
+ }
+ trackPlaylist.consolidate_blanks();
+ m_tractor->unlock();
+ m_doc->invalidatePreviews(list);
+}
diff --git a/src/timeline/timeline.h b/src/timeline/timeline.h
index c1f6279..b0ed868 100644
--- a/src/timeline/timeline.h
+++ b/src/timeline/timeline.h
@@ -235,6 +235,8 @@ private slots:
void slotUpdateTrackEffectState(int);
/** @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);
signals:
void mousePosition(int);
diff --git a/src/timeline/track.cpp b/src/timeline/track.cpp
index 3bbc235..b49bbd0 100644
--- a/src/timeline/track.cpp
+++ b/src/timeline/track.cpp
@@ -115,6 +115,7 @@ bool Track::doAdd(qreal t, Mlt::Producer *cut, TimelineMode::EditMode mode)
if (m_playlist.insert_at(pos, cut, 1) == m_playlist.count() - 1) {
emit newTrackDuration(m_playlist.get_playtime());
}
+ emit invalidatePreview(pos, len);
return true;
}
@@ -143,6 +144,7 @@ bool Track::move(qreal start, qreal end, TimelineMode::EditMode mode)
if (durationChanged) {
emit newTrackDuration(m_playlist.get_playtime());
}
+ emit invalidatePreview(pos, clipProducer->get_playtime());
return result;
}
@@ -159,15 +161,19 @@ bool Track::del(qreal t)
{
m_playlist.lock();
bool durationChanged = false;
- int ix = m_playlist.get_clip_index_at(frame(t));
+ int pos = frame(t);
+ int ix = m_playlist.get_clip_index_at(pos);
if (ix == m_playlist.count() - 1) {
durationChanged = true;
}
+ int length = 0;
Mlt::Producer *clip = m_playlist.replace_with_blank(ix);
- if (clip)
+ if (clip) {
+ length = clip->get_playtime();
delete clip;
+ }
else {
- qWarning("Error deleting clip at %d, tk: %d", frame(t), m_index);
+ qWarning("Error deleting clip at %d, tk: %d", pos, m_index);
m_playlist.unlock();
return false;
}
@@ -176,6 +182,7 @@ bool Track::del(qreal t)
if (durationChanged) {
emit newTrackDuration(m_playlist.get_playtime());
}
+ emit invalidatePreview(pos, length);
return true;
}
@@ -185,14 +192,17 @@ bool Track::del(qreal t, qreal dt)
m_playlist.insert_blank(m_playlist.remove_region(frame(t), frame(dt) + 1), frame(dt));
m_playlist.consolidate_blanks();
m_playlist.unlock();
+ emit invalidatePreview(frame(t), frame(dt));
return true;
}
bool Track::resize(qreal t, qreal dt, bool end)
{
m_playlist.lock();
- int index = m_playlist.get_clip_index_at(frame(t));
+ int startFrame = frame(t);
+ int index = m_playlist.get_clip_index_at(startFrame);
int length = frame(dt);
+ int updateLength = length;
QScopedPointer<Mlt::Producer> clip(m_playlist.get_clip(index));
if (clip == NULL || clip->is_blank()) {
qWarning("Can't resize clip at %f", t);
@@ -202,7 +212,14 @@ bool Track::resize(qreal t, qreal dt, bool end)
int in = clip->get_in();
int out = clip->get_out();
- if (end) out += length; else in += length;
+ if (end) {
+ // Resizing clip end
+ startFrame += out - in;
+ out += length;
+ } else {
+ // Resizing clip start
+ in += length;
+ }
//image or color clips are not bounded
if (in < 0) {out -= in; in = 0;}
@@ -224,6 +241,10 @@ bool Track::resize(qreal t, qreal dt, bool end)
m_playlist.unlock();
// this is the last clip in track, check tracks length to adjust black track and project duration
emit newTrackDuration(m_playlist.get_playtime());
+ if (updateLength > 0)
+ emit invalidatePreview(startFrame, updateLength);
+ else
+ emit invalidatePreview(startFrame + updateLength, -updateLength);
return true;
}
length = -length;
@@ -249,6 +270,10 @@ bool Track::resize(qreal t, qreal dt, bool end)
m_playlist.consolidate_blanks();
m_playlist.unlock();
+ if (updateLength > 0)
+ emit invalidatePreview(startFrame, updateLength);
+ else
+ emit invalidatePreview(startFrame + updateLength, -updateLength);
return true;
}
@@ -332,6 +357,7 @@ bool Track::replaceAll(const QString &id, Mlt::Producer *original, Mlt::Producer
QString service = original->parent().get("mlt_service");
QString idForTrack = original->parent().get("id");
QLocale locale;
+ QList <QPoint> updateList;
if (needsDuplicate(service)) {
// We have to use the track clip duplication functions, because of audio glitches in MLT's multitrack
idForAudioTrack = idForTrack + QLatin1Char('_') + m_playlist.get("id") + "_audio";
@@ -350,6 +376,7 @@ bool Track::replaceAll(const QString &id, Mlt::Producer *original, Mlt::Producer
}
current.remove(0, 1);
Mlt::Producer *cut = NULL;
+ updateList << QPoint(m_playlist.clip_start(i), m_playlist.clip_length(i));
if (current.startsWith("slowmotion:" + id + ":")) {
// Slowmotion producer, just update resource
Mlt::Producer *slowProd = newSlowMos.value(current.section(QStringLiteral(":"), 2));
@@ -398,6 +425,9 @@ bool Track::replaceAll(const QString &id, Mlt::Producer *original, Mlt::Producer
delete cut;
}
}
+ foreach(const QPoint &pt, updateList) {
+ emit invalidatePreview(pt.x(), pt.y());
+ }
return found;
}
@@ -426,6 +456,7 @@ bool Track::replace(qreal t, Mlt::Producer *prod, PlaylistState::ClipState state
bool ok = m_playlist.insert_at(frame(t), cut, 1) >= 0;
delete cut;
m_playlist.unlock();
+ emit invalidatePreview(frame(t), orig->get_playtime());
return ok;
}
@@ -435,7 +466,7 @@ void Track::updateEffects(const QString &id, Mlt::Producer *original)
QString idForVideoTrack;
QString service = original->parent().get("mlt_service");
QString idForTrack = original->parent().get("id");
-
+ QList <QPoint> updateList;
if (needsDuplicate(service)) {
// We have to use the track clip duplication functions, because of audio glitches in MLT's multitrack
idForAudioTrack = idForTrack + QLatin1Char('_') + m_playlist.get("id") + "_audio";
@@ -451,16 +482,22 @@ void Track::updateEffects(const QString &id, Mlt::Producer *original)
if (current.startsWith(QLatin1String("slowmotion:"))) {
if (current.section(QStringLiteral(":"), 1, 1) == id) {
Clip(origin).replaceEffects(*original);
+ updateList << QPoint(m_playlist.clip_start(i), m_playlist.clip_length(i));
}
}
else if (current == id) {
// we are directly using original producer, no need to update effects
+ updateList << QPoint(m_playlist.clip_start(i), m_playlist.clip_length(i));
continue;
}
else if (current.section(QStringLiteral("_"), 0, 0) == id) {
+ updateList << QPoint(m_playlist.clip_start(i), m_playlist.clip_length(i));
Clip(origin).replaceEffects(*original);
}
}
+ foreach(const QPoint &pt, updateList) {
+ emit invalidatePreview(pt.x(), pt.y());
+ }
}
/*Mlt::Producer &Track::find(const QByteArray &name, const QByteArray &value, int startindex) {
@@ -646,6 +683,7 @@ Mlt::Producer *Track::buildSlowMoProducer(Mlt::Properties passProps, const QStri
int Track::changeClipSpeed(ItemInfo info, ItemInfo speedIndependantInfo, PlaylistState::ClipState state, double speed, int strobe, Mlt::Producer *prod, const QString &id, Mlt::Properties passProps, bool removeEffect)
{
+ //TODO: invalidate preview rendering
int newLength = 0;
int startPos = info.startPos.frames(fps());
int clipIndex = m_playlist.get_clip_index_at(startPos);
diff --git a/src/timeline/track.h b/src/timeline/track.h
index 8914876..aec88d4 100644
--- a/src/timeline/track.h
+++ b/src/timeline/track.h
@@ -201,6 +201,7 @@ signals:
* @param duration is the new length */
void newTrackDuration(int duration);
void storeSlowMotion(const QString &url, Mlt::Producer *prod);
+ void invalidatePreview(int position, int length);
private:
/** Position in MLT's tractor */