aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <[email protected]>2015-06-20 20:17:28 +0200
committerJean-Baptiste Mardelle <[email protected]>2015-06-20 20:17:28 +0200
commit6a16040d35bf695cb1183552e8f9afb4e2b2a97b (patch)
treeb850f292889a9648768a02320ad8501fc5157831
parent0e65e38c5136fdb42716a5bc190a0ff5b33ecf19 (diff)
Try to exit properly without crashing when closing a project that is still creating thumbs
-rw-r--r--src/bin/bin.cpp11
-rw-r--r--src/bin/projectclip.cpp78
-rw-r--r--src/bin/projectclip.h1
-rw-r--r--src/core.cpp2
-rw-r--r--src/mainwindow.cpp5
-rw-r--r--src/monitor/monitormanager.cpp7
-rw-r--r--src/monitor/monitormanager.h1
-rw-r--r--src/project/projectmanager.cpp5
-rw-r--r--src/timeline/clipitem.cpp24
-rw-r--r--src/timeline/clipitem.h4
10 files changed, 96 insertions, 42 deletions
diff --git a/src/bin/bin.cpp b/src/bin/bin.cpp
index 2dc0a51..8e20069 100644
--- a/src/bin/bin.cpp
+++ b/src/bin/bin.cpp
@@ -337,6 +337,17 @@ Bin::Bin(QWidget* parent) :
Bin::~Bin()
{
+ blockSignals(true);
+ setEnabled(false);
+ if (m_rootFolder) {
+ while (!m_rootFolder->isEmpty()) {
+ AbstractProjectItem *child = m_rootFolder->at(0);
+ m_rootFolder->removeChild(child);
+ delete child;
+ }
+ }
+ delete m_rootFolder;
+ delete m_itemView;
delete m_jobManager;
delete m_infoMessage;
}
diff --git a/src/bin/projectclip.cpp b/src/bin/projectclip.cpp
index 45ed5f8..e9dd35b 100644
--- a/src/bin/projectclip.cpp
+++ b/src/bin/projectclip.cpp
@@ -55,6 +55,7 @@ ProjectClip::ProjectClip(const QString &id, QIcon thumb, ClipController *control
m_duration = m_controller->getStringDuration();
m_date = m_controller->date;
m_description = m_controller->description();
+ m_type = m_controller->clipType();
getFileHash();
setParent(parent);
bin()->loadSubClips(id, m_controller->getSubClips());
@@ -69,10 +70,14 @@ ProjectClip::ProjectClip(const QDomElement& description, QIcon thumb, ProjectFol
, audioFrameCache()
, m_gpuProducer(NULL)
, m_abortAudioThumb(false)
+ , m_type(Unknown)
{
Q_ASSERT(description.hasAttribute("id"));
m_clipStatus = StatusWaiting;
m_thumbnail = thumb;
+ if (description.hasAttribute("type")) {
+ m_type = (ClipType) description.attribute("type").toInt();
+ }
m_temporaryUrl = QUrl::fromLocalFile(getXmlProperty(description, "resource"));
QString clipName = getXmlProperty(description, "kdenlive:clipname");
if (!clipName.isEmpty()) {
@@ -89,8 +94,7 @@ ProjectClip::ProjectClip(const QDomElement& description, QIcon thumb, ProjectFol
ProjectClip::~ProjectClip()
{
// controller is deleted in bincontroller
- m_abortAudioThumb = true;
- m_audioThumbsThread.waitForFinished();
+ abortAudioThumbs();
}
QString ProjectClip::getToolTip() const
@@ -132,8 +136,7 @@ bool ProjectClip::audioThumbCreated() const
ClipType ProjectClip::clipType() const
{
- if (m_controller == NULL) return Unknown;
- return m_controller->clipType();
+ return m_type;
}
ProjectClip* ProjectClip::clip(const QString &id)
@@ -273,6 +276,7 @@ void ProjectClip::setProducer(ClipController *controller, bool replaceProducer)
m_date = m_controller->date;
m_description = m_controller->description();
m_temporaryUrl.clear();
+ m_type = m_controller->clipType();
}
m_clipStatus = StatusReady;
bin()->emitItemUpdated(this);
@@ -291,6 +295,7 @@ void ProjectClip::abortAudioThumbs()
{
if (m_audioThumbsThread.isRunning()) {
m_abortAudioThumb = true;
+ m_audioThumbsThread.waitForFinished();
}
}
@@ -406,43 +411,51 @@ const QString ProjectClip::hash()
{
if (m_controller) {
QString clipHash = m_controller->property("kdenlive:file_hash");
- if (clipHash.isEmpty()) {
- return getFileHash();
+ if (!clipHash.isEmpty()) {
+ return clipHash;
}
- return clipHash;
}
return getFileHash();
}
const QString ProjectClip::getFileHash() const
{
- if (clipType() == SlideShow) return QString();
- QFile file(m_controller ? m_controller->clipUrl().toLocalFile() : m_temporaryUrl.toLocalFile());
- if (file.open(QIODevice::ReadOnly)) { // write size and hash only if resource points to a file
- QByteArray fileData;
- QByteArray fileHash;
- ////qDebug() << "SETTING HASH of" << value;
- //m_properties.insert("file_size", QString::number(file.size()));
- /*
+ QByteArray fileData;
+ QByteArray fileHash;
+ switch (m_type) {
+ case SlideShow:
+ fileData = m_controller ? m_controller->clipUrl().toLocalFile().toUtf8() : m_temporaryUrl.toLocalFile().toUtf8();
+ fileHash = QCryptographicHash::hash(fileData, QCryptographicHash::Md5);
+ break;
+ case Text:
+ case Color:
+ return QString();
+ break;
+ default:
+ QFile file(m_controller ? m_controller->clipUrl().toLocalFile() : m_temporaryUrl.toLocalFile());
+ if (file.open(QIODevice::ReadOnly)) { // write size and hash only if resource points to a file
+ /*
* 1 MB = 1 second per 450 files (or faster)
* 10 MB = 9 seconds per 450 files (or faster)
*/
- if (file.size() > 2000000) {
- fileData = file.read(1000000);
- if (file.seek(file.size() - 1000000))
- fileData.append(file.readAll());
- } else
- fileData = file.readAll();
- file.close();
- fileHash = QCryptographicHash::hash(fileData, QCryptographicHash::Md5);
- QString result = fileHash.toHex();
- if (m_controller) {
- m_controller->setProperty("kdenlive:file_hash", result);
- m_controller->setProperty("kdenlive:file_size", QString::number(file.size()));
- }
- return result;
+ if (file.size() > 2000000) {
+ fileData = file.read(1000000);
+ if (file.seek(file.size() - 1000000))
+ fileData.append(file.readAll());
+ } else
+ fileData = file.readAll();
+ file.close();
+ if (m_controller) m_controller->setProperty("kdenlive:file_size", QString::number(file.size()));
+ fileHash = QCryptographicHash::hash(fileData, QCryptographicHash::Md5);
+ }
+ break;
+ }
+ if (fileHash.isEmpty()) return QString();
+ QString result = fileHash.toHex();
+ if (m_controller) {
+ m_controller->setProperty("kdenlive:file_hash", result);
}
- return QString();
+ return result;
}
double ProjectClip::getOriginalFps() const
@@ -467,7 +480,7 @@ void ProjectClip::setProperties(QMap <QString, QString> properties, bool refresh
while (i.hasNext()) {
i.next();
setProducerProperty(i.key(), i.value());
- if (clipType() == SlideShow && keys.contains(i.key())) refreshProducer = true;
+ if (m_type == SlideShow && keys.contains(i.key())) refreshProducer = true;
}
if (properties.contains("kdenlive:proxy")) {
QString value = properties.value("kdenlive:proxy");
@@ -489,7 +502,7 @@ void ProjectClip::setProperties(QMap <QString, QString> properties, bool refresh
}
else if (properties.contains("resource")) {
// Clip resource changed, update thumbnail
- if (clipType() == Color) {
+ if (m_type == Color) {
//reloadProducer(true);
}
else {
@@ -834,6 +847,7 @@ void ProjectClip::slotCreateAudioThumbs()
*audioLevels << audioLevels->last();
}
delete mlt_frame;
+ if (m_abortAudioThumb) break;
}
if (!m_abortAudioThumb && audioLevels->size() > 0) {
diff --git a/src/bin/projectclip.h b/src/bin/projectclip.h
index c628c3d..39b3f38 100644
--- a/src/bin/projectclip.h
+++ b/src/bin/projectclip.h
@@ -223,6 +223,7 @@ private:
bool m_abortAudioThumb;
/** @brief Indicates whether audio thumbnail creation is running. */
QFuture<void> m_audioThumbsThread;
+ ClipType m_type;
signals:
void gotAudioData();
diff --git a/src/core.cpp b/src/core.cpp
index 608a4e5..454bb34 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -33,9 +33,11 @@ Core::Core(MainWindow *mainWindow) :
Core::~Core()
{
+ m_monitorManager->stopActiveMonitor();
delete m_projectManager;
delete m_binWidget;
delete m_binController;
+ delete m_monitorManager;
m_self = 0;
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 434f994..aa3e998 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -546,9 +546,6 @@ bool MainWindow::queryClose()
}
}
saveOptions();
- if (pCore->monitorManager()) {
- pCore->monitorManager()->stopActiveMonitor();
- }
// WARNING: According to KMainWindow::queryClose documentation we are not supposed to close the document here?
return pCore->projectManager()->closeCurrentDocument(true);
@@ -2508,7 +2505,7 @@ void MainWindow::slotSelectClipInTimeline()
void MainWindow::hideEvent(QHideEvent */*event*/)
{
if (isMinimized() && pCore->monitorManager())
- pCore->monitorManager()->stopActiveMonitor();
+ pCore->monitorManager()->pauseActiveMonitor();
}
/*void MainWindow::slotSaveZone(Render *render, const QPoint &zone, DocClipBase *baseClip, QUrl path)
diff --git a/src/monitor/monitormanager.cpp b/src/monitor/monitormanager.cpp
index b16fdad..11b7f06 100644
--- a/src/monitor/monitormanager.cpp
+++ b/src/monitor/monitormanager.cpp
@@ -137,6 +137,11 @@ void MonitorManager::slotSwitchMonitors(bool activateClip)
void MonitorManager::stopActiveMonitor()
{
+ if (m_activeMonitor) m_activeMonitor->stop();
+}
+
+void MonitorManager::pauseActiveMonitor()
+{
if (m_activeMonitor == m_clipMonitor) m_clipMonitor->pause();
else if (m_activeMonitor == m_projectMonitor) m_projectMonitor->pause();
}
@@ -148,7 +153,7 @@ void MonitorManager::slotPlay()
void MonitorManager::slotPause()
{
- stopActiveMonitor();
+ pauseActiveMonitor();
}
void MonitorManager::slotPlayZone()
diff --git a/src/monitor/monitormanager.h b/src/monitor/monitormanager.h
index b8514e6..0be6324 100644
--- a/src/monitor/monitormanager.h
+++ b/src/monitor/monitormanager.h
@@ -45,6 +45,7 @@ public:
Timecode timecode() const;
void resetProfiles(const Timecode &tc);
void stopActiveMonitor();
+ void pauseActiveMonitor();
AbstractRender *activeRenderer();
/** Searches for a monitor with the given name.
@return NULL, if no monitor could be found, or the monitor otherwise.
diff --git a/src/project/projectmanager.cpp b/src/project/projectmanager.cpp
index ea64f6b..29090d1 100644
--- a/src/project/projectmanager.cpp
+++ b/src/project/projectmanager.cpp
@@ -63,6 +63,9 @@ ProjectManager::ProjectManager(QObject* parent) :
ProjectManager::~ProjectManager()
{
+ if (m_trackView) {
+ delete m_trackView;
+ }
if (m_project) {
delete m_project;
}
@@ -212,7 +215,7 @@ bool ProjectManager::closeCurrentDocument(bool saveChanges)
bool ProjectManager::saveFileAs(const QString &outputFileName)
{
- pCore->monitorManager()->stopActiveMonitor();
+ pCore->monitorManager()->pauseActiveMonitor();
if (m_project->saveSceneList(outputFileName, pCore->monitorManager()->projectMonitor()->sceneList(), m_trackView->projectView()->guidesData()) == false) {
return false;
diff --git a/src/timeline/clipitem.cpp b/src/timeline/clipitem.cpp
index 7f61f1f..bc075ed 100644
--- a/src/timeline/clipitem.cpp
+++ b/src/timeline/clipitem.cpp
@@ -121,6 +121,9 @@ ClipItem::~ClipItem()
blockSignals(true);
m_endThumbTimer.stop();
m_startThumbTimer.stop();
+ m_thumbThreads.setCancelOnWait(true);
+ m_thumbThreads.waitForFinished();
+ m_thumbThreads.clearFutures();
if (scene())
scene()->removeItem(this);
//if (m_clipType == Video | AV | SlideShow | Playlist) { // WRONG, cannot use |
@@ -480,7 +483,7 @@ void ClipItem::slotFetchThumbs()
}
if (!frames.isEmpty()) {
- QtConcurrent::run(m_binClip, &ProjectClip::slotExtractImage, frames);
+ m_thumbThreads.addFuture(QtConcurrent::run(m_binClip, &ProjectClip::slotExtractImage, frames));
}
}
@@ -494,7 +497,7 @@ void ClipItem::stopThumbs()
void ClipItem::slotGetStartThumb()
{
m_startThumbRequested = true;
- QtConcurrent::run(m_binClip, &ProjectClip::slotExtractImage, QList<int>() << (int)m_speedIndependantInfo.cropStart.frames(m_fps));
+ m_thumbThreads.addFuture(QtConcurrent::run(m_binClip, &ProjectClip::slotExtractImage, QList<int>() << (int)m_speedIndependantInfo.cropStart.frames(m_fps)));
//TODO
//m_clip->slotExtractImage(QList<int>() << (int)m_speedIndependantInfo.cropStart.frames(m_fps));
}
@@ -502,7 +505,7 @@ void ClipItem::slotGetStartThumb()
void ClipItem::slotGetEndThumb()
{
m_endThumbRequested = true;
- QtConcurrent::run(m_binClip, &ProjectClip::slotExtractImage, QList<int>() << (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1);
+ m_thumbThreads.addFuture(QtConcurrent::run(m_binClip, &ProjectClip::slotExtractImage, QList<int>() << (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1));
//TODO
//m_clip->slotExtractImage(QList<int>() << (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1);
}
@@ -543,6 +546,7 @@ void ClipItem::slotThumbReady(int frame, const QImage &img)
if (m_clipType == Image || m_clipType == Text) {
update(r.right() - width, r.top(), width, pix.height());
}
+ clearThumbthreads();
} else if (m_endThumbRequested && frame == (m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1) {
QRectF r = boundingRect();
QPixmap pix = QPixmap::fromImage(img);
@@ -550,6 +554,20 @@ void ClipItem::slotThumbReady(int frame, const QImage &img)
m_endPix = pix;
m_endThumbRequested = false;
update(r.right() - width, r.top(), width, pix.height());
+ clearThumbthreads();
+ }
+}
+
+void ClipItem::clearThumbthreads()
+{
+ if (!m_thumbThreads.futures().isEmpty()) {
+ // Remove inactive threads
+ QList <QFuture<void> > futures = m_thumbThreads.futures();
+ m_thumbThreads.clearFutures();
+ for (int i = 0; i < futures.count(); ++i)
+ if (!futures.at(i).isFinished()) {
+ m_thumbThreads.addFuture(futures.at(i));
+ }
}
}
diff --git a/src/timeline/clipitem.h b/src/timeline/clipitem.h
index 1182565..09bb24c 100644
--- a/src/timeline/clipitem.h
+++ b/src/timeline/clipitem.h
@@ -29,6 +29,7 @@
#include <QTimeLine>
#include <QGraphicsRectItem>
#include <QDomElement>
+#include <QFutureSynchronizer>
#include <QGraphicsSceneMouseEvent>
#include <QTimer>
@@ -238,10 +239,11 @@ private:
QMap<int, QPixmap> m_audioThumbCachePic;
bool m_audioThumbReady;
double m_framePixelWidth;
-
+ QFutureSynchronizer<void> m_thumbThreads;
QPixmap m_videoPix;
QPixmap m_audioPix;
bool parseKeyframes(const QLocale locale, QDomElement e);
+ void clearThumbthreads();
private slots:
void slotGetStartThumb();