From: Jean-Baptiste Mardelle Date: Wed, 16 Jul 2008 22:17:07 +0000 (+0000) Subject: * new: crash recovery feature X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=a6d4ef775d1459f868b03d444bfe5d1d23208291;p=kdenlive * new: crash recovery feature * fix project file corruption when the same clip was inserted several time svn path=/branches/KDE4/; revision=2319 --- diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 778d8075..0e48dfaf 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -932,8 +932,11 @@ void CustomTrackView::dropEvent(QDropEvent * event) { m_commandStack->push(command); m_dropItem->baseClip()->addReference(); m_document->updateClip(m_dropItem->baseClip()->getId()); + ItemInfo info; + info = m_dropItem->info(); + info.track = m_tracksList.count() - m_dropItem->track(); // kDebug()<<"IIIIIIIIIIIIIIIIIIIIIIII TRAX CNT: "<track(); - m_document->renderer()->mltInsertClip(m_tracksList.count() - m_dropItem->track(), m_dropItem->startPos(), m_dropItem->cropStart(), m_dropItem->xml()); + m_document->renderer()->mltInsertClip(info, m_dropItem->xml()); m_document->setModified(true); } else QGraphicsView::dropEvent(event); m_dropItem = NULL; @@ -1125,7 +1128,9 @@ void CustomTrackView::mouseReleaseEvent(QMouseEvent * event) { if (item->type() == AVWIDGET) { ClipItem *clip = static_cast (item); new AddTimelineClipCommand(this, clip->xml(), clip->clipProducer(), item->info(), false, false, moveClips); - m_document->renderer()->mltInsertClip(m_tracksList.count() - item->track(), item->startPos(), item->cropStart(), clip->xml()); + ItemInfo info = item->info(); + info.track = m_tracksList.count() - item->track(); + m_document->renderer()->mltInsertClip(info, clip->xml()); } else { Transition *tr = static_cast (item); ItemInfo transitionInfo = tr->info(); @@ -1257,10 +1262,10 @@ void CustomTrackView::deleteSelectedClips() { deleteSelected->setText("Delete selected items"); for (int i = 0; i < itemList.count(); i++) { if (itemList.at(i)->type() == AVWIDGET) { - ClipItem *item = static_cast (itemList.at(i)); + ClipItem *item = static_cast (itemList.at(i)); new AddTimelineClipCommand(this, item->xml(), item->clipProducer(), item->info(), true, true, deleteSelected); } else if (itemList.at(i)->type() == TRANSITIONWIDGET) { - Transition *item = static_cast (itemList.at(i)); + Transition *item = static_cast (itemList.at(i)); ItemInfo info; info.startPos = item->startPos(); info.endPos = item->endPos(); @@ -1295,7 +1300,8 @@ void CustomTrackView::addClip(QDomElement xml, int clipId, ItemInfo info) { scene()->addItem(item); baseclip->addReference(); m_document->updateClip(baseclip->getId()); - m_document->renderer()->mltInsertClip(m_tracksList.count() - info.track, info.startPos, info.cropStart, xml); + info.track = m_tracksList.count() - info.track; + m_document->renderer()->mltInsertClip(info, xml); m_document->renderer()->doRefresh(); } @@ -1307,7 +1313,9 @@ void CustomTrackView::slotUpdateClip(int clipId) { clip = static_cast (list.at(i)); if (clip->clipProducer() == clipId) { clip->refreshClip(); - m_document->renderer()->mltUpdateClip(m_tracksList.count() - clip->track(), clip->startPos(), clip->cropStart(), clip->xml()); + ItemInfo info = clip->info(); + info.track = m_tracksList.count() - clip->track(); + m_document->renderer()->mltUpdateClip(info, clip->xml()); } } } @@ -1725,6 +1733,7 @@ void CustomTrackView::editGuide(const GenTime oldPos, const GenTime pos, const Q } if (!found) emit displayMessage(i18n("No guide at cursor time"), ErrorMessage); } + m_document->syncGuides(m_guides); } bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) { @@ -1737,6 +1746,7 @@ bool CustomTrackView::addGuide(const GenTime pos, const QString &comment) { Guide *g = new Guide(this, pos, comment, m_scale, m_document->fps(), m_tracksHeight * m_tracksList.count()); scene()->addItem(g); m_guides.append(g); + m_document->syncGuides(m_guides); return true; } @@ -1859,19 +1869,6 @@ void CustomTrackView::drawBackground(QPainter * painter, const QRectF & rect) { painter->fillRect(QRectF(rectInView.left(), lowerLimit, rectInView.width(), height() - lowerLimit), QBrush(base)); } -QDomElement CustomTrackView::xmlInfo() { - QDomDocument doc; - QDomElement e; - QDomElement guides = doc.createElement("guides"); - for (int i = 0; i < m_guides.count(); i++) { - e = doc.createElement("guide"); - e.setAttribute("time", m_guides.at(i)->position().ms() / 1000); - e.setAttribute("comment", m_guides.at(i)->label()); - guides.appendChild(e); - } - return guides; -} - bool CustomTrackView::findString(const QString &text) { QString marker; for (int i = 0; i < m_searchPoints.size(); ++i) { diff --git a/src/customtrackview.h b/src/customtrackview.h index 1ed4541d..1cbdca00 100644 --- a/src/customtrackview.h +++ b/src/customtrackview.h @@ -84,7 +84,6 @@ public: void slotSeekToPreviousSnap(); void slotSeekToNextSnap(); double getSnapPointForPos(double pos); - QDomElement xmlInfo(); void editKeyFrame(const GenTime pos, const int track, const int index, const QString keyframes); bool findString(const QString &text); bool findNextString(const QString &text); diff --git a/src/kdenlivedoc.cpp b/src/kdenlivedoc.cpp index c9b8be8f..3bebe75a 100644 --- a/src/kdenlivedoc.cpp +++ b/src/kdenlivedoc.cpp @@ -36,6 +36,7 @@ #include "titlewidget.h" #include "mainwindow.h" + KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, MltVideoProfile profile, QUndoGroup *undoGroup, MainWindow *parent): QObject(parent), m_render(NULL), m_url(url), m_projectFolder(projectFolder), m_profile(profile), m_fps((double)profile.frame_rate_num / profile.frame_rate_den), m_width(profile.width), m_height(profile.height), m_commandStack(new KUndoStack(undoGroup)), m_modified(false), m_documentLoadingProgress(0), m_documentLoadingStep(0.0), m_startPos(0) { kDebug() << "// init profile, ratnum: " << profile.frame_rate_num << ", " << profile.frame_rate_num << ", width: " << profile.width; m_clipManager = new ClipManager(this); @@ -199,11 +200,44 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, MltVideoPro kDebug() << "KDEnnlive document, init timecode: " << m_fps; if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true); else m_timecode.setFormat((int) m_fps); + + m_autoSaveTimer = new QTimer(this); + m_autoSaveTimer->setSingleShot(true); + QString directory = m_url.directory(); + QString fileName = m_url.fileName(); + m_recoveryUrl.setDirectory(directory); + m_recoveryUrl.setFileName("~" + fileName); + connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); } KdenliveDoc::~KdenliveDoc() { delete m_commandStack; delete m_clipManager; + delete m_autoSaveTimer; + if (!m_url.isEmpty()) { + // remove backup file + if (KIO::NetAccess::exists(m_recoveryUrl, KIO::NetAccess::SourceSide, NULL)) + KIO::NetAccess::del(m_recoveryUrl, NULL); + } +} + +void KdenliveDoc::syncGuides(QList guides) { + QDomDocument doc; + QDomElement e; + m_guidesXml.clear(); + m_guidesXml = doc.createElement("guides"); + for (int i = 0; i < guides.count(); i++) { + e = doc.createElement("guide"); + e.setAttribute("time", guides.at(i)->position().ms() / 1000); + e.setAttribute("comment", guides.at(i)->label()); + m_guidesXml.appendChild(e); + } +} + +void KdenliveDoc::slotAutoSave() { + if (m_render) + m_render->saveSceneList(m_recoveryUrl.path(), documentInfoXml()); + } void KdenliveDoc::convertDocument(double version) { @@ -313,7 +347,7 @@ void KdenliveDoc::convertDocument(double version) { //kDebug() << "///////////////// END CONVERTED DOC:"; } -QDomElement KdenliveDoc::documentInfoXml(QDomElement timelineInfo) { +QDomElement KdenliveDoc::documentInfoXml() { QDomDocument doc; QDomElement e; QDomElement addedXml = doc.createElement("kdenlivedoc"); @@ -336,7 +370,7 @@ QDomElement KdenliveDoc::documentInfoXml(QDomElement timelineInfo) { } } addedXml.appendChild(markers); - addedXml.appendChild(doc.importNode(timelineInfo, true)); + if (!m_guidesXml.isNull()) addedXml.appendChild(doc.importNode(m_guidesXml, true)); //kDebug() << m_document.toString(); return addedXml; } @@ -494,9 +528,16 @@ KUrl KdenliveDoc::url() const { void KdenliveDoc::setUrl(KUrl url) { m_url = url; + QString directory = m_url.directory(); + QString fileName = m_url.fileName(); + m_recoveryUrl.setDirectory(directory); + m_recoveryUrl.setFileName("~" + fileName); } void KdenliveDoc::setModified(bool mod) { + if (!m_url.isEmpty() && mod && KdenliveSettings::crashrecovery()) { + m_autoSaveTimer->start(3000); + } if (mod == m_modified) return; m_modified = mod; emit docModified(m_modified); diff --git a/src/kdenlivedoc.h b/src/kdenlivedoc.h index 084b92d6..d2102c6e 100644 --- a/src/kdenlivedoc.h +++ b/src/kdenlivedoc.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ #include "gentime.h" #include "timecode.h" #include "definitions.h" +#include "guide.h" class Render; class ClipManager; @@ -59,6 +61,7 @@ Q_OBJECT public: void setProducerDuration(int id, int duration); int getProducerDuration(int id); Render *renderer(); + QDomElement m_guidesXml; ClipManager *clipManager(); void addClip(const QDomElement &elem, const int clipId); void addFolder(const QString foldername, int clipId, bool edit); @@ -84,7 +87,7 @@ Q_OBJECT public: /** Returns the document format: PAL or NTSC */ QString getDocumentStandard(); void setUrl(KUrl url); - QDomElement documentInfoXml(QDomElement timelineInfo); + QDomElement documentInfoXml(); void setProfilePath(QString path); /** Set to true if document needs saving, false otherwise */ void setModified(bool mod); @@ -96,9 +99,11 @@ Q_OBJECT public: /** Used to inform main app of the current document loading progress */ void loadingProgressed(); void updateAllProjectClips(); + void syncGuides(QList guides); private: KUrl m_url; + KUrl m_recoveryUrl; QDomDocument m_document; QString m_projectName; double m_fps; @@ -113,6 +118,7 @@ private: ClipManager *m_clipManager; MltVideoProfile m_profile; QString m_scenelist; + QTimer *m_autoSaveTimer; /** tells whether current doc has been changed since last save event */ bool m_modified; /** Project folder, used to store project files (titles, effects,...) */ @@ -124,6 +130,9 @@ private: public slots: void slotCreateTextClip(QString group, int groupId); +private slots: + void slotAutoSave(); + signals: void addProjectClip(DocClipBase *); void addProjectFolder(const QString, int, bool, bool edit = false); diff --git a/src/kdenlivesettings.kcfg b/src/kdenlivesettings.kcfg index c4a8bec3..78f42ea3 100644 --- a/src/kdenlivesettings.kcfg +++ b/src/kdenlivesettings.kcfg @@ -9,6 +9,11 @@ false + + + true + + 00:00:05:00 diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2c58bf9d..c3cdefbd 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include @@ -280,6 +281,7 @@ bool MainWindow::queryClose() { switch (KMessageBox::warningYesNoCancel(this, i18n("Save changes to document ?"))) { case KMessageBox::Yes : // save document here. If saving fails, return false; + saveFile(); return true; case KMessageBox::No : return true; @@ -750,7 +752,7 @@ void MainWindow::slotRemoveTab() { } void MainWindow::saveFileAs(const QString &outputFileName) { - m_projectMonitor->saveSceneList(outputFileName, m_activeDocument->documentInfoXml(m_activeTimeline->projectView()->xmlInfo())); + m_projectMonitor->saveSceneList(outputFileName, m_activeDocument->documentInfoXml()); m_activeDocument->setUrl(KUrl(outputFileName)); setCaption(m_activeDocument->description()); m_timelineArea->setTabText(m_timelineArea->currentIndex(), m_activeDocument->description()); @@ -776,7 +778,7 @@ void MainWindow::saveFile() { } } -void MainWindow::openFile() { //changed +void MainWindow::openFile() { KUrl url = KFileDialog::getOpenUrl(KUrl(), "*.kdenlive|Kdenlive project files (*.kdenlive)\n*.westley|MLT project files (*.westley)"); if (url.isEmpty()) return; m_fileOpenRecent->addUrl(url); @@ -789,11 +791,32 @@ void MainWindow::openLastFile() { openFile(KUrl(Lastproject)); } -void MainWindow::openFile(const KUrl &url) { //new +void MainWindow::openFile(const KUrl &url) { + // Check for backup file + bool recovery = false; + QString directory = url.directory(); + QString fileName = url.fileName(); + KUrl recoveryUrl; + recoveryUrl.setDirectory(directory); + recoveryUrl.setFileName("~" + fileName); + if (KIO::NetAccess::exists(recoveryUrl, KIO::NetAccess::SourceSide, this)) { + KFileItem bkup(KFileItem::Unknown, KFileItem::Unknown, recoveryUrl, true); + KFileItem src(KFileItem::Unknown, KFileItem::Unknown, url, true); + if (bkup.time(KFileItem::ModificationTime) > src.time(KFileItem::ModificationTime)) { + // Backup file is more recent than source file, ask user for recovery + if (KMessageBox::questionYesNo(this, i18n("A newer recovery file exists for %1\nOpen recovery file ?", url.fileName())) == KMessageBox::Yes) recovery = true; + } + } + //TODO: get video profile from url before opening it MltVideoProfile prof = ProfilesDialog::getVideoProfile(KdenliveSettings::default_profile()); if (prof.width == 0) prof = ProfilesDialog::getVideoProfile("dv_pal"); - KdenliveDoc *doc = new KdenliveDoc(url, KUrl(), prof, m_commandStack, this); + KdenliveDoc *doc; + if (recovery) { + doc = new KdenliveDoc(recoveryUrl, KUrl(), prof, m_commandStack, this); + doc->setUrl(url); + doc->setModified(true); + } else doc = new KdenliveDoc(url, KUrl(), prof, m_commandStack, this); connectDocumentInfo(doc); TrackView *trackView = new TrackView(doc, this); m_timelineArea->setCurrentIndex(m_timelineArea->addTab(trackView, KIcon("kdenlive"), doc->description())); diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 899b41f3..af0fddf3 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -310,9 +310,13 @@ void ProjectList::slotUpdateClip(int id) { void ProjectList::slotAddClip(QUrl givenUrl, QString group) { if (!m_commandStack) kDebug() << "!!!!!!!!!!!!!!!!  NO CMD STK"; KUrl::List list; - if (givenUrl.isEmpty()) - list = KFileDialog::getOpenUrls(KUrl(), "application/vnd.kde.kdenlive application/vnd.westley.scenelist application/flv application/vnd.rn-realmedia video/x-dv video/x-msvideo video/mpeg video/x-ms-wmv audio/mpeg audio/x-mp3 audio/x-wav application/ogg *.m2t *.mts *.dv video/mp4 video/quicktime image/gif image/jpeg image/png image/x-bmp image/svg+xml image/tiff image/x-xcf-gimp image/x-vnd.adobe.photoshop image/x-pcx image/x-exr"); - else list.append(givenUrl); + if (givenUrl.isEmpty()) { + KFileDialog d(KUrl("kfiledialog:///clipfolder"), "application/x-kdenlive application/flv application/vnd.rn-realmedia video/x-dv video/x-msvideo video/mpeg video/x-ms-wmv audio/mpeg audio/x-mp3 audio/x-wav application/ogg video/mp4 video/quicktime image/gif image/jpeg image/png image/x-bmp image/svg+xml image/tiff image/x-xcf-gimp image/x-vnd.adobe.photoshop image/x-pcx image/x-exr", this); + d.setFilter(d.currentFilter() + "\n*.m2t *.mts|HDV video\n*.dv|DV video"); + if (d.exec() == QDialog::Accepted) + list = d.selectedUrls(); + /*list = KFileDialog::getOpenUrls(KUrl("kfiledialog:///clipfolder"), "application/vnd.kde.kdenlive application/vnd.westley.scenelist application/flv application/vnd.rn-realmedia video/x-dv video/x-msvideo video/mpeg video/x-ms-wmv audio/mpeg audio/x-mp3 audio/x-wav application/ogg video/mp4 video/quicktime image/gif image/jpeg image/png image/x-bmp image/svg+xml image/tiff image/x-xcf-gimp image/x-vnd.adobe.photoshop image/x-pcx image/x-exr\n*.m2t *.mts|HDV video\n*.dv|DV video");*/ + } else list.append(givenUrl); if (list.isEmpty()) return; KUrl::List::Iterator it; int groupId = -1; diff --git a/src/renderer.cpp b/src/renderer.cpp index 533b31dd..6e0f198e 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -121,6 +121,7 @@ void Render::closeMlt() { delete m_mltConsumer; if (m_mltProducer) delete m_mltProducer; + while (! m_producersList.isEmpty()) delete m_producersList.takeFirst(); //delete m_osdInfo; } @@ -161,6 +162,7 @@ int Render::resetProfile(QString profile) { Mlt::Producer *producer = new Mlt::Producer(*m_mltProfile , "westley-xml", tmp); delete[] tmp; m_mltProducer = producer; + m_mltProducer->optimise(); m_mltProducer->set_speed(0); connectPlaylist(); @@ -382,29 +384,35 @@ void Render::getFileProperties(const QDomElement &xml, int clipId) { QMap < QString, QString > metadataPropertyMap; KUrl url = KUrl(xml.attribute("resource", QString::null)); + bool newProducer = false; + + Mlt::Producer *producer = getProducerById(QString::number(clipId)); + if (producer == NULL) { + if (url.isEmpty()) { + QDomDocument doc; + QDomElement westley = doc.createElement("westley"); + QDomElement play = doc.createElement("playlist"); + doc.appendChild(westley); + westley.appendChild(play); + play.appendChild(doc.importNode(xml, true)); + char *tmp = decodedString(doc.toString()); + producer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp); + delete[] tmp; + } else { + char *tmp = decodedString(url.path()); + producer = new Mlt::Producer(*m_mltProfile, tmp); + delete[] tmp; + } - Mlt::Producer *producer; - - if (url.isEmpty()) { - QDomDocument doc; - QDomElement westley = doc.createElement("westley"); - QDomElement play = doc.createElement("playlist"); - doc.appendChild(westley); - westley.appendChild(play); - play.appendChild(doc.importNode(xml, true)); - char *tmp = decodedString(doc.toString()); - producer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp); - delete[] tmp; - } else { - char *tmp = decodedString(url.path()); - producer = new Mlt::Producer(*m_mltProfile, tmp); - delete[] tmp; + if (producer->is_blank()) { + kDebug() << " / / / / / / / /ERRROR / / / / // CANNOT LOAD PRODUCER: "; + return; + } + m_producersList.append(producer); + newProducer = true; } - if (producer->is_blank()) { - kDebug() << " / / / / / / / /ERRROR / / / / // CANNOT LOAD PRODUCER: "; - return; - } + int frameNumber = xml.attribute("thumbnail", "0").toInt(); if (frameNumber != 0) producer->seek(frameNumber); @@ -508,7 +516,7 @@ void Render::getFileProperties(const QDomElement &xml, int clipId) { emit replyGetFileProperties(clipId, filePropertyMap, metadataPropertyMap); kDebug() << "REquested fuile info for: " << url.path(); if (frame) delete frame; - if (producer) delete producer; + if (!newProducer && producer) delete producer; } /** Create the producer from the Westley QDomDocument */ @@ -585,7 +593,7 @@ void Render::setSceneList(QString playlist, int position) { m_mltProducer = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp); delete[] tmp; if (!m_mltProducer || !m_mltProducer->is_valid()) kDebug() << " WARNING - - - - -INVALID PLAYLIST: " << tmp; - //m_mltProducer->optimise(); + m_mltProducer->optimise(); /*if (KdenliveSettings::osdtimecode()) { // Attach filter for on screen display of timecode @@ -645,6 +653,7 @@ void Render::saveSceneList(QString path, QDomElement kdenliveData) { char *tmppath = decodedString("westley:" + path); Mlt::Consumer westleyConsumer(*m_mltProfile , tmppath); + m_mltProducer->optimise(); delete[] tmppath; westleyConsumer.set("terminate_on_pause", 1); Mlt::Producer prod(m_mltProducer->get_producer()); @@ -682,6 +691,7 @@ void Render::connectPlaylist() { m_mltConsumer->connect(*m_mltProducer); m_mltProducer->set_speed(0); m_mltConsumer->start(); + parsePlaylistForClips(); emit durationChanged(m_mltProducer->get_playtime()); //refresh(); /* @@ -1029,23 +1039,26 @@ void Render::mltCheckLength(bool reload) { black.setAttribute("mlt_service", "colour"); black.setAttribute("colour", "black"); black.setAttribute("id", "black"); - black.setAttribute("in", "0"); - black.setAttribute("out", "13999"); + ItemInfo info; + info.track = 0; while (dur > 14000) { - mltInsertClip(0, GenTime(i * 14000, m_fps), GenTime(), black); + info.startPos = GenTime(i * 14000, m_fps); + info.endPos = info.startPos + GenTime(13999, m_fps); + mltInsertClip(info, black); dur = dur - 14000; i++; } if (dur > 0) { - black.setAttribute("out", QString::number(dur)); - mltInsertClip(0, GenTime(i * 14000, m_fps), GenTime(), black); + info.startPos = GenTime(i * 14000, m_fps); + info.endPos = info.startPos + GenTime(dur, m_fps); + mltInsertClip(info, black); } m_mltProducer->set("out", duration); emit durationChanged((int)duration); } } -void Render::mltInsertClip(int track, GenTime position, GenTime crop, QDomElement element) { +void Render::mltInsertClip(ItemInfo info, QDomElement element) { if (!m_mltProducer) { kDebug() << "PLAYLIST NOT INITIALISED //////"; return; @@ -1059,24 +1072,68 @@ void Render::mltInsertClip(int track, GenTime position, GenTime crop, QDomElemen Mlt::Service service(parentProd.get_service()); Mlt::Tractor tractor(service); mlt_service_lock(service.get_service()); - Mlt::Producer trackProducer(tractor.track(track)); + Mlt::Producer trackProducer(tractor.track(info.track)); Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); - QDomDocument doc; - doc.appendChild(doc.importNode(element, true)); - QString resource = doc.toString(); - char *tmp = decodedString(resource); - Mlt::Producer clip(*m_mltProfile, "westley-xml", tmp); - clip.set("in", crop.frames(m_fps)); - //clip.set_in_and_out(in.frames(m_fps), out.frames(m_fps)); - delete[] tmp; - trackPlaylist.insert_at((int) position.frames(m_fps), clip, 1); + Mlt::Producer *prod = getProducerById(element.attribute("id")); + if (prod == NULL) { + // clip was never used yet + QDomDocument doc; + doc.appendChild(doc.importNode(element, true)); + QString resource = doc.toString(); + kDebug() << "// INSERTING CLIP: " << resource; + char *tmp = decodedString(resource); + prod = new Mlt::Producer(*m_mltProfile, "westley-xml", tmp); + delete[] tmp; + m_producersList.append(prod); + } + + Mlt::Producer *clip = prod->cut(info.cropStart.frames(m_fps), (info.endPos - info.startPos).frames(m_fps)); + trackPlaylist.insert_at((int) info.startPos.frames(m_fps), *clip, 1); + mlt_service_unlock(service.get_service()); - if (track != 0) mltCheckLength(); + + if (info.track != 0) mltCheckLength(); //tractor.multitrack()->refresh(); //tractor.refresh(); } +Mlt::Producer *Render::getProducerById(const QString &id) { + for (int i = 0; i < m_producersList.count(); i++) { + if (m_producersList.at(i)->get("id") == id) return m_producersList.at(i); + } + return NULL; +} + +void Render::parsePlaylistForClips() { + // clear current producers list + while (! m_producersList.isEmpty()) delete m_producersList.takeFirst(); + + //parse entire playlists to find all the different clips + Mlt::Producer parentProd(m_mltProducer->parent()); + if (parentProd.get_producer() == NULL) { + kDebug() << "PLAYLIST BROKEN, CANNOT INSERT CLIP //////"; + return; + } + Mlt::Service service(parentProd.get_service()); + if (service.type() != tractor_type) return; + Mlt::Tractor tractor(service); + mlt_service_lock(service.get_service()); + for (int i = 0; i < tractor.count(); i++) { + Mlt::Producer trackProducer(tractor.track(i)); + Mlt::Playlist trackPlaylist((mlt_playlist) trackProducer.get_service()); + for (int j = 0; j < trackPlaylist.count(); j++) { + if (!trackPlaylist.is_blank(j)) { + Mlt::Producer *clip = trackPlaylist.get_clip(j); + if (clip) { + if (getProducerById(clip->get("id")) == NULL) + m_producersList.append(new Mlt::Producer(clip->get_parent())); + } + } + } + } +} + void Render::mltCutClip(int track, GenTime position) { m_isBlocked = true; @@ -1091,10 +1148,10 @@ void Render::mltCutClip(int track, GenTime position) { m_isBlocked = false; } -void Render::mltUpdateClip(int track, GenTime position, GenTime crop, QDomElement element) { +void Render::mltUpdateClip(ItemInfo info, QDomElement element) { // TODO: optimize - mltRemoveClip(track, position); - mltInsertClip(track, position, crop, element); + mltRemoveClip(info.track, info.startPos); + mltInsertClip(info, element); } @@ -1575,7 +1632,7 @@ void Render::mltUpdateTransition(QString oldTag, QString tag, int a_track, int b mltDeleteTransition(oldTag, a_track, b_track, in, out, xml, false); mltAddTransition(tag, a_track, b_track, in, out, xml); } - mltSavePlaylist(); + //mltSavePlaylist(); } void Render::mltUpdateTransitionParams(QString type, int a_track, int b_track, GenTime in, GenTime out, QDomElement xml) { diff --git a/src/renderer.h b/src/renderer.h index 979ab46a..324a20d2 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -27,9 +27,7 @@ #include #include "gentime.h" -/*#include "docclipref.h" -#include "effectdesc.h" -#include "effectparamdescfactory.h"*/ +#include "definitions.h" /**Render encapsulates the client side of the interface to a renderer. From Kdenlive's point of view, you treat the Render object as the @@ -149,8 +147,8 @@ Q_OBJECT public: const double dar() const; /** Playlist manipulation */ - void mltInsertClip(int track, GenTime position, GenTime crop, QDomElement element); - void mltUpdateClip(int track, GenTime position, GenTime crop, QDomElement element); + void mltInsertClip(ItemInfo info, QDomElement element); + void mltUpdateClip(ItemInfo info, QDomElement element); void mltCutClip(int track, GenTime position); void mltResizeClipEnd(int track, GenTime pos, GenTime in, GenTime out); void mltResizeClipStart(int track, GenTime pos, GenTime moveEnd, GenTime moveStart, GenTime in, GenTime out); @@ -182,6 +180,9 @@ private: // Private attributes & methods uint m_monitorId; bool m_generateScenelist; + QList m_producersList; + Mlt::Producer *getProducerById(const QString &id); + void parsePlaylistForClips(); /** Holds the path to on screen display profile */ QString m_osdProfile; diff --git a/src/renderwidget.cpp b/src/renderwidget.cpp index 793bf92d..7034ed19 100644 --- a/src/renderwidget.cpp +++ b/src/renderwidget.cpp @@ -161,7 +161,7 @@ void RenderWidget::slotEditProfile() { ui.profile_name->setFocus(); if (d->exec() == QDialog::Accepted) { - slotDeleteProfile(); + slotDeleteProfile(); QString exportFile = KStandardDirs::locateLocal("data", "kdenlive/export/customprofiles.xml"); QDomDocument doc; QFile file(exportFile); @@ -319,12 +319,11 @@ void RenderWidget::refreshParams() { } if (item->data(EditableRole).toString().isEmpty()) { - m_view.buttonDelete->setEnabled(false); - m_view.buttonEdit->setEnabled(false); - } - else { - m_view.buttonDelete->setEnabled(true); - m_view.buttonEdit->setEnabled(true); + m_view.buttonDelete->setEnabled(false); + m_view.buttonEdit->setEnabled(false); + } else { + m_view.buttonDelete->setEnabled(true); + m_view.buttonEdit->setEnabled(true); } } diff --git a/src/trackview.cpp b/src/trackview.cpp index 32c52b0f..d2da5574 100644 --- a/src/trackview.cpp +++ b/src/trackview.cpp @@ -343,7 +343,7 @@ int TrackView::slotAddProjectTrack(int ix, QDomElement xml, bool videotrack) { ItemInfo clipinfo; clipinfo.startPos = GenTime(position, m_doc->fps()); clipinfo.endPos = clipinfo.startPos + GenTime(out - in, m_doc->fps()); - clipinfo.cropStart = GenTime(in, m_doc->fps()); + clipinfo.cropStart = GenTime(in, m_doc->fps()); clipinfo.track = ix; //kDebug() << "// INSERTING CLIP: " << in << "x" << out << ", track: " << ix << ", ID: " << id << ", SCALE: " << m_scale << ", FPS: " << m_doc->fps(); ClipItem *item = new ClipItem(clip, clipinfo, m_scale, m_doc->fps()); diff --git a/src/widgets/configmisc_ui.ui b/src/widgets/configmisc_ui.ui index f9bc4725..4a32b418 100644 --- a/src/widgets/configmisc_ui.ui +++ b/src/widgets/configmisc_ui.ui @@ -6,11 +6,11 @@ 0 0 369 - 258 + 285 - + Default Durations @@ -50,7 +50,7 @@ - + Default Profile @@ -136,7 +136,7 @@ - + Qt::Vertical @@ -156,6 +156,16 @@ + + + + Crash recovery (automatic backup) + + + true + + +