* Fix threading warning on audio thumbs creation

* cleanup, start using loadTrack in timeline to reload current timeline after operation instead of moving clip items manually
parent b0d05db5
......@@ -2334,8 +2334,9 @@ void Bin::slotItemDropped(const QList<QUrl>&urls, const QModelIndex &parent)
}
}
}
if (!clipsToAdd.isEmpty())
ClipCreationDialog::createClipsCommand(m_doc, clipsToAdd, folderInfo, this);
if (!clipsToAdd.isEmpty()) {
ClipCreationDialog::createClipsCommand(m_doc, clipsToAdd, folderInfo, this);
}
}
void Bin::slotExpandUrl(ItemInfo info, QUrl url, QUndoCommand *command)
......
......@@ -970,8 +970,6 @@ const QString ProjectClip::getAudioThumbPath(AudioStreamInfo *audioInfo)
void ProjectClip::slotCreateAudioThumbs()
{
QMutexLocker lock(&m_audioMutex);
if (m_audioThumbsProcess.state() != QProcess::NotRunning)
return;
Mlt::Producer *prod = originalProducer();
if (!prod || !prod->is_valid()) return;
AudioStreamInfo *audioInfo = m_controller->audioInfo();
......@@ -1002,7 +1000,6 @@ void ProjectClip::slotCreateAudioThumbs()
return;
}
bool jobFinished = false;
if (KdenliveSettings::ffmpegaudiothumbnails() && m_type != Playlist) {
QStringList args;
QList <QTemporaryFile*> channelFiles;
......@@ -1051,21 +1048,22 @@ void ProjectClip::slotCreateAudioThumbs()
}
}
emit updateJobStatus(AbstractClipJob::THUMBJOB, JobWaiting, 0);
connect(this, SIGNAL(doAbortAudioThumbs()), &m_audioThumbsProcess, SLOT(kill()), Qt::DirectConnection);
connect(&m_audioThumbsProcess, &QProcess::readyReadStandardOutput, this, &ProjectClip::updateFfmpegProgress);
m_audioThumbsProcess.start(KdenliveSettings::ffmpegpath(), args);
QProcess audioThumbsProcess;
connect(this, SIGNAL(doAbortAudioThumbs()), &audioThumbsProcess, SLOT(kill()), Qt::DirectConnection);
connect(&audioThumbsProcess, &QProcess::readyReadStandardOutput, this, &ProjectClip::updateFfmpegProgress);
audioThumbsProcess.start(KdenliveSettings::ffmpegpath(), args);
bool ffmpegError = false;
if (!m_audioThumbsProcess.waitForStarted()) {
if (!audioThumbsProcess.waitForStarted()) {
ffmpegError = true;
}
m_audioThumbsProcess.waitForFinished(-1);
audioThumbsProcess.waitForFinished(-1);
if (m_abortAudioThumb) {
emit updateJobStatus(AbstractClipJob::THUMBJOB, JobDone, 0);
m_abortAudioThumb = false;
return;
}
if (!ffmpegError && m_audioThumbsProcess.exitStatus() != QProcess::CrashExit) {
if (!ffmpegError && audioThumbsProcess.exitStatus() != QProcess::CrashExit) {
int dataSize = 0;
QList <const qint16*> rawChannels;
QList <QByteArray> sourceChannels;
......@@ -1207,7 +1205,10 @@ void ProjectClip::slotCreateAudioThumbs()
void ProjectClip::updateFfmpegProgress()
{
QString result = m_audioThumbsProcess.readAllStandardOutput();
QProcess *callerProcess = qobject_cast<QProcess *> (QObject::sender());
if (!callerProcess)
return;
QString result = callerProcess->readAllStandardOutput();
QStringList lines = result.split('\n');
foreach(const QString & data, lines) {
if (data.startsWith(QStringLiteral("out_time_ms"))) {
......
......@@ -241,7 +241,6 @@ private:
QUrl m_temporaryUrl;
ClipType m_type;
Mlt::Producer *m_thumbsProducer;
QProcess m_audioThumbsProcess;
QMutex m_producerMutex;
QMutex m_thumbMutex;
QMutex m_intraThumbMutex;
......
......@@ -418,7 +418,7 @@ void ClipCreationDialog::createClipsCommand(KdenliveDoc *doc, const QList<QUrl>
if (folderFiles.count() > 1) foldersList.append(folderFiles);
}
}*/
foreach(const QUrl &file, urls) {
QDomDocument xml;
QDomElement prod = xml.createElement(QStringLiteral("producer"));
......@@ -444,21 +444,6 @@ void ClipCreationDialog::createClipsCommand(KdenliveDoc *doc, const QList<QUrl>
prod.setAttribute(QStringLiteral("in"), 0);
prod.setAttribute(QStringLiteral("out"), doc->getFramePos(KdenliveSettings::image_duration()) - 1);
if (KdenliveSettings::autoimagetransparency()) properties.insert(QStringLiteral("kdenlive:transparency"), QStringLiteral("1"));
// Read EXIF metadata for JPEG
if (type.inherits(QStringLiteral("image/jpeg"))) {
//TODO KF5 how to read metadata?
/*
KFileMetaInfo metaInfo(file.path(), QString("image/jpeg"), KFileMetaInfo::TechnicalInfo);
const QHash<QString, KFileMetaInfoItem> metaInfoItems = metaInfo.items();
foreach(const KFileMetaInfoItem & metaInfoItem, metaInfoItems) {
QDomElement meta = xml.createElement("metaproperty");
meta.setAttribute("name", "meta.attr." + metaInfoItem.name().section('#', 1));
QDomText value = xml.createTextNode(metaInfoItem.value().toString());
meta.setAttribute("tool", "KDE Metadata");
meta.appendChild(value);
prod.appendChild(meta);
}*/
}
} else if (type.inherits(QStringLiteral("application/x-kdenlivetitle"))) {
// opening a title file
QDomDocument txtdoc(QStringLiteral("titledocument"));
......
......@@ -146,6 +146,7 @@ void EffectStackView2::slotClipItemUpdate()
void EffectStackView2::slotClipItemSelected(ClipItem* c, Monitor *m, bool reloadStack)
{
QMutexLocker lock (&m_mutex);
if (m_effect->effectCompare->isChecked()) {
// disable split effect when changing clip
m_effect->effectCompare->setChecked(false);
......
......@@ -123,6 +123,7 @@ private:
/** @brief The current effect may require an on monitor scene. */
MonitorSceneType m_monitorSceneWanted;
QMutex m_mutex;
/** If in track mode: Info of the edited track to be able to access its duration. */
TrackInfo m_trackInfo;
......
......@@ -1627,9 +1627,9 @@ void MainWindow::connectDocument()
connect(trackView, SIGNAL(showTrackEffects(int,TrackInfo)), this, SLOT(slotTrackSelected(int,TrackInfo)));
connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*,bool,bool)), this, SLOT(slotTimelineClipSelected(ClipItem*,bool,bool)));
connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*,bool,bool)), this, SLOT(slotTimelineClipSelected(ClipItem*,bool,bool)), Qt::DirectConnection);
connect(trackView->projectView(), &CustomTrackView::setActiveKeyframe, m_effectStack, &EffectStackView2::setActiveKeyframe);
connect(trackView->projectView(), SIGNAL(transitionItemSelected(Transition*,int,QPoint,bool)), m_effectStack, SLOT(slotTransitionItemSelected(Transition*,int,QPoint,bool)));
connect(trackView->projectView(), SIGNAL(transitionItemSelected(Transition*,int,QPoint,bool)), m_effectStack, SLOT(slotTransitionItemSelected(Transition*,int,QPoint,bool)), Qt::DirectConnection);
connect(trackView->projectView(), SIGNAL(transitionItemSelected(Transition*,int,QPoint,bool)), this, SLOT(slotActivateTransitionView(Transition*)));
connect(trackView->projectView(), SIGNAL(zoomIn()), this, SLOT(slotZoomIn()));
......
......@@ -169,10 +169,6 @@ CustomTrackView::CustomTrackView(KdenliveDoc *doc, Timeline *timeline, CustomTra
m_scrollTimer.setInterval(100);
m_scrollTimer.setSingleShot(true);
connect(&m_thumbsTimer, SIGNAL(timeout()), this, SLOT(slotFetchNextThumbs()));
m_thumbsTimer.setInterval(500);
m_thumbsTimer.setSingleShot(true);
QIcon razorIcon = KoIconUtils::themedIcon(QStringLiteral("edit-cut"));
m_razorCursor = QCursor(razorIcon.pixmap(32, 32));
m_spacerCursor = QCursor(Qt::SplitHCursor);
......@@ -188,7 +184,6 @@ CustomTrackView::~CustomTrackView()
{
qDeleteAll(m_guides);
m_guides.clear();
m_waitingThumbs.clear();
delete m_keyPropertiesTimer;
}
......@@ -397,19 +392,6 @@ int CustomTrackView::getNextVideoTrack(int track)
return track;
}
void CustomTrackView::slotFetchNextThumbs()
{
if (!m_waitingThumbs.isEmpty()) {
ClipItem *item = m_waitingThumbs.takeFirst();
while (item == NULL && !m_waitingThumbs.isEmpty()) {
item = m_waitingThumbs.takeFirst();
}
if (item) item->slotFetchThumbs();
if (!m_waitingThumbs.isEmpty()) m_thumbsTimer.start();
}
}
void CustomTrackView::slotCheckMouseScrolling()
{
if (m_scrollOffset == 0) {
......@@ -1973,8 +1955,6 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint &pos)
m_dragItem->setMainSelectedClip(true);
}
item->setSelected(true);
//TODO:
//if (!clip->isPlaceHolder()) m_waitingThumbs.append(item);
}
updateSnapPoints(NULL, offsetList);
......@@ -1990,7 +1970,6 @@ bool CustomTrackView::insertDropClips(const QMimeData *data, const QPoint &pos)
m_dragItem->setPos(framePos);
}
//m_selectionGroup->setZValue(10);
m_thumbsTimer.start();
}
return true;
}
......@@ -2620,8 +2599,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, effect, ix, refreshEffectStack, true);
else command = new EditEffectCommand(this, track, GenTime(-1), oldeffect, effect, ix, refreshEffectStack, true);
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);
m_commandStack->push(command);
}
......@@ -2634,43 +2613,38 @@ void CustomTrackView::slotUpdateClipRegion(ClipItem *clip, int ix, QString regio
m_commandStack->push(command);
}
ClipItem *CustomTrackView::cutClip(const ItemInfo &info, const GenTime &cutTime, bool cut, const EffectsList &oldStack, bool execute)
void CustomTrackView::cutClip(const ItemInfo &info, const GenTime &cutTime, bool cut, const EffectsList &oldStack, bool execute)
{
if (cut) {
// cut clip
ClipItem *item = getClipItemAtStart(info.startPos, info.track);
bool selectDup = false;
if (item == m_dragItem) {
emit clipItemSelected(NULL);
selectDup = true;
}
if (!item || cutTime >= item->endPos() || cutTime <= item->startPos()) {
emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage);
if (item)
qDebug() << "///////// ERROR CUTTING CLIP : (" << item->startPos().frames(25) << '-' << item->endPos().frames(25) << "), INFO: (" << info.startPos.frames(25) << '-' << info.endPos.frames(25) << ')' << ", CUT: " << cutTime.frames(25);
else
qDebug() << "/// ERROR NO CLIP at: " << info.startPos.frames(m_document->fps()) << ", track: " << info.track;
return NULL;
return;
}
if (execute) {
if (!m_timeline->track(info.track)->cut(cutTime.seconds())) {
// Error cuting clip in playlist
return NULL;
return;
}
}
int cutPos = (int) cutTime.frames(m_document->fps());
ItemInfo newPos;
newPos.startPos = cutTime;
newPos.endPos = info.endPos;
newPos.cropStart = item->info().cropStart + (cutTime - info.startPos);
newPos.track = info.track;
newPos.cropDuration = newPos.endPos - newPos.startPos;
bool snap = KdenliveSettings::snaptopoints();
KdenliveSettings::setSnaptopoints(false);
ClipItem *dup = item->clone(newPos);
connect(dup, &AbstractClipItem::selectItem, this, &CustomTrackView::slotSelectItem);
dup->binClip()->addRef();
dup->setPos(newPos.startPos.frames(m_document->fps()), getPositionFromTrack(newPos.track) + 1 + dup->itemOffset());
m_timeline->reloadTrack(info.track, info.startPos.frames(m_document->fps()), info.endPos.frames(m_document->fps()));
// remove unwanted effects
// fade in from 2nd part of the clip
item = getClipItemAtStart(info.startPos, info.track);
ClipItem *dup = getClipItemAtStart(cutTime, info.track);
dup->binClip()->addRef();
int ix = dup->hasEffect(QString(), QStringLiteral("fadein"));
if (ix != -1) {
QDomElement oldeffect = dup->effectAtIndex(ix);
......@@ -2693,57 +2667,47 @@ ClipItem *CustomTrackView::cutClip(const ItemInfo &info, const GenTime &cutTime,
item->deleteEffect(oldeffect.attribute(QStringLiteral("kdenlive_ix")).toInt());
}
item->resizeEnd(cutPos);
scene()->addItem(dup);
if (item->checkKeyFrames(m_document->width(), m_document->height(), (info.cropDuration + info.cropStart).frames(m_document->fps())))
slotRefreshEffects(item);
if (dup->checkKeyFrames(m_document->width(), m_document->height(), (info.cropDuration + info.cropStart).frames(m_document->fps()), (cutTime - item->startPos()).frames(m_document->fps())))
slotRefreshEffects(dup);
KdenliveSettings::setSnaptopoints(snap);
return dup;
if (selectDup) {
dup->setSelected(true);
dup->setMainSelectedClip(true);
m_dragItem = dup;
emit clipItemSelected(dup);
}
return;
} else {
// uncut clip
ClipItem *item = getClipItemAtStart(info.startPos, info.track);
ClipItem *dup = getClipItemAtStart(cutTime, info.track);
bool selectDup = false;
if (m_dragItem == item || m_dragItem == dup) {
emit clipItemSelected(NULL);
selectDup = true;
}
if (!item || !dup || item == dup) {
emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage);
return NULL;
return;
}
if (!m_timeline->track(info.track)->del(cutTime.seconds())) {
emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(cutTime.frames(m_document->fps())), m_timeline->getTrackInfo(info.track).trackName), ErrorMessage);
return NULL;
return;
}
dup->binClip()->removeRef();
bool snap = KdenliveSettings::snaptopoints();
KdenliveSettings::setSnaptopoints(false);
m_waitingThumbs.removeAll(dup);
if (dup->isSelected() && dup == m_dragItem) {
m_timeline->track(info.track)->resize(info.startPos.seconds(), (info.endPos - cutTime).seconds(), true);
m_timeline->reloadTrack(info.track, info.startPos.frames(m_document->fps()), info.endPos.frames(m_document->fps()));
item = getClipItemAtStart(info.startPos, info.track);
// Restore original effects
item->setEffectList(oldStack);
if (selectDup) {
item->setSelected(true);
item->setMainSelectedClip(true);
m_dragItem = item;
emit clipItemSelected(item);
}
scene()->removeItem(dup);
delete dup;
dup = NULL;
ItemInfo clipinfo = item->info();
bool success = m_timeline->track(clipinfo.track)->resize(clipinfo.startPos.seconds(), (info.endPos - cutTime).seconds(), true);
if (success) {
item->resizeEnd((int) info.endPos.frames(m_document->fps()));
item->setEffectList(oldStack);
} else {
emit displayMessage(i18n("Error when resizing clip"), ErrorMessage);
}
KdenliveSettings::setSnaptopoints(snap);
return item;
}
}
......@@ -3037,8 +3001,6 @@ void CustomTrackView::dragMoveEvent(QDragMoveEvent * event)
void CustomTrackView::dragLeaveEvent(QDragLeaveEvent * event)
{
if ((m_selectionGroup || m_dragItem) && m_clipDrag) {
m_thumbsTimer.stop();
m_waitingThumbs.clear();
QList<QGraphicsItem *> items;
QMutexLocker lock(&m_selectionMutex);
if (m_selectionGroup) items = m_selectionGroup->childItems();
......@@ -4792,7 +4754,6 @@ void CustomTrackView::deleteClip(ItemInfo info, bool refresh)
emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(info.startPos.frames(m_document->fps())), m_timeline->getTrackInfo(info.track).trackName), ErrorMessage);
return;
}
m_waitingThumbs.removeAll(item);
item->stopThumbs();
item->binClip()->removeRef();
if (item->isSelected()) emit clipItemSelected(NULL);
......@@ -4935,6 +4896,12 @@ void CustomTrackView::cutSelectedClips()
QList<QGraphicsItem *> itemList = scene()->selectedItems();
QList<AbstractGroupItem *> groups;
GenTime currentPos = GenTime(m_cursorPos, m_document->fps());
if (itemList.isEmpty()) {
// Fetch clip on selected track / under cursor
ClipItem *under = getClipItemAtMiddlePoint(m_cursorPos, m_selectedTrack);
if (under)
itemList << under;
}
for (int i = 0; i < itemList.count(); ++i) {
if (!itemList.at(i))
continue;
......@@ -4947,16 +4914,6 @@ void CustomTrackView::cutSelectedClips()
} else if (currentPos > item->startPos() && currentPos < item->endPos()) {
RazorClipCommand *command = new RazorClipCommand(this, item->info(), item->effectList(), currentPos);
m_commandStack->push(command);
// Select right part of the cut for further cuts
ClipItem *dup = getClipItemAtStart(currentPos, item->track());
if (item->isSelected() && dup) {
m_scene->clearSelection();
item->setMainSelectedClip(false);
dup->setSelected(true);
m_dragItem = dup;
m_dragItem->setMainSelectedClip(true);
emit clipItemSelected(dup, false);
}
}
} else if (itemList.at(i)->type() == GroupWidget && itemList.at(i) != m_selectionGroup) {
AbstractGroupItem *group = static_cast<AbstractGroupItem *>(itemList.at(i));
......@@ -5013,10 +4970,15 @@ void CustomTrackView::razorGroup(AbstractGroupItem* group, GenTime cutPos)
// Process the cut
for (int i = 0; i < clipsToCut.count(); ++i) {
ClipItem *clip = static_cast<ClipItem *>(clipsToCut.at(i));
new RazorClipCommand(this, clip->info(), clip->effectList(), cutPos, false, command);
ClipItem *secondClip = cutClip(clip->info(), cutPos, true);
clips1 << clip->info();
clips2 << secondClip->info();
new RazorClipCommand(this, clip->info(), clip->effectList(), cutPos, true, command);
ItemInfo info = clip->info();
info.endPos = GenTime(cutPos.frames(m_document->fps()) - 1, m_document->fps());
info.cropDuration = info.endPos - info.startPos;
ItemInfo cutInfo = info;
cutInfo.startPos = cutPos;
cutInfo.cropDuration = cutInfo.endPos - cutInfo.startPos;
clips1 << info;
clips2 << cutInfo;
}
new GroupClipsCommand(this, clips1, transitions1, true, true, command);
new GroupClipsCommand(this, clips2, transitions2, true, true, command);
......@@ -5256,11 +5218,6 @@ void CustomTrackView::addClip(const QString &clipId, ItemInfo info, EffectsList
if (refresh) {
m_document->renderer()->doRefresh();
}
//TODO: manage placeholders
/*if (!baseclip->isPlaceHolder())
m_waitingThumbs.append(item);
*/
//m_thumbsTimer.start();
}
void CustomTrackView::slotUpdateClip(const QString &clipId, bool reload)
......@@ -7180,7 +7137,6 @@ void CustomTrackView::deleteTimelineTrack(int ix, TrackInfo trackinfo)
if (selection.at(i)->type() == AVWidget) {
ClipItem *item = static_cast <ClipItem *>(selection.at(i));
new AddTimelineClipCommand(this, item->getBinId(), item->info(), item->effectList(), item->clipState(), false, true, deleteTrack);
m_waitingThumbs.removeAll(item);
m_scene->removeItem(item);
delete item;
item = NULL;
......@@ -8162,7 +8118,6 @@ void CustomTrackView::updateTrackDuration(int track, QUndoCommand *command)
void CustomTrackView::adjustEffects(ClipItem* item, ItemInfo oldInfo, QUndoCommand* command)
{
QMap<int, QDomElement> effects = item->adjustEffectsToDuration(oldInfo);
if (!effects.isEmpty()) {
QMap<int, QDomElement>::const_iterator i = effects.constBegin();
while (i != effects.constEnd()) {
......@@ -8185,7 +8140,7 @@ void CustomTrackView::slotGotFilterJobResults(const QString &/*id*/, int startPo
return;
}
QDomElement newEffect;
QDomElement effect = clip->getEffectAtIndex(clip->selectedEffectIndex());
QDomElement effect = clip->effectAtIndex(clip->selectedEffectIndex());
if (effect.attribute(QStringLiteral("id")) == extra.value(QStringLiteral("finalfilter"))) {
newEffect = effect.cloneNode().toElement();
QMap<QString, QString>::const_iterator i = filterParams.constBegin();
......
......@@ -106,7 +106,7 @@ public:
bool checkTrackHeight(bool force = false);
void updateSceneFrameWidth(bool fpsChanged = false);
void setTool(ProjectTool tool);
ClipItem *cutClip(const ItemInfo &info, const GenTime &cutTime, bool cut, const EffectsList &oldStack = EffectsList(), bool execute = true);
void cutClip(const ItemInfo &info, const GenTime &cutTime, bool cut, const EffectsList &oldStack = EffectsList(), bool execute = true);
Transition *cutTransition(const ItemInfo &info, const GenTime &cutTime, bool cut, const QDomElement &oldStack = QDomElement(), bool execute = true);
void slotSeekToPreviousSnap();
void slotSeekToNextSnap();
......@@ -439,7 +439,6 @@ private:
QList <QAction*> m_avActions;
QActionGroup *m_clipTypeGroup;
QTimer m_scrollTimer;
QTimer m_thumbsTimer;
int m_scrollOffset;
bool m_clipDrag;
......@@ -452,7 +451,6 @@ private:
/** Used to get the point in timeline where a context menu was opened */
QPoint m_menuPosition;
AbstractGroupItem *m_selectionGroup;
QList <ClipItem *> m_waitingThumbs;
int m_selectedTrack;
int m_spacerOffset;
......@@ -545,7 +543,6 @@ private slots:
void slotCheckMouseScrolling();
void slotEditTimeLineGuide();
void slotDeleteTimeLineGuide();
void slotFetchNextThumbs();
void checkTrackSequence(int track);
void slotGoToMarker(QAction *action);
/** @brief Context menu is finished, prepare resetting las known menu pos. */
......
......@@ -274,17 +274,22 @@ int Timeline::getTracks() {
Mlt::Playlist playlist(*track);
int trackduration = 0;
int audio = 0;
Track *tk = NULL;
if (!isBackgroundBlackTrack) {
audio = playlist.get_int("kdenlive:audio_track");
tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, this);
m_tracks.append(tk);
trackduration = loadTrack(i, offset, playlist);
QFrame *frame = new QFrame(headers_container);
frame->setFrameStyle(QFrame::HLine);
frame->setFixedHeight(1);
headerLayout->insertWidget(0, frame);
} else {
// Black track
tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, this);
m_tracks.append(tk);
}
offset += track->count();
Track *tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, this);
m_tracks.append(tk);
if (audio == 0 && !isBackgroundBlackTrack) {
// Check if we have a composite transition for this track
QScopedPointer<Mlt::Transition> transition(transitionHandler->getTransition(KdenliveSettings::gpu_accel() ? "movit.overlay" : "frei0r.cairoblend", i, -1, true));
......@@ -933,25 +938,49 @@ void Timeline::adjustTrackHeaders()
}
}
int Timeline::loadTrack(int ix, int offset, Mlt::Playlist &playlist) {
void Timeline::reloadTrack(int ix, int start, int end)
{
// Get playlist
Mlt::Playlist pl = m_tracks.at(ix)->playlist();
if (end == -1)
end = pl.get_length();
// Remove current clips
int startIndex = pl.get_clip_index_at(start);
int endIndex = pl.get_clip_index_at(end);
double startY = m_trackview->getPositionFromTrack(ix) + 2;
QRectF r(start, startY, end - start, 2);
QList<QGraphicsItem *> selection = m_scene->items(r);
QList<QGraphicsItem *> toDelete;
for (int i = 0; i < selection.count(); i++) {
if (selection.at(i)->type() == AVWidget)
toDelete << selection.at(i);
}
qDeleteAll(toDelete);
// Reload items
loadTrack(ix, 0, pl, startIndex, endIndex, false);
}
int Timeline::loadTrack(int ix, int offset, Mlt::Playlist &playlist, int start, int end, bool updateReferences) {
// parse track
int position = 0;
Mlt::ClipInfo *info = new Mlt::ClipInfo();
double fps = m_doc->fps();
if (end == -1)
end = playlist.count();
bool locked = playlist.get_int("kdenlive:locked_track") == 1;
for(int i = 0; i < playlist.count(); ++i) {
for(int i = start; i < end; ++i) {
emit loadingBin(offset + i + 1);
QScopedPointer<Mlt::Producer> clip(playlist.get_clip(i));
if (clip->is_blank()) {
position += clip->get_playtime();
if (playlist.is_blank(i)) {
continue;
}
playlist.clip_info(i, info);
Mlt::Producer *clip = info->cut;
// Found a clip
int in = clip->get_in();
int out = clip->get_out();
QString idString = clip->parent().get("id");
int in = info->frame_in;
int out = info->frame_out;
QString idString = info->producer->get("id");
if (in > out || m_invalidProducers.contains(idString)) {
QString trackName = playlist.get("kdenlive:track_name");
m_documentErrors.append(i18n("Invalid clip removed from track %1 at %2\n", trackName.isEmpty() ? QString::number(ix) : trackName, position));
m_documentErrors.append(i18n("Invalid clip removed from track %1 at %2\n", trackName.isEmpty() ? QString::number(ix) : trackName, info->start));
playlist.remove(i);
--i;
continue;
......@@ -989,17 +1018,16 @@ int Timeline::loadTrack(int ix, int offset, Mlt::Playlist &playlist) {
// Warning, unknown clip found, timeline corruption!!
//TODO: fix this
qDebug()<<"* * * * *UNKNOWN CLIP, WE ARE DEAD: "<<id;
position += length;
continue;
}
binclip->addRef();
if (updateReferences)
binclip->addRef();
ItemInfo clipinfo;
clipinfo.startPos = GenTime(position, fps);
clipinfo.endPos = GenTime(position + length, fps);
clipinfo.startPos = GenTime(info->start, fps);
clipinfo.endPos = GenTime(info->start + length, fps);
clipinfo.cropStart = GenTime(in, fps);
clipinfo.cropDuration = GenTime(length, fps);
clipinfo.track = ix;
position += length;
//qDebug()<<"// Loading clip: "<<idString<<" / SPEED: "<<speed<<"\n++++++++++++++++++++++++";
ClipItem *item = new ClipItem(binclip, clipinfo, fps, slowInfo.speed, slowInfo.strobe, m_trackview->getFrameWidth(), true);
connect(item, &AbstractClipItem::selectItem, m_trackview, &CustomTrackView::slotSelectItem);
......@@ -1017,7 +1045,8 @@ int Timeline::loadTrack(int ix, int offset, Mlt::Playlist &playlist) {
// parse clip effects
getEffects(*clip, item);
}
return position;
delete info;
return playlist.get_length();
}
void Timeline::loadGuides(QMap <double, QString> guidesData)
......
......@@ -161,6 +161,7 @@ public:
int getLowestVideoTrack();
/** @brief Returns the document properties with some added values from timeline. */
QMap <QString, QString> documentProperties();
void reloadTrack(int ix, int start = 0, int end = -1);
protected:
void keyPressEvent(QKeyEvent * event);
......@@ -201,7 +202,7 @@ private:
void adjustTrackHeaders();
void parseDocument(const QDomDocument &doc);
int loadTrack(int ix, int offset, Mlt::Playlist &playlist);
int loadTrack(int ix, int offset, Mlt::Playlist &playlist, int start = 0, int end = -1, bool updateReferences = true);
void getEffects(Mlt::Service &service, ClipItem *clip, int track = 0);
void adjustDouble(QDomElement &e, const QString &value);
......
......@@ -23,6 +23,8 @@
#include "track.h"
#include "headertrack.h"
#include "kdenlivesettings.h"
#include "clip.h"
#include <QtGlobal>
#include <QDebug>
......@@ -133,7 +135,7 @@ bool Track::move(qreal start, qreal end, TimelineMode::EditMode mode)
bool result = doAdd(end, clipProducer.data(), mode);
m_playlist.unlock();
if (durationChanged) {
emit newTrackDuration(m_playlist.get_playtime());