From c50bb6246e30215bcade0e8d699c3efd9bd342fc Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Mardelle Date: Fri, 28 Oct 2011 21:50:21 +0000 Subject: [PATCH] Make sure we only use one thread to create video thumbnails svn path=/trunk/kdenlive/; revision=5997 --- src/clipitem.cpp | 23 +++++++-------- src/clipmanager.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++- src/clipmanager.h | 13 +++++++++ src/docclipbase.cpp | 4 +-- src/docclipbase.h | 2 +- src/kthumb.cpp | 59 ++++++++++++++----------------------- src/kthumb.h | 8 ++--- src/projectlist.cpp | 4 +-- 8 files changed, 122 insertions(+), 62 deletions(-) diff --git a/src/clipitem.cpp b/src/clipitem.cpp index 5f4cfb02..9f6f0420 100644 --- a/src/clipitem.cpp +++ b/src/clipitem.cpp @@ -517,7 +517,6 @@ void ClipItem::resetThumbs(bool clearExistingThumbs) m_endPix = QPixmap(); m_audioThumbCachePic.clear(); } - //kDebug()<<"........... RESET THMBS: "< frames; + if (m_startPix.isNull()) { m_startThumbRequested = true; + frames.append((int)m_speedIndependantInfo.cropStart.frames(m_fps)); + } + + if (m_endPix.isNull()) { m_endThumbRequested = true; - m_clip->slotExtractImage((int)m_speedIndependantInfo.cropStart.frames(m_fps), (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1); - } else { - if (m_endPix.isNull()) { - slotGetEndThumb(); - } - if (m_startPix.isNull()) { - slotGetStartThumb(); - } + frames.append((int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1); } + + m_clip->slotExtractImage(frames); } void ClipItem::slotGetStartThumb() { m_startThumbRequested = true; - m_clip->slotExtractImage((int)m_speedIndependantInfo.cropStart.frames(m_fps), -1); + m_clip->slotExtractImage(QList() << (int)m_speedIndependantInfo.cropStart.frames(m_fps)); } void ClipItem::slotGetEndThumb() { m_endThumbRequested = true; - m_clip->slotExtractImage(-1, (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1); + m_clip->slotExtractImage(QList() << (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1); } diff --git a/src/clipmanager.cpp b/src/clipmanager.cpp index 0710fce5..41df4c83 100644 --- a/src/clipmanager.cpp +++ b/src/clipmanager.cpp @@ -26,6 +26,7 @@ #include "abstractclipitem.h" #include "abstractgroupitem.h" #include "titledocument.h" +#include "kthumb.h" #include @@ -36,6 +37,7 @@ #include #include +#include #include @@ -43,7 +45,8 @@ ClipManager::ClipManager(KdenliveDoc *doc) : QObject(), m_audioThumbsQueue(), m_doc(doc), - m_generatingAudioId() + m_generatingAudioId(), + m_abortThumb(false) { m_clipIdCounter = 1; m_folderIdCounter = 1; @@ -62,8 +65,16 @@ ClipManager::ClipManager(KdenliveDoc *doc) : ClipManager::~ClipManager() { + m_thumbsMutex.lock(); + m_requestedThumbs.clear(); + m_thumbsMutex.unlock(); + m_abortThumb = true; + m_thumbsThread.waitForFinished(); m_audioThumbsQueue.clear(); m_generatingAudioId.clear(); + m_thumbsMutex.lock(); + m_requestedThumbs.clear(); + m_thumbsMutex.unlock(); qDeleteAll(m_clipList); m_clipList.clear(); #if KDE_IS_VERSION(4,5,0) @@ -73,6 +84,12 @@ ClipManager::~ClipManager() void ClipManager::clear() { + m_thumbsMutex.lock(); + m_requestedThumbs.clear(); + m_thumbsMutex.unlock(); + m_abortThumb = true; + m_thumbsThread.waitForFinished(); + m_abortThumb = false; m_folderList.clear(); m_audioThumbsQueue.clear(); m_modifiedClips.clear(); @@ -92,6 +109,58 @@ void ClipManager::clearCache() #endif } +void ClipManager::requestThumbs(const QString id, QList frames) +{ + kDebug()<<"// Request thbs: "<::const_iterator i = m_requestedThumbs.constBegin(); + while (i != m_requestedThumbs.constEnd() && !m_abortThumb) { + const QString producerId = i.key(); + m_thumbsMutex.lock(); + QList values = m_requestedThumbs.values(producerId); + m_requestedThumbs.remove(producerId); + m_thumbsMutex.unlock(); + qSort(values); + DocClipBase *clip = getClipById(producerId); + if (!clip) continue; + while (!values.isEmpty() && clip->thumbProducer() && !m_abortThumb) { + clip->thumbProducer()->getThumb(values.takeFirst()); + } + if (m_abortThumb) { + // keep the requested frames that were not processed + m_thumbsMutex.lock(); + foreach (int frame, values) + m_requestedThumbs.insertMulti(producerId, frame); + m_thumbsMutex.unlock(); + } + i = m_requestedThumbs.constBegin(); + } +} + void ClipManager::checkAudioThumbs() { if (!KdenliveSettings::audiothumbnails()) { diff --git a/src/clipmanager.h b/src/clipmanager.h index ad01a17c..9535c774 100644 --- a/src/clipmanager.h +++ b/src/clipmanager.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -110,6 +112,10 @@ Q_OBJECT public: void removeGroup(AbstractGroupItem *group); QDomElement groupsXml() const; int clipsCount() const; + /** @brief Request creation of a clip thumbnail for specified frames. */ + void requestThumbs(const QString id, QList frames); + /** @brief remove a clip id from the queue list. */ + void stopThumbs(const QString &id); #if KDE_IS_VERSION(4,5,0) KImageCache* pixmapCache; @@ -122,6 +128,7 @@ private slots: void slotClipAvailable(const QString &path); /** Check the list of externally modified clips, and process them if they were not modified in the last 1500 milliseconds */ void slotProcessModifiedClips(); + void slotGetThumbs(); private: // Private attributes /** the list of clips in the document */ @@ -140,6 +147,12 @@ private: // Private attributes QTimer m_modifiedTimer; /** List of the clip IDs that need to be reloaded after being externally modified */ QMap m_modifiedClips; + /** Struct containing the list of clip thumbnails to request (clip id and frames) */ + QMap m_requestedThumbs; + QMutex m_thumbsMutex; + QFuture m_thumbsThread; + /** @brief If true, abort processing of clip thumbs before removing a clip. */ + bool m_abortThumb; signals: void reloadClip(const QString &); diff --git a/src/docclipbase.cpp b/src/docclipbase.cpp index adeb59c1..88765872 100644 --- a/src/docclipbase.cpp +++ b/src/docclipbase.cpp @@ -1207,10 +1207,10 @@ bool DocClipBase::hasAudioCodec(const QString &codec) const } -void DocClipBase::slotExtractImage(int frame, int frame2) +void DocClipBase::slotExtractImage(QList frames) { if (m_thumbProd == NULL) return; - m_thumbProd->extractImage(frame, frame2); + m_thumbProd->extractImage(frames); } QPixmap DocClipBase::extractImage(int frame, int width, int height) diff --git a/src/docclipbase.h b/src/docclipbase.h index 337a1373..31a9a982 100644 --- a/src/docclipbase.h +++ b/src/docclipbase.h @@ -279,7 +279,7 @@ public slots: void setMetadata(QMap properties); QMap properties() const; QMap metadata() const; - void slotExtractImage(int frame, int frame2); + void slotExtractImage(QList frames); signals: void gotAudioData(); diff --git a/src/kthumb.cpp b/src/kthumb.cpp index 6eb212a7..2ea15906 100644 --- a/src/kthumb.cpp +++ b/src/kthumb.cpp @@ -57,26 +57,20 @@ KThumb::KThumb(ClipManager *clipManager, KUrl url, const QString &id, const QStr KThumb::~KThumb() { - m_listMutex.lock(); - m_requestedThumbs.clear(); - m_listMutex.unlock(); + m_clipManager->stopThumbs(m_id); m_intraFramesQueue.clear(); if (m_audioThumbProducer.isRunning()) { m_stopAudioThumbs = true; m_audioThumbProducer.waitForFinished(); slotAudioThumbOver(); } - m_future.waitForFinished(); m_intra.waitForFinished(); } void KThumb::setProducer(Mlt::Producer *producer) { - m_listMutex.lock(); - m_requestedThumbs.clear(); - m_listMutex.unlock(); + m_clipManager->stopThumbs(m_id); m_intraFramesQueue.clear(); - m_future.waitForFinished(); m_intra.waitForFinished(); m_mutex.lock(); m_producer = producer; @@ -117,34 +111,21 @@ QPixmap KThumb::getImage(KUrl url, int width, int height) return getImage(url, 0, width, height); } -void KThumb::extractImage(int frame, int frame2) +void KThumb::extractImage(QList frames) { if (!KdenliveSettings::videothumbnails() || m_producer == NULL) return; - m_listMutex.lock(); - if (frame != -1 && !m_requestedThumbs.contains(frame)) m_requestedThumbs.append(frame); - if (frame2 != -1 && !m_requestedThumbs.contains(frame2)) m_requestedThumbs.append(frame2); - qSort(m_requestedThumbs); - m_listMutex.unlock(); - if (!m_future.isRunning()) { - m_future = QtConcurrent::run(this, &KThumb::doGetThumbs); - } + m_clipManager->requestThumbs(m_id, frames); } -void KThumb::doGetThumbs() + +void KThumb::getThumb(int frame) { const int theight = KdenliveSettings::trackheight(); const int swidth = (int)(theight * m_ratio + 0.5); const int dwidth = (int)(theight * m_dar + 0.5); - while (!m_requestedThumbs.isEmpty()) { - m_listMutex.lock(); - int frame = m_requestedThumbs.takeFirst(); - m_listMutex.unlock(); - if (frame != -1) { - QImage img = getProducerFrame(frame, swidth, dwidth, theight); - emit thumbReady(frame, img); - } - } + QImage img = getProducerFrame(frame, swidth, dwidth, theight); + emit thumbReady(frame, img); } QPixmap KThumb::extractImage(int frame, int width, int height) @@ -230,9 +211,13 @@ QImage KThumb::getFrame(Mlt::Frame *frame, int frameWidth, int displayWidth, int int ow = frameWidth; int oh = height; mlt_image_format format = mlt_image_rgb24a; - + const uchar* imagedata = frame->get_image(format, ow, oh); - QImage image(imagedata, ow, oh, QImage::Format_ARGB32_Premultiplied); + QImage image(ow, oh, QImage::Format_ARGB32_Premultiplied); + memcpy(image.bits(), imagedata, ow * oh * 4);//.byteCount()); + + //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)) { @@ -430,8 +415,8 @@ void KThumb::getAudioThumbs(int channel, double frame, double frameLength, int a void KThumb::slotCreateAudioThumbs() { - Mlt::Profile prof((char*) KdenliveSettings::current_profile().toUtf8().data()); - Mlt::Producer producer(prof, m_url.path().toUtf8().data()); + Mlt::Profile prof((char*) KdenliveSettings::current_profile().toUtf8().constData()); + Mlt::Producer producer(prof, m_url.path().toUtf8().constData()); if (!producer.is_valid()) { kDebug() << "++++++++ INVALID CLIP: " << m_url.path(); return; @@ -451,7 +436,10 @@ void KThumb::slotCreateAudioThumbs() int last_val = 0; int val = 0; - //kDebug() << "for " << m_frame << " " << m_frameLength << " " << m_producer.is_valid(); + mlt_audio_format m_audioFormat = mlt_audio_pcm; + double framesPerSecond = mlt_producer_get_fps(producer.get_producer()); + Mlt::Frame *mlt_frame; + for (int z = (int) m_frame; z < (int)(m_frame + m_frameLength) && producer.is_valid(); z++) { if (m_stopAudioThumbs) break; val = (int)((z - m_frame) / (m_frame + m_frameLength) * 100.0); @@ -460,13 +448,10 @@ void KThumb::slotCreateAudioThumbs() last_val = val; } producer.seek(z); - Mlt::Frame *mlt_frame = producer.get_frame(); + mlt_frame = producer.get_frame(); if (mlt_frame && mlt_frame->is_valid()) { - double m_framesPerSecond = mlt_producer_get_fps(producer.get_producer()); - int m_samples = mlt_sample_calculator(m_framesPerSecond, m_frequency, mlt_frame_get_position(mlt_frame->get_frame())); - mlt_audio_format m_audioFormat = mlt_audio_pcm; + int m_samples = mlt_sample_calculator(framesPerSecond, m_frequency, mlt_frame_get_position(mlt_frame->get_frame())); qint16* m_pcm = static_cast(mlt_frame->get_audio(m_audioFormat, m_frequency, m_channels, m_samples)); - for (int c = 0; c < m_channels; c++) { QByteArray m_array; m_array.resize(m_arrayWidth); diff --git a/src/kthumb.h b/src/kthumb.h index f90051d7..7dbc5c98 100644 --- a/src/kthumb.h +++ b/src/kthumb.h @@ -63,7 +63,7 @@ Q_OBJECT public: bool hasProducer() const; void clearProducer(); void updateThumbUrl(const QString &hash); - void extractImage(int frame, int frame2); + void extractImage(QList frames); QPixmap extractImage(int frame, int width, int height); #if KDE_IS_VERSION(4,5,0) /** @brief Request thumbnails for the frame range. */ @@ -71,6 +71,7 @@ Q_OBJECT public: /** @brief Query cached thumbnail. */ QImage findCachedThumb(const QString path); #endif + void getThumb(int frame); public slots: void updateClipUrl(KUrl url, const QString &hash); @@ -106,9 +107,6 @@ private: Mlt::Producer *m_producer; ClipManager *m_clipManager; QString m_id; - QList m_requestedThumbs; - /** @brief Controls the thumbnails process. */ - QFuture m_future; /** @brief Controls the intra frames thumbnails process (cached thumbnails). */ QFuture m_intra; QFile m_audioThumbFile; @@ -121,8 +119,6 @@ private: /** @brief List of frame numbers from which we want to extract thumbnails. */ QList m_intraFramesQueue; QMutex m_mutex; - QMutex m_listMutex; - void doGetThumbs(); QImage getProducerFrame(int framepos, int frameWidth, int displayWidth, int height); signals: diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 29250d8b..eb17ca2e 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -1646,7 +1646,6 @@ QDomElement ProjectList::producersList() QDomDocument doc; QDomElement prods = doc.createElement("producerlist"); doc.appendChild(prods); - kDebug() << "//////////// PRO LIST BUILD PRDSLIST "; QTreeWidgetItemIterator it(m_listView); while (*it) { if ((*it)->type() != PROJECTCLIPTYPE) { @@ -1664,10 +1663,9 @@ void ProjectList::slotCheckForEmptyQueue() { if (m_render->processingItems() == 0 && m_thumbnailQueue.isEmpty()) { if (!m_refreshed && m_allClipsProcessed) { - kDebug()<<"// LOADING IS OVER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"; m_listView->setEnabled(true); slotClipSelected(); - emit loadingIsOver(); + QTimer::singleShot(500, this, SIGNAL(loadingIsOver())); emit displayMessage(QString(), -1); m_refreshed = true; } -- 2.39.2