videocollection/videocollectionwrapper/src/videothumbnaildata_p.cpp
changeset 15 cf5481c2bc0b
child 17 69946d1824c4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videocollection/videocollectionwrapper/src/videothumbnaildata_p.cpp	Fri Apr 16 14:59:52 2010 +0300
@@ -0,0 +1,576 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  VideoThumbnailDataPrivate class implementation
+*
+*/
+
+// INCLUDE FILES
+#include <qapplication.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+#include <mpxmediageneraldefs.h>
+#include <hbicon.h>
+
+#include <vcxmyvideosdefs.h>
+
+#include "videothumbnaildata_p.h"
+#include "videocollectionwrapper.h"
+#include "videosortfilterproxymodel.h"
+#include "videothumbnailfetcher.h"
+
+// Maximum thumbnails kept in memory.
+const int THUMBNAIL_CACHE_SIZE = 60;
+// Maximum of thumbnail fetches done at one background fetch round.
+const int THUMBNAIL_BACKGROUND_FETCH_AMOUNT = 20;
+// Milliseconds for the background fetch timer.
+const int THUMBNAIL_BACKGROUND_TIMEOUT = 100;
+// Milliseconds while thumbnail ready events are gathered before they 
+// are signaled.
+const int THUMBNAIL_READY_SIGNAL_TIMEOUT = 50;
+// Priority for background thumbnail fetches.
+const int BACKGROUND_FETCH_PRIORITY = 3000;
+
+/**
+ * global qHash function required fo creating hash values for TMPXItemId -keys
+ */
+inline uint qHash(TMPXItemId key) 
+{ 
+    QPair<uint, uint> keyPair(key.iId1, key.iId2); 
+
+    return qHash(keyPair);
+}
+
+// ================= MEMBER FUNCTIONS =======================
+//
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::VideoThumbnailDataPrivate()
+// -----------------------------------------------------------------------------
+//
+VideoThumbnailDataPrivate::VideoThumbnailDataPrivate() :
+    mThumbnailFetcher(0),
+    mCurrentModel(0),
+    mCurrentFetchIndex(0),
+    mCurrentBackgroundFetchCount(0),
+    mBgFetchTimer(0),
+    mTbnReportTimer(0),
+    mSignalsConnected(false),
+    mBackgroundFetchingEnabled(true)
+{
+    initialize();
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::~VideoThumbnailDataPrivate()
+// -----------------------------------------------------------------------------
+//
+VideoThumbnailDataPrivate::~VideoThumbnailDataPrivate()
+{
+    cleanup();
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::initialize()
+// -----------------------------------------------------------------------------
+//
+int VideoThumbnailDataPrivate::initialize()
+{
+    mThumbnailData.setMaxCost(THUMBNAIL_CACHE_SIZE);
+    
+    if(!mThumbnailFetcher)
+    {
+        mThumbnailFetcher = new VideoThumbnailFetcher();        
+    }
+
+    if(!mBgFetchTimer)
+    {
+        mBgFetchTimer = new QTimer();
+    }
+    
+    if(!mTbnReportTimer)
+    {
+        mTbnReportTimer = new QTimer();
+    }
+
+    if(connectSignals() < 0)
+    {
+        cleanup();
+        return -1;
+    }
+    
+    return 0;
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::cleanup()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::cleanup()
+{
+    disconnectSignals();
+
+    delete mThumbnailFetcher;
+    mThumbnailFetcher = 0;
+    
+    freeThumbnailData();
+    
+    if(mTbnReportTimer)
+    {
+        mTbnReportTimer->stop();
+        delete mTbnReportTimer;
+        mTbnReportTimer = 0;
+    }
+    
+    if(mBgFetchTimer)
+    {
+        mBgFetchTimer->stop();
+        delete mBgFetchTimer;
+        mBgFetchTimer = 0;
+    }
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::disconnectSignals()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::disconnectSignals()
+{
+    if(mSignalsConnected)
+    {
+        VideoSortFilterProxyModel *model = 
+                VideoCollectionWrapper::instance().getModel(VideoCollectionWrapper::EAllVideos);
+        if(model)
+            {
+            disconnect(model->sourceModel(), SIGNAL(modelReady()), this, SLOT(modelChangedSlot()));
+            disconnect(model->sourceModel(), SIGNAL(modelChanged()), this, SLOT(modelChangedSlot()));
+            }
+		disconnect(mThumbnailFetcher, SIGNAL(thumbnailReady( QPixmap , void *, int )),
+                    this, SLOT(thumbnailReadySlot( QPixmap , void *, int )));
+        disconnect(mThumbnailFetcher, SIGNAL(allThumbnailsFetched()),
+                 this, SLOT(allThumbnailsFetchedSlot()));          
+        disconnect(mBgFetchTimer, SIGNAL(timeout()), this, SLOT(doBackgroundFetching()));
+        disconnect(mTbnReportTimer, SIGNAL(timeout()), this, SLOT(reportThumbnailsReadySlot()));
+    }
+    mSignalsConnected = false;
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::connectSignals()
+// -----------------------------------------------------------------------------
+//
+int VideoThumbnailDataPrivate::connectSignals()
+{
+    if(!mSignalsConnected)
+    {
+        VideoSortFilterProxyModel *model = 
+                VideoCollectionWrapper::instance().getModel(VideoCollectionWrapper::EAllVideos);
+        if(!model)
+            return -1;
+        if(!connect(mThumbnailFetcher, SIGNAL(thumbnailReady( QPixmap , void *, int )),
+                    this, SLOT(thumbnailReadySlot( QPixmap , void *, int))) ||
+            !connect(mThumbnailFetcher, SIGNAL(allThumbnailsFetched()),
+                     this, SLOT(allThumbnailsFetchedSlot())) ||
+           !connect(model->sourceModel(), SIGNAL(modelReady()), this, SLOT(modelChangedSlot())) ||
+           !connect(model->sourceModel(), SIGNAL(modelChanged()), this, SLOT(modelChangedSlot())) ||
+           !connect(mBgFetchTimer, SIGNAL(timeout()), this, SLOT(doBackgroundFetching())) ||
+           !connect(mTbnReportTimer, SIGNAL(timeout()), this, SLOT(reportThumbnailsReadySlot())))
+        {
+            return -1;
+        }
+        
+        QApplication *app = qApp;
+        if(!connect(app, SIGNAL(aboutToQuit()), this, SLOT(aboutToQuitSlot())))
+        {
+            return -1;
+        }
+        
+        mSignalsConnected = true;
+    }
+    return 0;
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::getThumbnail()
+// -----------------------------------------------------------------------------
+//
+const QIcon* VideoThumbnailDataPrivate::getThumbnail(TMPXItemId mediaId)
+{
+    const QIcon *thumbnail = mThumbnailData[mediaId];
+    if(!thumbnail)
+    {
+        return defaultThumbnail(mediaId);
+    }
+    return thumbnail;
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::startFetchingThumbnails()
+// -----------------------------------------------------------------------------
+//
+int VideoThumbnailDataPrivate::startFetchingThumbnails(const QList<QModelIndex> &indexes, int priority)
+{
+    if(!mCurrentModel || !mThumbnailFetcher)
+    {
+        return -1;
+    }
+    if(indexes.count() == 0)
+    {
+        return 0;
+    }
+    
+    mThumbnailFetcher->pauseFetching();
+
+    int fetchCountBefore = mThumbnailFetcher->fetchCount();
+    
+    // Fetch the thumbnails
+    for(int i = 0; i < indexes.count(); i++)
+    {
+        startFetchingThumbnail(mCurrentModel->getMediaIdAtIndex(indexes[i]), priority--);
+    }
+    
+    int started = mThumbnailFetcher->fetchCount() - fetchCountBefore;
+    
+    mThumbnailFetcher->continueFetching();
+    
+    return started;
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::startFetchingThumbnail()
+// -----------------------------------------------------------------------------
+//
+int VideoThumbnailDataPrivate::startFetchingThumbnail(TMPXItemId mediaId, int priority)
+{
+    if(!mCurrentModel || !mThumbnailFetcher)
+    {
+        return -1;
+    }
+
+    // Check that it's not fetched before.
+    if(mThumbnailData.contains(mediaId))
+    {
+        return 0;
+    }
+
+    QString fileName = mCurrentModel->getMediaFilePathForId(mediaId);
+    
+    // object containing media id to be passed throught
+    // thumbnail generation process.
+    TMPXItemId *internal = new TMPXItemId(mediaId.iId1, mediaId.iId2);
+    
+    // Thumbnail fetcher signals into thumbnailReadySlot when thumbnail ready
+    if(fileName.length() > 0)
+    {
+        mThumbnailFetcher->addFetch(fileName, internal, priority);
+    }
+
+    return 0;
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::doBackgroundFetching()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::doBackgroundFetching()
+{
+    if(!mCurrentModel || !mThumbnailFetcher)
+    {
+        return;
+    }
+
+    if(mCurrentBackgroundFetchCount >= THUMBNAIL_CACHE_SIZE)
+    {
+        return;
+    }
+    
+    int maxIndex = mCurrentModel->rowCount();
+    if(maxIndex == 0)
+    {
+        return;
+    }
+
+    // Delta to UI index where fetch has been done already.  
+    int currentDelta = mCurrentBackgroundFetchCount/2;
+    
+    // How many will be fetched.  
+    const int fetchAmount = THUMBNAIL_BACKGROUND_FETCH_AMOUNT/2;
+
+    QList<QModelIndex> indexes;
+
+    // Items after the current fetch index.
+    int startIndex = mCurrentFetchIndex+currentDelta;
+    int endIndex = mCurrentFetchIndex+currentDelta+fetchAmount;
+    getModelIndexes(indexes, startIndex, endIndex);
+
+    // Items before the current fetch index.
+    startIndex = mCurrentFetchIndex-currentDelta-fetchAmount;
+    endIndex = mCurrentFetchIndex-currentDelta;
+    getModelIndexes(indexes, startIndex, endIndex);
+    
+    mCurrentBackgroundFetchCount += THUMBNAIL_BACKGROUND_FETCH_AMOUNT;
+
+    int fetchesStarted = startFetchingThumbnails(indexes, BACKGROUND_FETCH_PRIORITY);
+    
+    // No thumbnails to fetch, start again.
+    if(fetchesStarted == 0)
+    {
+        continueBackgroundFetch();
+    }
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::getModelIndexes()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::getModelIndexes(QList<QModelIndex> &indexes, int startIndex, int endIndex)
+{
+    QModelIndex index;
+    for(int i = startIndex; i < endIndex; i++)
+    {
+        if(i >= 0)
+        {
+            index = mCurrentModel->index(i, 0);
+            if(index.isValid())
+            {
+                indexes.append(index);
+            }
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::thumbnailReadySlot()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::thumbnailReadySlot(QPixmap tnData, void *internal, int error)
+{
+    TMPXItemId mediaId(0, 0);
+    if(internal)
+    {
+        mediaId = *(static_cast<TMPXItemId*>(internal));
+        delete internal;
+    }
+    else
+    {
+        return;
+    }
+
+    if(!error && !tnData.isNull())
+    {
+        mThumbnailData.insert(mediaId, new QIcon(tnData));
+        
+        // Gather list of media ids and emit thumbnailReady signals in larger set
+        // when timer goes off.
+        if(mTbnReportTimer && !mTbnReportTimer->isActive())
+        {
+            mTbnReportTimer->setSingleShot(true);
+            mTbnReportTimer->start(THUMBNAIL_READY_SIGNAL_TIMEOUT);
+        }
+
+        // Save the media id for the signal.  
+        mReadyThumbnailMediaIds.append(mediaId);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::reportThumbnailsReadySlot()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::reportThumbnailsReadySlot()
+{
+    emit thumbnailsFetched(mReadyThumbnailMediaIds);
+    mReadyThumbnailMediaIds.clear();
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::allThumbnailsFetchedSlot()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::allThumbnailsFetchedSlot()
+{
+    continueBackgroundFetch();
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::modelChangedSlot()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::modelChangedSlot()
+{
+    startBackgroundFetching(mCurrentModel, mCurrentFetchIndex);
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::defaultThumbnail()
+// -----------------------------------------------------------------------------
+//
+const QIcon* VideoThumbnailDataPrivate::defaultThumbnail(TMPXItemId mediaId)
+{
+    const TMPXItemId defaultIdVideo(KMaxTUint32-1, KVcxMvcMediaTypeVideo);
+    const TMPXItemId defaultIdAlbum(KMaxTUint32-1, KVcxMvcMediaTypeAlbum);
+    const TMPXItemId defaultIdDownloads(KVcxMvcCategoryIdDownloads, KVcxMvcMediaTypeCategory);
+    const TMPXItemId defaultIdCaptured(KVcxMvcCategoryIdCaptured, KVcxMvcMediaTypeCategory);
+
+    // Default thumbnail for video
+    if(mediaId.iId2 == KVcxMvcMediaTypeVideo) 
+    {
+        if(!mDefaultThumbnails.contains(defaultIdVideo))
+        {
+            mDefaultThumbnails[defaultIdVideo] = HbIcon(":/icons/default_thumbnail_video.svg");
+        }
+        return &mDefaultThumbnails[defaultIdVideo].qicon();
+    }
+    else
+    {
+        // Default thumbnail for user defined album.
+        if(mediaId.iId2 == KVcxMvcMediaTypeAlbum)
+        {
+            if(!mDefaultThumbnails.contains(defaultIdAlbum))
+            {
+                mDefaultThumbnails[defaultIdAlbum] = HbIcon(":/icons/default_thumbnail_collection.svg");
+            }
+            return &mDefaultThumbnails[defaultIdAlbum].qicon();
+        }
+
+        // Thumbnails for default collections.
+        switch(mediaId.iId1)
+        {
+            case KVcxMvcCategoryIdDownloads:
+            {
+                if(!mDefaultThumbnails.contains(defaultIdDownloads))
+                {
+                    mDefaultThumbnails[defaultIdDownloads] = HbIcon("qtg_large_video_download");
+                }
+                return &mDefaultThumbnails[defaultIdDownloads].qicon();
+            }
+            
+            case KVcxMvcCategoryIdCaptured:
+            {
+                if(!mDefaultThumbnails.contains(defaultIdCaptured))
+                {
+                    mDefaultThumbnails[defaultIdCaptured] = HbIcon("qtg_large_video_capture");
+                }
+                return &mDefaultThumbnails[defaultIdCaptured].qicon();
+            }
+
+            default:
+            {
+                if(!mDefaultThumbnails.contains(defaultIdAlbum))
+                {
+                    mDefaultThumbnails[defaultIdAlbum] = HbIcon(":/icons/default_thumbnail_collection.svg");
+                }
+                return &mDefaultThumbnails[defaultIdAlbum].qicon();
+            }
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::removeThumbnail()
+// -----------------------------------------------------------------------------
+//
+bool VideoThumbnailDataPrivate::removeThumbnail(TMPXItemId mediaId)
+{
+    return mThumbnailData.remove(mediaId);
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::enableBackgroundFetching()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::enableBackgroundFetching(bool enable)
+{
+    mBackgroundFetchingEnabled = enable;
+    startBackgroundFetching(mCurrentModel, 0);
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::enableThumbnailCreation()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::enableThumbnailCreation(bool enable)
+{
+    if(mThumbnailFetcher)
+        mThumbnailFetcher->enableThumbnailCreation(enable);
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::freeThumbnailData()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::freeThumbnailData()
+{
+    // Stop timers.
+    if(mBgFetchTimer)
+        mBgFetchTimer->stop();
+    
+    if(mTbnReportTimer)
+        mTbnReportTimer->stop();
+
+    if(mThumbnailFetcher)
+        mThumbnailFetcher->cancelFetches();
+    
+    // Clear data.
+    mReadyThumbnailMediaIds.clear();
+    mThumbnailData.clear();
+    mDefaultThumbnails.clear();
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::startBackgroundFetching()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::startBackgroundFetching(VideoSortFilterProxyModel *model, int fetchIndex)
+{
+    if(!mBackgroundFetchingEnabled || !mThumbnailFetcher)
+        return;
+    
+    mThumbnailFetcher->cancelFetches();
+    
+    // If model is null, we continue using the current one. 
+    if(model)
+        mCurrentModel = model;
+    
+    mCurrentFetchIndex = fetchIndex;
+    mCurrentBackgroundFetchCount = 0;
+    doBackgroundFetching();
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::continueBackgroundFetch()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::continueBackgroundFetch()
+{
+    if(!mBackgroundFetchingEnabled)
+        return;
+
+    if(mBgFetchTimer)
+    {
+        mBgFetchTimer->stop();
+        mBgFetchTimer->setSingleShot(true);
+        mBgFetchTimer->start(THUMBNAIL_BACKGROUND_TIMEOUT);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// VideoThumbnailDataPrivate::aboutToQuitSlot()
+// -----------------------------------------------------------------------------
+//
+void VideoThumbnailDataPrivate::aboutToQuitSlot()
+{
+    cleanup();
+}
+
+// End of file