From 5a403d4a2689486dbdef95fb4c529a44636e8753 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Sat, 22 Oct 2011 16:56:43 +0000 Subject: [PATCH] Try to fix the concurrency issues causing crash in the avformat producer svn path=/trunk/kdenlive/; revision=5976 --- src/customtrackview.cpp | 5 +--- src/docclipbase.cpp | 19 +++++++++++++++ src/docclipbase.h | 2 ++ src/kthumb.cpp | 9 ++++---- src/mainwindow.cpp | 32 +++++++++++++++----------- src/mainwindow.h | 4 ++-- src/monitor.cpp | 21 +++++++++++++---- src/monitor.h | 4 +++- src/projectlist.cpp | 51 +++++++++++++++++++++-------------------- src/projectlist.h | 6 ++++- src/renderer.cpp | 49 ++++++++++++++++++++++++++++++--------- src/renderer.h | 8 +++---- 12 files changed, 140 insertions(+), 70 deletions(-) diff --git a/src/customtrackview.cpp b/src/customtrackview.cpp index 428612df..f00f7ad6 100644 --- a/src/customtrackview.cpp +++ b/src/customtrackview.cpp @@ -4200,12 +4200,9 @@ void CustomTrackView::slotUpdateClip(const QString &clipId, bool reload) } } } - m_document->renderer()->unlockService(tractor); for (int i = 0; i < clipList.count(); i++) clipList.at(i)->refreshClip(true, true); - if (baseClip) { - baseClip->cleanupProducers(); - } + m_document->renderer()->unlockService(tractor); } ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track) diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index 171392dd..68ab9056 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -624,6 +624,25 @@ Mlt::Producer *DocClipBase::videoProducer() return m_videoOnlyProducer; } +Mlt::Producer *DocClipBase::getCloneProducer(Mlt::Producer *source) +{ + QMutexLocker locker(&m_producerMutex); + if (source == NULL) { + for (int i = 0; i < m_baseTrackProducers.count(); i++) { + if (m_baseTrackProducers.at(i) != NULL) { + source = m_baseTrackProducers.at(i); + break; + } + } + } + if (source) { + Mlt::Producer *prod = cloneProducer(source); + adjustProducerProperties(prod, getId() + "_monitor", false, false); + return prod; + } + return NULL; +} + Mlt::Producer *DocClipBase::getProducer(int track) { QMutexLocker locker(&m_producerMutex); diff --git a/src/docclipbase.h b/src/docclipbase.h index edccd3c4..9d8a59b4 100644 --- a/src/docclipbase.h +++ b/src/docclipbase.h @@ -120,6 +120,8 @@ Q_OBJECT public: void setProducer(Mlt::Producer *producer, bool reset = false, bool readPropertiesFromProducer = false); /** Retrieve a producer for a track */ Mlt::Producer *getProducer(int track = -1); + /** Get a copy of the producer, for use in the clip monitor */ + Mlt::Producer *getCloneProducer(Mlt::Producer *source = NULL); /** Retrieve the producer that shows only video */ Mlt::Producer *videoProducer(); /** Retrieve the producer that shows only audio */ diff --git a/src/kthumb.cpp b/src/kthumb.cpp index ac232e66..71f2bfc9 100644 --- a/src/kthumb.cpp +++ b/src/kthumb.cpp @@ -222,13 +222,14 @@ QImage KThumb::getFrame(Mlt::Frame *frame, int frameWidth, int displayWidth, int int ow = frameWidth; int oh = height; mlt_image_format format = mlt_image_rgb24a; - uint8_t *data = frame->get_image(format, ow, oh, 0); - QImage image((uchar *)data, ow, oh, QImage::Format_ARGB32_Premultiplied); + + const uchar* imagedata = frame->get_image(format, ow, oh); + QImage image(imagedata, ow, oh, QImage::Format_ARGB32_Premultiplied); + if (!image.isNull()) { if (ow > (2 * displayWidth)) { // there was a scaling problem, do it manually - QImage scaled = image.scaled(displayWidth, height); - image = scaled.rgbSwapped(); + image = image.scaled(displayWidth, height).rgbSwapped(); } else { image = image.scaled(displayWidth, height, Qt::IgnoreAspectRatio).rgbSwapped(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 30616e1c..0c4376c5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -208,7 +208,8 @@ MainWindow::MainWindow(const QString &MltPath, const KUrl & Url, const QString & m_clipMonitorDock->setObjectName("clip_monitor"); m_clipMonitor = new Monitor("clip", m_monitorManager, QString(), m_timelineArea); m_clipMonitorDock->setWidget(m_clipMonitor); - connect(m_projectList, SIGNAL(clipSelected(DocClipBase *, QPoint)), m_clipMonitor, SLOT(slotSetXml(DocClipBase *, QPoint))); + connect(m_projectList, SIGNAL(clipSelected(DocClipBase *, QPoint)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint))); + connect(m_projectList, SIGNAL(raiseClipMonitor()), m_clipMonitor, SLOT(activateMonitor())); m_projectMonitorDock = new QDockWidget(i18n("Project Monitor"), this); m_projectMonitorDock->setObjectName("project_monitor"); @@ -839,23 +840,28 @@ void MainWindow::slotAddEffect(const QDomElement effect) void MainWindow::slotUpdateClip(const QString &id) { if (!m_activeDocument) return; - m_activeTimeline->projectView()->slotUpdateClip(id); + DocClipBase *clip = m_activeDocument->clipManager()->getClipById(id); + if (clip->numReferences() > 0) m_activeTimeline->projectView()->slotUpdateClip(id); + if (m_clipMonitor->activeClip() && m_clipMonitor->activeClip()->getId() == id) { + if (clip) m_clipMonitor->updateClipProducer(clip->getCloneProducer()); + } + if (clip) { + clip->cleanupProducers(); + } } void MainWindow::slotConnectMonitors() { m_projectList->setRenderer(m_projectMonitor->render); - //connect(m_projectList, SIGNAL(receivedClipDuration(const QString &)), this, SLOT(slotUpdateClip(const QString &))); connect(m_projectList, SIGNAL(deleteProjectClips(QStringList, QMap)), this, SLOT(slotDeleteProjectClips(QStringList, QMap))); connect(m_projectList, SIGNAL(showClipProperties(DocClipBase *)), this, SLOT(slotShowClipProperties(DocClipBase *))); connect(m_projectList, SIGNAL(showClipProperties(QList , QMap)), this, SLOT(slotShowClipProperties(QList , QMap))); connect(m_projectMonitor->render, SIGNAL(replyGetImage(const QString &, const QString &, int, int)), m_projectList, SLOT(slotReplyGetImage(const QString &, const QString &, int, int))); connect(m_projectMonitor->render, SIGNAL(replyGetImage(const QString &, const QImage &)), m_projectList, SLOT(slotReplyGetImage(const QString &, const QImage &))); - connect(m_projectMonitor->render, SIGNAL(replyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool, bool)), m_projectList, SLOT(slotReplyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool, bool))); + connect(m_projectMonitor->render, SIGNAL(replyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool, bool)), this, SLOT(slotReplyGetFileProperties(const QString &, Mlt::Producer*, const stringMap &, const stringMap &, bool, bool))); connect(m_projectMonitor->render, SIGNAL(removeInvalidClip(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidClip(const QString &, bool))); - connect(m_projectMonitor->render, SIGNAL(blockClipMonitor(const QString)), this, SLOT(slotBlockClipMonitor(const QString))); connect(m_projectMonitor->render, SIGNAL(removeInvalidProxy(const QString &, bool)), m_projectList, SLOT(slotRemoveInvalidProxy(const QString &, bool))); connect(m_clipMonitor, SIGNAL(refreshClipThumbnail(const QString &, bool)), m_projectList, SLOT(slotRefreshClipThumbnail(const QString &, bool))); @@ -1867,7 +1873,7 @@ bool MainWindow::closeCurrentDocument(bool saveChanges) break; } } - m_clipMonitor->slotSetXml(NULL); + m_clipMonitor->slotSetClipProducer(NULL); m_timelineArea->removeTab(m_timelineArea->indexOf(w)); if (m_timelineArea->count() == 1) { m_timelineArea->setTabBarHidden(true); @@ -2279,7 +2285,7 @@ void MainWindow::slotUpdateProjectProfile(const QString &profile) // Deselect current effect / transition m_effectStack->slotClipItemSelected(NULL, 0); m_transitionConfig->slotTransitionItemSelected(NULL, 0, QPoint(), false); - m_clipMonitor->slotSetXml(NULL); + m_clipMonitor->slotSetClipProducer(NULL); bool updateFps = m_activeDocument->setProfilePath(profile); KdenliveSettings::setCurrent_profile(profile); KdenliveSettings::setProject_fps(m_activeDocument->fps()); @@ -2424,7 +2430,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha disconnect(m_activeTimeline->projectView(), SIGNAL(transitionItemSelected(Transition*, int, QPoint, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(Transition*))); disconnect(m_activeTimeline->projectView(), SIGNAL(playMonitor()), m_projectMonitor, SLOT(slotPlay())); disconnect(m_activeTimeline->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType))); - disconnect(m_activeTimeline->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, const int)), m_clipMonitor, SLOT(slotSetXml(DocClipBase *, QPoint, const int))); + disconnect(m_activeTimeline->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, const int))); disconnect(m_activeTimeline, SIGNAL(cursorMoved()), m_projectMonitor, SLOT(activateMonitor())); disconnect(m_activeTimeline, SIGNAL(insertTrack(int)), this, SLOT(slotInsertTrack(int))); disconnect(m_activeTimeline, SIGNAL(deleteTrack(int)), this, SLOT(slotDeleteTrack(int))); @@ -2444,7 +2450,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha disconnect(m_projectList, SIGNAL(loadingIsOver()), m_activeTimeline->projectView(), SLOT(slotUpdateAllThumbs())); disconnect(m_projectList, SIGNAL(displayMessage(const QString&, int)), this, SLOT(slotGotProgressInfo(const QString&, int))); disconnect(m_projectList, SIGNAL(updateRenderStatus()), this, SLOT(slotCheckRenderStatus())); - disconnect(m_projectList, SIGNAL(clipNeedsReload(const QString&, bool)), m_activeTimeline->projectView(), SLOT(slotUpdateClip(const QString &, bool))); + disconnect(m_projectList, SIGNAL(clipNeedsReload(const QString&)), this, SLOT(slotUpdateClip(const QString &))); disconnect(m_projectList, SIGNAL(refreshClip(const QString &)), m_activeTimeline->projectView(), SLOT(slotRefreshThumbs(const QString &))); m_effectStack->clear(); } @@ -2460,7 +2466,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha m_effectStack->updateProjectFormat(doc->mltProfile(), doc->timecode()); connect(m_projectList, SIGNAL(refreshClip(const QString &, bool)), m_monitorManager, SLOT(slotRefreshCurrentMonitor())); connect(m_projectList, SIGNAL(refreshClip(const QString &, bool)), trackView->projectView(), SLOT(slotRefreshThumbs(const QString &, bool))); - connect(m_projectList, SIGNAL(clipNeedsReload(const QString&, bool)), trackView->projectView(), SLOT(slotUpdateClip(const QString &, bool))); + connect(m_projectList, SIGNAL(clipNeedsReload(const QString&)),this, SLOT(slotUpdateClip(const QString &))); connect(m_projectList, SIGNAL(projectModified()), doc, SLOT(setModified())); connect(m_projectList, SIGNAL(updateProfile(const QString &)), this, SLOT(slotUpdateProjectProfile(const QString &))); @@ -2510,7 +2516,7 @@ void MainWindow::connectDocument(TrackView *trackView, KdenliveDoc *doc) //cha connect(trackView, SIGNAL(setZoom(int)), this, SLOT(slotSetZoom(int))); connect(trackView->projectView(), SIGNAL(displayMessage(const QString&, MessageType)), m_messageLabel, SLOT(setMessage(const QString&, MessageType))); - connect(trackView->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, const int)), m_clipMonitor, SLOT(slotSetXml(DocClipBase *, QPoint, const int))); + connect(trackView->projectView(), SIGNAL(showClipFrame(DocClipBase *, QPoint, const int)), m_clipMonitor, SLOT(slotSetClipProducer(DocClipBase *, QPoint, const int))); connect(trackView->projectView(), SIGNAL(playMonitor()), m_projectMonitor, SLOT(slotPlay())); connect(trackView->projectView(), SIGNAL(clipItemSelected(ClipItem*, int, bool)), m_projectMonitor, SLOT(slotSetSelectedClip(ClipItem*))); @@ -4379,9 +4385,9 @@ void MainWindow::slotOpenBackupDialog(const KUrl url) delete dia; } -void MainWindow::slotBlockClipMonitor(const QString id) +void MainWindow::slotReplyGetFileProperties(const QString &clipId, Mlt::Producer *producer, const stringMap &properties, const stringMap &metadata, bool replace, bool refreshThumbnail) { - if (m_clipMonitor->activeClip() && m_clipMonitor->activeClip()->getId() == id) m_clipMonitor->slotSetXml(NULL); + m_projectList->slotReplyGetFileProperties(clipId, producer, properties, metadata, replace, refreshThumbnail); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 7bec3fc8..bcd9b5a0 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -544,8 +544,8 @@ private slots: void slotInsertNotesTimecode(); /** @brief Open the project's backupdialog. */ void slotOpenBackupDialog(const KUrl url = KUrl()); - /** @brief Make sure to block clip monitor before deleting a clip's producer. */ - void slotBlockClipMonitor(const QString id); + /** @brief Make sure to update clip monitor before deleting a clip's producer. */ + void slotReplyGetFileProperties(const QString &clipId, Mlt::Producer *producer, const stringMap &properties, const stringMap &metadata, bool replace, bool refreshThumbnail); /** @brief Disable proxies for this project. */ void slotDisableProxies(); diff --git a/src/monitor.cpp b/src/monitor.cpp index b22c2cac..b446886e 100644 --- a/src/monitor.cpp +++ b/src/monitor.cpp @@ -59,7 +59,6 @@ Monitor::Monitor(QString name, MonitorManager *manager, QString profile, QWidget m_selectedClip(NULL), m_loopClipTransition(true), m_editMarker(NULL) - { QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); @@ -804,10 +803,17 @@ void Monitor::slotLoopClip() m_playAction->setIcon(m_pauseIcon); } -void Monitor::slotSetXml(DocClipBase *clip, QPoint zone, const int position) +void Monitor::updateClipProducer(Mlt::Producer *prod) +{ + if (render == NULL) return; + render->setProducer(prod, render->seekFramePosition()); +} + +void Monitor::slotSetClipProducer(DocClipBase *clip, QPoint zone, int position) { if (render == NULL) return; if (clip == NULL && m_currentClip != NULL) { + kDebug()<<"// SETTING NULL CLIP MONITOR"; m_currentClip = NULL; m_length = -1; render->setProducer(NULL, -1); @@ -817,13 +823,18 @@ void Monitor::slotSetXml(DocClipBase *clip, QPoint zone, const int position) m_currentClip = clip; if (m_currentClip) activateMonitor(); updateMarkers(clip); - if (render->setProducer(clip->getProducer(), position) == -1) { + Mlt::Producer *prod = NULL; + if (clip) prod = clip->getCloneProducer(); + if (render->setProducer(prod, position) == -1) { // MLT CONSUMER is broken kDebug(QtWarningMsg) << "ERROR, Cannot start monitor"; } } else { - if (m_currentClip) activateMonitor(); - if (position != -1) render->seek(position); + if (m_currentClip) { + activateMonitor(); + if (position == -1) position = render->seekFramePosition(); + render->seek(position); + } } if (!zone.isNull()) { m_ruler->setZone(zone.x(), zone.y()); diff --git a/src/monitor.h b/src/monitor.h index 45f0179a..5dc9113d 100644 --- a/src/monitor.h +++ b/src/monitor.h @@ -176,6 +176,7 @@ private: /** true if selected clip is transition, false = selected clip is clip. * Necessary because sometimes we get two signals, e.g. we get a clip and we get selected transition = NULL. */ bool m_loopClipTransition; + #if defined(Q_WS_MAC) || defined(USE_OPEN_GL) VideoGLWidget *m_glWidget; bool createOpenGlWidget(QWidget *parent, const QString profile); @@ -207,7 +208,8 @@ private slots: public slots: void slotOpenFile(const QString &); - void slotSetXml(DocClipBase *clip, QPoint zone = QPoint(), const int position = -1); + void slotSetClipProducer(DocClipBase *clip, QPoint zone = QPoint(), int position = -1); + void updateClipProducer(Mlt::Producer *prod); void refreshMonitor(bool visible); void refreshMonitor(); void slotSeek(int pos); diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 2b099953..e798466b 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -160,7 +160,7 @@ ProjectList::ProjectList(QWidget *parent) : connect(this, SIGNAL(processNextThumbnail()), this, SLOT(slotProcessNextThumbnail())); connect(m_listView, SIGNAL(projectModified()), this, SIGNAL(projectModified())); connect(m_listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotClipSelected())); - connect(m_listView, SIGNAL(focusMonitor()), this, SLOT(slotClipSelected())); + connect(m_listView, SIGNAL(focusMonitor()), this, SIGNAL(raiseClipMonitor())); connect(m_listView, SIGNAL(pauseMonitor()), this, SLOT(slotPauseMonitor())); connect(m_listView, SIGNAL(requestMenu(const QPoint &, QTreeWidgetItem *)), this, SLOT(slotContextMenu(const QPoint &, QTreeWidgetItem *))); connect(m_listView, SIGNAL(addClip()), this, SLOT(slotAddClip())); @@ -500,8 +500,8 @@ void ProjectList::slotReloadClip(const QString &id) item = static_cast (selected.at(i)); if (item && !item->isProxyRunning()) { DocClipBase *clip = item->referencedClip(); - if (!clip->isClean()) { - // The clip is currently under processing (replacement in timeline), we cannot reload it now. + if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) { + kDebug()<<"//// TRYING TO RELOAD: "<clipId()<<", but it is busy"; continue; } CLIPTYPE t = item->clipType(); @@ -523,10 +523,8 @@ void ProjectList::slotReloadClip(const QString &id) e.setAttribute("length", length); } } - if (clip) { - clip->clearThumbProducer(); - } m_render->getFileProperties(e, item->clipId(), m_listView->iconSize().height(), true); + resetThumbsProducer(clip); } } } @@ -579,7 +577,7 @@ void ProjectList::slotMissingClip(const QString &id) } item->referencedClip()->setProducer(newProd, true); item->slotSetToolTip(); - emit clipNeedsReload(id, true); + emit clipNeedsReload(id); } } update(); @@ -1087,8 +1085,8 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) m_listView->processLayout(); QDomElement e = clip->toXML().cloneNode().toElement(); e.removeAttribute("file_hash"); - clip->clearThumbProducer(); m_render->getFileProperties(e, clip->getId(), m_listView->iconSize().height(), true); + resetThumbsProducer(clip); } else if (item->hasProxy() && !item->isProxyRunning()) { slotCreateProxy(clip->getId()); @@ -1145,11 +1143,6 @@ void ProjectList::slotGotProxy(ProjectItem *item) { if (item == NULL || !m_refreshed) return; DocClipBase *clip = item->referencedClip(); - if (!clip->isClean()) { - //WARNING: might result in clip said marked as proxy but not using proxy? - // The clip is currently under processing (replacement in timeline), we cannot reload it now. - return; - } // Proxy clip successfully created QDomElement e = clip->toXML().cloneNode().toElement(); @@ -1161,7 +1154,6 @@ void ProjectList::slotGotProxy(ProjectItem *item) e.setAttribute("length", length); } } - clip->clearThumbProducer(); m_render->getFileProperties(e, clip->getId(), m_listView->iconSize().height(), true); } @@ -1245,8 +1237,8 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged) xml.removeAttribute("proxy_out"); } bool replace = xml.attribute("replace") == "1"; - if (replace) clip->clearThumbProducer(); m_render->getFileProperties(xml, clip->getId(), m_listView->iconSize().height(), replace); + if (replace) resetThumbsProducer(clip); } else { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); @@ -1645,6 +1637,13 @@ void ProjectList::requestClipThumbnail(const QString id) slotProcessNextThumbnail(); } +void ProjectList::resetThumbsProducer(DocClipBase *clip) +{ + if (!clip) return; + clip->clearThumbProducer(); + m_thumbnailQueue.removeAll(clip->getId()); +} + void ProjectList::slotProcessNextThumbnail() { if (m_render->processingItems() > 0) { @@ -1725,7 +1724,7 @@ void ProjectList::slotRefreshMonitor() if (m_listView->currentItem() && m_listView->currentItem()->type() != PROJECTFOLDERTYPE) { ProjectItem *item = static_cast (m_listView->currentItem()); DocClipBase *clip = item->referencedClip(); - if (clip && clip->isClean()) emit clipSelected(clip); + if (clip && clip->isClean() && !m_render->isProcessing(item->clipId())) emit clipSelected(clip); } } } @@ -1749,8 +1748,8 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce } item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled); } - clip->setProducer(producer, replace); item->setProperties(properties, metadata); + clip->setProducer(producer, replace); clip->askForAudioThumbs(); if (refreshThumbnail) getCachedThumbnail(item); // Proxy stuff @@ -1808,18 +1807,17 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce processNextThumbnail(); } if (replace && item) { - if (item->numReferences() > 0) toReload = clipId; - else item->referencedClip()->cleanupProducers(); + toReload = clipId; // update clip in clip monitor - if (queue == 0 && item->isSelected() && m_listView->selectedItems().count() == 1) - m_refreshMonitorTimer.start(); + /*if (queue == 0 && item->isSelected() && m_listView->selectedItems().count() == 1) + m_refreshMonitorTimer.start();*/ } if (!item) { // no item for producer, delete it delete producer; } if (!toReload.isEmpty()) - emit clipNeedsReload(toReload, true); + emit clipNeedsReload(toReload); } bool ProjectList::adjustProjectProfileToItem(ProjectItem *item) @@ -2601,12 +2599,15 @@ void ProjectList::slotProxyCurrentItem(bool doProxy) CLIPTYPE t = item->clipType(); if ((t == VIDEO || t == AV || t == UNKNOWN || t == IMAGE || t == PLAYLIST) && item->referencedClip()) { if ((doProxy && item->hasProxy()) || (!doProxy && !item->hasProxy())) continue; - oldProps = item->referencedClip()->properties(); + DocClipBase *clip = item->referencedClip(); + if (!clip->isClean() || m_render->isProcessing(item->clipId())) continue; + resetThumbsProducer(clip); + oldProps = clip->properties(); if (doProxy) { newProps.clear(); - QString path = proxydir + item->referencedClip()->getClipHash() + "." + (t == IMAGE ? "png" : m_doc->getDocumentProperty("proxyextension")); + QString path = proxydir + clip->getClipHash() + "." + (t == IMAGE ? "png" : m_doc->getDocumentProperty("proxyextension")); // insert required duration for proxy - newProps.insert("proxy_out", item->referencedClip()->producerProperty("out")); + newProps.insert("proxy_out", clip->producerProperty("out")); newProps.insert("proxy", path); // We need to insert empty proxy so that undo will work oldProps.insert("proxy", QString()); diff --git a/src/projectlist.h b/src/projectlist.h index 1803c362..fbebd9f6 100644 --- a/src/projectlist.h +++ b/src/projectlist.h @@ -341,6 +341,8 @@ private: void setThumbnail(const QString &clipId, const QPixmap &pix); /** @brief Get cached thumbnail for a project's clip or create it if no cache. */ void getCachedThumbnail(ProjectItem *item); + /** @brief The clip is about to be reloaded, cancel thumbnail requests. */ + void resetThumbsProducer(DocClipBase *clip); private slots: void slotClipSelected(); @@ -393,7 +395,7 @@ signals: void loadingIsOver(); void displayMessage(const QString, int progress); void clipNameChanged(const QString, const QString); - void clipNeedsReload(const QString&, bool); + void clipNeedsReload(const QString&); /** @brief A property affecting display was changed, so we need to update monitors and thumbnails * @param id: The clip's id string * @param resetThumbs Should we recreate the timeline thumbnails. */ @@ -404,6 +406,8 @@ signals: /** @brief Request a profile change for current document. */ void updateProfile(const QString &); void processNextThumbnail(); + /** @brief Activate the clip monitor. */ + void raiseClipMonitor(); }; #endif diff --git a/src/renderer.cpp b/src/renderer.cpp index 16078ff1..183fa2f1 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -565,8 +565,10 @@ void Render::getFileProperties(const QDomElement &xml, const QString &clipId, in info.imageHeight = imageHeight; info.replaceProducer = replaceProducer; // Make sure we don't request the info for same clip twice + m_infoMutex.lock(); m_requestList.removeAll(info); m_requestList.append(info); + m_infoMutex.unlock(); if (!m_infoThread.isRunning()) m_infoThread = QtConcurrent::run(this, &Render::processFileProperties); } @@ -595,6 +597,21 @@ int Render::processingItems() const return count; } +bool Render::isProcessing(const QString &id) +{ + if (m_processingClipId == id) return true; + m_infoMutex.lock(); + for (int i = 0; i < m_requestList.count(); i++) { + requestClipInfo info = m_requestList.at(i); + if (info.clipId == id) { + m_infoMutex.unlock(); + return true; + } + } + m_infoMutex.unlock(); + return false; +} + void Render::processFileProperties() { requestClipInfo info; @@ -603,7 +620,7 @@ void Render::processFileProperties() m_infoMutex.lock(); info = m_requestList.takeFirst(); m_infoMutex.unlock(); - if (info.replaceProducer) emit blockClipMonitor(info.clipId); + m_processingClipId = info.clipId; QString path; bool proxyProducer; if (info.xml.hasAttribute("proxy") && info.xml.attribute("proxy") != "-") { @@ -644,6 +661,7 @@ void Render::processFileProperties() } else emit removeInvalidClip(info.clipId, info.replaceProducer); delete producer; + m_processingClipId.clear(); continue; } @@ -654,6 +672,7 @@ void Render::processFileProperties() // Proxy file length is different than original clip length, this will corrupt project so disable this proxy clip emit removeInvalidProxy(info.clipId, true); delete producer; + m_processingClipId.clear(); continue; } } @@ -734,6 +753,7 @@ void Render::processFileProperties() if ((!info.replaceProducer && info.xml.hasAttribute("file_hash")) || proxyProducer) { // Clip already has all properties emit replyGetFileProperties(info.clipId, producer, stringMap(), stringMap(), info.replaceProducer, true); + m_processingClipId.clear(); continue; } @@ -830,6 +850,7 @@ void Render::processFileProperties() variance = -1; } } while (variance == -1); + delete frame; if (frameNumber > -1) filePropertyMap["thumbnail"] = frameNumber; emit replyGetImage(info.clipId, img); } else if (frame->get_int("test_audio") == 0) { @@ -837,7 +858,6 @@ void Render::processFileProperties() filePropertyMap["type"] = "audio"; } } - delete frame; // Retrieve audio / video codec name // If there is a @@ -909,6 +929,7 @@ void Render::processFileProperties() producer->seek(0); emit replyGetFileProperties(info.clipId, producer, filePropertyMap, metadataPropertyMap, info.replaceProducer); } + m_processingClipId.clear(); } @@ -952,10 +973,12 @@ void Render::initSceneList() int Render::setProducer(Mlt::Producer *producer, int position) { - kDebug()<<"//////////\n SET CLIP PRODUCER \n//////////"; QMutexLocker locker(&m_mutex); + QString currentId; + int consumerPosition = 0; if (m_winid == -1) return -1; if (m_mltConsumer) { + consumerPosition = m_mltConsumer->position(); if (!m_mltConsumer->is_stopped()) { m_mltConsumer->stop(); m_mltConsumer->purge(); @@ -967,6 +990,7 @@ int Render::setProducer(Mlt::Producer *producer, int position) } if (m_mltProducer) { + currentId = m_mltProducer->get("id"); m_mltProducer->set_speed(0); delete m_mltProducer; m_mltProducer = NULL; @@ -974,13 +998,15 @@ int Render::setProducer(Mlt::Producer *producer, int position) } blockSignals(true); if (producer && producer->is_valid()) { - m_mltProducer = new Mlt::Producer(producer->get_producer()); + m_mltProducer = producer; } else m_mltProducer = m_blackClip->cut(0, 1); if (!m_mltProducer || !m_mltProducer->is_valid()) { kDebug() << " WARNING - - - - -INVALID PLAYLIST: "; return -1; } + if (position == -1 && m_mltProducer->get("id") == currentId) position = consumerPosition; + if (position != -1) m_mltProducer->seek(position); int volume = KdenliveSettings::volume(); m_mltProducer->set("meta.volume", (double)volume / 100); m_fps = m_mltProducer->get_fps(); @@ -990,10 +1016,7 @@ int Render::setProducer(Mlt::Producer *producer, int position) return error; } - if (position != -1) { - m_mltProducer->seek(position); - emit rendererPosition(position); - } else emit rendererPosition((int) m_mltProducer->position()); + emit rendererPosition((int) m_mltProducer->position()); return error; } @@ -1280,6 +1303,7 @@ void Render::start() kDebug() << "----- BROKEN MONITOR: " << m_name << ", RESTART"; return; } + if (m_mltConsumer && m_mltConsumer->is_stopped()) { if (m_mltConsumer->start() == -1) { //KMessageBox::error(qApp->activeWindow(), i18n("Could not create the video preview window.\nThere is something wrong with your Kdenlive install or your driver settings, please fix it.")); @@ -1338,8 +1362,8 @@ void Render::switchPlay(bool play) m_mltProducer->set_speed(1.0); } else if (!play) { m_mltConsumer->set("refresh", 0); - stop(); m_mltProducer->seek(m_mltConsumer->position()); + stop(); //emitConsumerStopped(); /*m_mltConsumer->set("refresh", 0); m_mltConsumer->stop(); @@ -1477,7 +1501,8 @@ GenTime Render::seekPosition() const int Render::seekFramePosition() const { - if (m_mltProducer) return (int) m_mltProducer->position(); + //if (m_mltProducer) return (int) m_mltProducer->position(); + if (m_mltConsumer) return (int) m_mltConsumer->position(); return 0; } @@ -1827,7 +1852,9 @@ Mlt::Tractor *Render::lockService() void Render::unlockService(Mlt::Tractor *tractor) { - if (tractor) delete tractor; + if (tractor) { + delete tractor; + } if (!m_mltProducer) return; Mlt::Service service(m_mltProducer->parent().get_service()); if (service.type() != tractor_type) { diff --git a/src/renderer.h b/src/renderer.h index f6298504..a8de89ea 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -106,7 +106,6 @@ Q_OBJECT public: void seek(GenTime time); void seek(int time); void seekToFrameDiff(int diff); - int m_isBlocked; QPixmap getImageThumbnail(KUrl url, int width, int height); @@ -285,6 +284,8 @@ Q_OBJECT public: int processingItems() const; /** @brief Force processing of clip with selected id. */ void forceProcessing(const QString &id); + /** @brief Are we currently processing clip with selected id. */ + bool isProcessing(const QString &id); /** @brief Requests the file properties for the specified URL (will be put in a queue list) @param xml The xml parameters for the clip @@ -342,6 +343,8 @@ private: void mltPasteEffects(Mlt::Producer *source, Mlt::Producer *dest); QMap mltGetTransitionParamsFromXml(QDomElement xml); QMap m_slowmotionProducers; + /** @brief The id of the clip that is currently being loaded for info query */ + QString m_processingClipId; /** @brief Build the MLT Consumer object with initial settings. * @param profileName The MLT profile to use for the consumer */ @@ -397,9 +400,6 @@ signals: */ void removeInvalidProxy(const QString &id, bool durationError); void refreshDocumentProducers(bool displayRatioChanged, bool fpsChanged); - - /** @brief If we will delete the producer, make sure to pause the monitor */ - void blockClipMonitor(const QString &); /** @brief A frame's image has to be shown. * -- 2.39.2