]> git.sesse.net Git - kdenlive/commitdiff
Project tree sub-clips and clip properties dialog thumbnails are now created in anoth...
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Mon, 22 Oct 2012 23:08:37 +0000 (01:08 +0200)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Mon, 22 Oct 2012 23:08:37 +0000 (01:08 +0200)
13 files changed:
src/clipmanager.cpp
src/clipmanager.h
src/clipproperties.cpp
src/clipproperties.h
src/kthumb.cpp
src/kthumb.h
src/mainwindow.cpp
src/projectlist.cpp
src/projectlist.h
src/renderwidget.cpp
src/subprojectitem.cpp
src/subprojectitem.h
src/widgets/clipproperties_ui.ui

index c65526969a52eda0b4cee4e613fe0e7c7e7975d5..a706e5ade50076606625b0fed4842a2756c9b062 100644 (file)
@@ -26,6 +26,7 @@
 #include "abstractclipitem.h"
 #include "abstractgroupitem.h"
 #include "titledocument.h"
+#include "subprojectitem.h"
 #include "kthumb.h"
 
 #include <mlt++/Mlt.h>
@@ -167,19 +168,42 @@ void ClipManager::slotGetThumbs()
     QMap<QString, int>::const_iterator i;
     int max;
     int done = 0;
+    int thumbType = 0; // 0 = timeline thumb, 1 = project clip zone thumb, 2 = clip properties thumb
+    
     while (!m_requestedThumbs.isEmpty() && !m_abortThumb) {
         m_thumbsMutex.lock();
         i = m_requestedThumbs.constBegin();
         m_processingThumbId = i.key();
         QList<int> values = m_requestedThumbs.values(m_processingThumbId);
         m_requestedThumbs.remove(m_processingThumbId);
+       if (m_processingThumbId.startsWith("?")) {
+           // if id starts with ?, it means the request comes from a clip property widget
+           thumbType = 2;
+           m_processingThumbId.remove(0, 1);
+       }
+       if (m_processingThumbId.startsWith("#")) {
+           // if id starts with #, it means the request comes from project tree
+           thumbType = 1;
+           m_processingThumbId.remove(0, 1);
+       }
         m_thumbsMutex.unlock();
         qSort(values);
         DocClipBase *clip = getClipById(m_processingThumbId);
         if (!clip) continue;
         max = m_requestedThumbs.size() + values.count();
+       int pos;
         while (!values.isEmpty() && clip->thumbProducer() && !m_abortThumb) {
-            clip->thumbProducer()->getThumb(values.takeFirst());
+           pos = values.takeFirst();
+           switch (thumbType) {
+             case 1:
+                 clip->thumbProducer()->getGenericThumb(pos, SubProjectItem::itemDefaultHeight(), thumbType);
+                 break;
+             case 2:
+                 clip->thumbProducer()->getGenericThumb(pos, 180, thumbType);
+                 break;
+             default:
+                 clip->thumbProducer()->getThumb(pos);
+           }
             done++;
             if (max > 3) emit displayMessage(i18n("Loading thumbnails"), 100 * done / max);
         }
@@ -918,5 +942,14 @@ bool ClipManager::isOnRemovableDevice(const KUrl &url)
     return volumeMatch;
 }
 
-
+void ClipManager::projectTreeThumbReady(const QString &id, int frame, QImage img, int type)
+{
+    switch (type) {
+      case 2:
+         emit gotClipPropertyThumbnail(id, img);
+         break;
+      default:
+       emit thumbReady(id, frame, img);
+    }
+}
 
index 512edd20edaea9f638773081cd3249426ef94735..ca85ab05894691660a039c815358e1302188f054 100644 (file)
@@ -127,6 +127,7 @@ Q_OBJECT public:
     void requestThumbs(const QString id, QList <int> frames);
     /** @brief remove a clip id from the queue list. */
     void stopThumbs(const QString &id);
+    void projectTreeThumbReady(const QString &id, int frame, QImage img, int type);
 
 #if KDE_IS_VERSION(4,5,0)
     KImageCache* pixmapCache;
@@ -177,6 +178,8 @@ private:   // Private attributes
     QString m_processingAudioThumbId;
     /** @brief The list of removable drives. */
     QList<SolidVolumeInfo> m_removableVolumes;
+
+    QPoint m_projectTreeThumbSize;
     
     /** @brief Get a list of drives, to check if we have files on removable media. */
     void listRemovableVolumes();
@@ -190,6 +193,8 @@ signals:
     void availableClip(const QString &);
     void checkAllClips(bool displayRatioChanged, bool fpsChanged, QStringList brokenClips);
     void displayMessage(const QString &, int);
+    void thumbReady(const QString &id, int, QImage);
+    void gotClipPropertyThumbnail(const QString &id, QImage);
 };
 
 #endif
index 1d5e39ee5dce7e62cce42b33e7d3b7fee1bf9933..22bc7269baa9513479376c3679698f64386cf507 100644 (file)
@@ -435,21 +435,8 @@ ClipProperties::ClipProperties(DocClipBase *clip, Timecode tc, double fps, QWidg
         if (props.contains("colorspace"))
             new QTreeWidgetItem(m_view.clip_vproperties, QStringList() << i18n("Colorspace") << ProfilesDialog::getColorspaceDescription(props.value("colorspace").toInt()));
         
-
-        int width = 180.0 * KdenliveSettings::project_display_ratio();
-        if (width % 2 == 1) width++;
-        QPixmap pix = m_clip->thumbProducer()->getImage(url, m_clip->getClipThumbFrame(), width, 180);
-       QPixmap framedPix(pix.width(), pix.height());
-       framedPix.fill(Qt::transparent);
-       QPainter p(&framedPix);
-       p.setRenderHint(QPainter::Antialiasing, true);
-       QPainterPath path;
-       path.addRoundedRect(0.5, 0.5, framedPix.width() - 1, framedPix.height() - 1, 4, 4);
-       p.setClipPath(path);
-       p.drawPixmap(0, 0, pix);
-       p.end();
-       
-        m_view.clip_thumb->setPixmap(framedPix);
+       m_view.clip_thumb->setMinimumSize(180 * KdenliveSettings::project_display_ratio(), 180);
+        
         if (t == IMAGE || t == VIDEO || t == PLAYLIST) m_view.tabWidget->removeTab(AUDIOTAB);
     } else {
         m_view.tabWidget->removeTab(IMAGETAB);
@@ -688,6 +675,21 @@ ClipProperties::~ClipProperties()
     if (del2) delete del2;
 }
 
+void ClipProperties::slotGotThumbnail(const QString &id, QImage img)
+{
+    if (id != m_clip->getId()) return;
+    QPixmap framedPix(img.width(), img.height());
+    framedPix.fill(Qt::transparent);
+    QPainter p(&framedPix);
+    p.setRenderHint(QPainter::Antialiasing, true);
+    QPainterPath path;
+    path.addRoundedRect(0.5, 0.5, framedPix.width() - 1, framedPix.height() - 1, 4, 4);
+    p.setClipPath(path);
+    p.drawImage(0, 0, img);
+    p.end();
+    m_view.clip_thumb->setPixmap(framedPix);
+}
+
 void ClipProperties::slotApplyProperties()
 {
     if (m_clip != NULL) {
index ec0dee89ae091b2b8794af73bd731459d3a054c8..18ef15fdfbf86ddc11cffcd0475733baf53fb6ed 100644 (file)
@@ -76,6 +76,7 @@ private slots:
     void slotSaveMarkers();
     void slotLoadMarkers();
     void slotDeleteAnalysis();
+    void slotGotThumbnail(const QString &id, QImage img);
 
 private:
     Ui::ClipProperties_UI m_view;
index 350f14f46bb8cf65b9fea30de5f14d06dc66039e..86dcab93ecdc24cb67459d0181f35cecf560b691 100644 (file)
@@ -66,7 +66,7 @@ void KThumb::setProducer(Mlt::Producer *producer)
     if (m_producer) m_clipManager->stopThumbs(m_id);
     m_intraFramesQueue.clear();
     m_intra.waitForFinished();
-    m_mutex.lock();
+    QMutexLocker lock(&m_mutex);
     m_producer = producer;
     // FIXME: the profile() call leaks an object, but trying to free
     // it leads to a double-free in Profile::~Profile()
@@ -75,7 +75,6 @@ void KThumb::setProducer(Mlt::Producer *producer)
         m_dar = profile->dar();
         m_ratio = (double) profile->width() / profile->height();
     }
-    m_mutex.unlock();
 }
 
 void KThumb::clearProducer()
@@ -118,11 +117,18 @@ 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);
-
     QImage img = getProducerFrame(frame, swidth, dwidth, theight);
     emit thumbReady(frame, img);
 }
 
+void KThumb::getGenericThumb(int frame, int height, int type)
+{
+    const int swidth = (int)(height * m_ratio + 0.5);
+    const int dwidth = (int)(height * m_dar + 0.5);
+    QImage img = getProducerFrame(frame, swidth, dwidth, height);
+    m_clipManager->projectTreeThumbReady(m_id, frame, img, type);
+}
+
 QImage KThumb::extractImage(int frame, int width, int height)
 {
     if (m_producer == NULL) {
@@ -139,9 +145,6 @@ QPixmap KThumb::getImage(KUrl url, int frame, int width, int height)
     Mlt::Profile profile(KdenliveSettings::current_profile().toUtf8().constData());
     QPixmap pix(width, height);
     if (url.isEmpty()) return pix;
-
-    //"<mlt><playlist><producer resource=\"" + url.path() + "\" /></playlist></mlt>");
-    //Mlt::Producer producer(profile, "xml-string", tmp);
     Mlt::Producer *producer = new Mlt::Producer(profile, url.path().toUtf8().constData());
     double swidth = (double) profile.width() / profile.height();
     pix = QPixmap::fromImage(getFrame(producer, frame, (int) (height * swidth + 0.5), width, height));
@@ -162,12 +165,14 @@ QImage KThumb::getProducerFrame(int framepos, int frameWidth, int displayWidth,
         p.fill(QColor(Qt::black).rgb());
         return p;
     }
-    m_mutex.lock();
+    QMutexLocker lock(&m_mutex);
     m_producer->seek(framepos);
     Mlt::Frame *frame = m_producer->get_frame();
+    frame->set("rescale.interp", "nearest");
+    frame->set("deinterlace_method", "onefield");
+    frame->set("top_field_first", -1 );
     QImage p = getFrame(frame, frameWidth, displayWidth, height);
     delete frame;
-    m_mutex.unlock();
     return p;
 }
 
@@ -187,6 +192,9 @@ QImage KThumb::getFrame(Mlt::Producer *producer, int framepos, int frameWidth, i
 
     producer->seek(framepos);
     Mlt::Frame *frame = producer->get_frame();
+    frame->set("rescale.interp", "nearest");
+    frame->set("deinterlace_method", "onefield");
+    frame->set("top_field_first", -1 );
     QImage p = getFrame(frame, frameWidth, displayWidth, height);
     delete frame;
     return p;
@@ -201,17 +209,14 @@ QImage KThumb::getFrame(Mlt::Frame *frame, int frameWidth, int displayWidth, int
         p.fill(QColor(Qt::red).rgb());
         return p;
     }
-
+    
     int ow = frameWidth;
     int oh = height;
     mlt_image_format format = mlt_image_rgb24a;
-    frame->set("rescale.interp", "nearest");
-    frame->set("deinterlace_method", "onefield");
-    frame->set("top_field_first", -1 );
     //frame->set("progressive", "1");
     if (ow % 2 == 1) ow++;
-    const uchar* imagedata = frame->get_image(format, ow, oh);
     QImage image(ow, oh, QImage::Format_ARGB32_Premultiplied);
+    const uchar* imagedata = frame->get_image(format, ow, oh);
     memcpy(image.bits(), imagedata, ow * oh * 4);//.byteCount());
     
     //const uchar* imagedata = frame->get_image(format, ow, oh);
index 142bff41c693970eb6afc086ef0a66febc2db89b..65e1cb8b539a6e8eaa91f072e576bc3586f1ff5d 100644 (file)
@@ -71,6 +71,7 @@ Q_OBJECT public:
     QImage findCachedThumb(const QString &path);
 #endif
     void getThumb(int frame);
+    void getGenericThumb(int frame, int height, int type);
 
 public slots:
     void updateClipUrl(KUrl url, const QString &hash);
index 31d181f574f657b5509222c9b5bfdc26345af20f..6aee68887847aea2cf454870367a7ea5d38248be 100644 (file)
@@ -3323,6 +3323,13 @@ void MainWindow::slotShowClipProperties(DocClipBase *clip)
 
     // any type of clip but a title
     ClipProperties *dia = new ClipProperties(clip, m_activeDocument->timecode(), m_activeDocument->fps(), this);
+
+    if (clip->clipType() == AV || clip->clipType() == VIDEO || clip->clipType() == PLAYLIST) {
+       // request clip thumbnails
+       m_activeDocument->clipManager()->requestThumbs(QString('?' + clip->getId()), QList<int>() << clip->getClipThumbFrame());
+       connect(m_activeDocument->clipManager(), SIGNAL(gotClipPropertyThumbnail(const QString&,QImage)), dia, SLOT(slotGotThumbnail(const QString&,QImage)));
+    }
+    
     connect(dia, SIGNAL(addMarkers(const QString &, QList <CommentedTime>)), m_activeTimeline->projectView(), SLOT(slotAddClipMarker(const QString &, QList <CommentedTime>)));
     connect(dia, SIGNAL(deleteAnalysis(QString,QString)), m_activeTimeline->projectView(), SLOT(slotAddClipExtraData(QString,QString)));
     connect(m_activeTimeline->projectView(), SIGNAL(updateClipMarkers(DocClipBase *)), dia, SLOT(slotFillMarkersList(DocClipBase *)));
index 8bc65c36cf3ba7fa5fe6afe088c5c3048cca445b..70ea5a10774f1d588967242708dea648cd83b2cc 100644 (file)
@@ -1360,7 +1360,7 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties)
     QList <CutZoneInfo> cuts = clip->cutZones();
     if (!cuts.isEmpty()) {
         for (int i = 0; i < cuts.count(); i++) {
-            SubProjectItem *sub = new SubProjectItem(item, cuts.at(i).zone.x(), cuts.at(i).zone.y(), cuts.at(i).description);
+            SubProjectItem *sub = new SubProjectItem(m_render->dar(), item, cuts.at(i).zone.x(), cuts.at(i).zone.y(), cuts.at(i).description);
             if (!clip->getClipHash().isEmpty()) {
                 QString cachedPixmap = m_doc->projectFolder().path(KUrl::AddTrailingSlash) + "thumbs/" + clip->getClipHash() + '#' + QString::number(cuts.at(i).zone.x()) + ".png";
                 if (QFile::exists(cachedPixmap)) {
@@ -2001,6 +2001,23 @@ void ProjectList::setDocument(KdenliveDoc *doc)
     connect(m_doc->clipManager(), SIGNAL(missingClip(const QString &)), this, SLOT(slotMissingClip(const QString &)));
     connect(m_doc->clipManager(), SIGNAL(availableClip(const QString &)), this, SLOT(slotAvailableClip(const QString &)));
     connect(m_doc->clipManager(), SIGNAL(checkAllClips(bool, bool, QStringList)), this, SLOT(updateAllClips(bool, bool, QStringList)));
+    connect(m_doc->clipManager(), SIGNAL(thumbReady(const QString &, int, QImage)), this, SLOT(slotSetThumbnail(const QString &, int, QImage)));
+}
+
+void ProjectList::slotSetThumbnail(const QString &id, int framePos, QImage img)
+{
+    QString fullid = id + '#' + QString::number(framePos);
+    ProjectItem *pItem = NULL;
+    QTreeWidgetItem *item = getAnyItemById(fullid);
+    if (item && item->parent()) pItem = static_cast <ProjectItem *>(item->parent());
+    if (!item && framePos == 0) pItem = getItemById(id);
+    if (!item && !pItem) return;
+    if (item) item->setData(0, Qt::DecorationRole, QPixmap::fromImage(img));
+    else if (pItem) pItem->setData(0, Qt::DecorationRole, QPixmap::fromImage(img));
+    if (pItem) {
+       QString hash = pItem->getClipHash();
+       if (!hash.isEmpty()) m_doc->cacheImage(hash + '#' + QString::number(framePos), img);
+    }
 }
 
 QList <DocClipBase*> ProjectList::documentClipList() const
@@ -2576,17 +2593,14 @@ void ProjectList::addClipCut(const QString &id, int in, int out, const QString d
         DocClipBase *base = clip->referencedClip();
         base->addCutZone(in, out);
         monitorItemEditing(false);
-        SubProjectItem *sub = new SubProjectItem(clip, in, out, desc);
+        SubProjectItem *sub = new SubProjectItem(m_render->dar(), clip, in, out, desc);
         if (newItem && desc.isEmpty() && !m_listView->isColumnHidden(1)) {
             if (!clip->isExpanded())
                 clip->setExpanded(true);
             m_listView->scrollToItem(sub);
             m_listView->editItem(sub, 1);
         }
-        QImage img = clip->referencedClip()->extractImage(in, (int)(sub->sizeHint(0).height()  * m_render->dar()), sub->sizeHint(0).height() - 2);
-        sub->setData(0, Qt::DecorationRole, QPixmap::fromImage(img));
-        QString hash = clip->getClipHash();
-        if (!hash.isEmpty()) m_doc->cacheImage(hash + '#' + QString::number(in), img);
+       m_doc->clipManager()->requestThumbs(QString('#' + id), QList <int>() << in);
         monitorItemEditing(true);
     }
     emit projectModified();
@@ -3668,4 +3682,5 @@ void ProjectList::slotGotFilterJobResults(QString id, int , int , QString filter
     }
 }
 
+
 #include "projectlist.moc"
index 7019595c7fec367d52a47f15a9e08c46781ca689..1f906a5db3c15f7dba8436c02b1254b2fdccd0b9 100644 (file)
@@ -331,6 +331,7 @@ public slots:
     void slotTranscodeClipJob(const QString &condition, QString params, QString desc);
     /** @brief Start an MLT process job. */
     void slotStartFilterJob(ItemInfo, const QString&,const QString&,const QString&,const QString&,const QString&,const QString&,const QStringList&);
+    void slotSetThumbnail(const QString &id, int framePos, QImage img);
     
 
 private:
index 35e408143c390f41e81c79033e825d84915ac4a0..89887ea1326fdc53fbe161d06b0b9771744579df 100644 (file)
@@ -980,6 +980,7 @@ void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const
         render_process_args << "consumer:" + (scriptExport ? "$SOURCE" : playlistPath);
     else
         render_process_args <<  (scriptExport ? "$SOURCE" : playlistPath);
+
     render_process_args << (scriptExport ? "$TARGET" : KUrl(dest).url());
     render_process_args << paramsList;
 
index 9c8ad1ef21303ad3f684689cca6c7c840d964f52..eba677b17c9ee9d974d101806fd6b219fba0a4f6 100644 (file)
 #include "kdenlivesettings.h"
 #include "docclipbase.h"
 
+
 #include <KDebug>
 #include <KLocale>
 #include <KIcon>
 
 const int DurationRole = Qt::UserRole + 1;
+const int itemHeight = 30;
 
-SubProjectItem::SubProjectItem(QTreeWidgetItem * parent, int in, int out, QString description) :
+SubProjectItem::SubProjectItem(double display_ratio, QTreeWidgetItem * parent, int in, int out, QString description) :
         QTreeWidgetItem(parent, PROJECTSUBCLIPTYPE), m_in(in), m_out(out), m_description(description)
 {
-    setSizeHint(0, QSize(65, 30));
+    setSizeHint(0, QSize((int) (itemHeight * display_ratio) + 2, itemHeight + 2));
     setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled);
     QString name = Timecode::getStringTimecode(in, KdenliveSettings::project_fps());
     setText(0, name);
     setText(1, description);
     GenTime duration = GenTime(out - in, KdenliveSettings::project_fps());
     if (duration != GenTime()) setData(0, DurationRole, Timecode::getEasyTimecode(duration, KdenliveSettings::project_fps()));
+    QPixmap pix((int) (itemHeight * display_ratio), itemHeight);
+    pix.fill(Qt::gray);
+    setData(0, Qt::DecorationRole, pix);
     //setFlags(Qt::NoItemFlags);
     //kDebug() << "Constructed with clipId: " << m_clipId;
 }
@@ -54,6 +59,12 @@ int SubProjectItem::numReferences() const
     return 0;
 }
 
+//static
+int SubProjectItem::itemDefaultHeight()
+{
+    return itemHeight;
+}
+
 QDomElement SubProjectItem::toXml() const
 {
     //return m_clip->toXML();
index 9a5a01cf94bada5f162c7ba0d64b51de7c7d24c9..d3efd85ad19c5a1c532535b59ee2a16db1333185 100644 (file)
@@ -38,7 +38,7 @@ class DocClipBase;
 class SubProjectItem : public QTreeWidgetItem
 {
 public:
-    SubProjectItem(QTreeWidgetItem * parent, int in, int out, QString description = QString());
+    SubProjectItem(double display_ratio, QTreeWidgetItem * parent, int in, int out, QString description = QString());
     virtual ~SubProjectItem();
     QDomElement toXml() const;
     int numReferences() const;
@@ -47,6 +47,7 @@ public:
     void setZone(QPoint p);
     QString description() const;
     void setDescription(QString desc);
+    static int itemDefaultHeight();
 
     /** Make sure folders appear on top of the tree widget */
     virtual bool operator<(const QTreeWidgetItem &other)const {
index 95516d38a507415b6ef274acc8919526b416b402..c6080d51ab3277230479483c6e8ce1cd2ef7676d 100644 (file)
@@ -16,9 +16,6 @@
   <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0" colspan="4">
     <widget class="QLabel" name="clip_thumb">
-     <property name="text">
-      <string>Image preview</string>
-     </property>
      <property name="alignment">
       <set>Qt::AlignCenter</set>
      </property>