Commit 6a16040d authored by Jean-Baptiste Mardelle's avatar Jean-Baptiste Mardelle
Browse files

Try to exit properly without crashing when closing a project that is still creating thumbs

parent 0e65e38c
......@@ -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;
}
......
......@@ -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) {
......
......@@ -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();
......
......@@ -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;
}
......
......@@ -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)
......
......@@ -136,6 +136,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()
......
......@@ -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.
......
......@@ -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;
......
......@@ -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));
}
}
}
......
......@@ -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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment