--- /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