camerauis/cameraxui/cxengine/src/cxefilesavethreadsymbian.cpp
changeset 19 d9aefe59d544
child 37 64817133cd1d
equal deleted inserted replaced
3:8b2d6d0384b0 19:d9aefe59d544
       
     1 /*
       
     2 * Copyright (c) 2009-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Still image saving thread
       
    15 *
       
    16 */
       
    17 
       
    18 #include <QPixmap>
       
    19 #include <QByteArray>
       
    20 #include <QCoreApplication>
       
    21 #include <QMutexLocker>
       
    22 
       
    23 #include "cxestillimage.h"
       
    24 #include "cxeimagedataitem.h"
       
    25 #include "cxeimagedataitemsymbian.h"
       
    26 #include "cxeharvestercontrolsymbian.h"
       
    27 #include "cxethumbnailmanagersymbian.h"
       
    28 #include "cxefilesavethreadsymbian.h"
       
    29 #include "cxutils.h" // debug
       
    30 
       
    31 namespace
       
    32 {
       
    33     static const int SLEEP_MS_FOR_SIGNALS = 100;
       
    34     // Id for "Captured" album
       
    35     static const quint32 MDS_CAPTURED_ALBUM_ID = 2;
       
    36 }
       
    37 
       
    38 
       
    39 /**
       
    40 * Implement factory method for CxeFileSaveThreadFactory.
       
    41 */
       
    42 CxeFileSaveThread *CxeFileSaveThreadFactory::createFileSaveThread(QObject *parent)
       
    43 {
       
    44     return new CxeFileSaveThreadSymbian(parent);
       
    45 }
       
    46 
       
    47 
       
    48 /*!
       
    49     \class CxeFileSaveThreadSymbian
       
    50     \brief Still image saving thread
       
    51 */
       
    52 
       
    53 
       
    54 // ======== MEMBER FUNCTIONS ========
       
    55 
       
    56 CxeFileSaveThreadSymbian::CxeFileSaveThreadSymbian( QObject *parent )
       
    57     : CxeFileSaveThread(parent),
       
    58       mExitThread(false),
       
    59       mSnapshots(),
       
    60       mExit(false),
       
    61       mThumbnailManager(NULL),
       
    62       mHarvesterControl(NULL)
       
    63 {
       
    64     start(IdlePriority);
       
    65 }
       
    66 
       
    67 CxeFileSaveThreadSymbian::~CxeFileSaveThreadSymbian()
       
    68 {
       
    69     CX_DEBUG_ENTER_FUNCTION();
       
    70     mMutex.lock();
       
    71     mExitThread = true;
       
    72     mDataToSave.wakeOne();
       
    73     mMutex.unlock();
       
    74 
       
    75     wait(); // until the thread has finished execution.
       
    76     qDeleteAll(mQueue);  // Ensure destruction
       
    77     mQueue.clear();
       
    78 
       
    79     mSnapshots.clear();
       
    80 
       
    81     delete mThumbnailManager;
       
    82     delete mHarvesterControl;
       
    83 
       
    84     CX_DEBUG_EXIT_FUNCTION();
       
    85 }
       
    86 
       
    87 void CxeFileSaveThreadSymbian::save(CxeImageDataItem *data)
       
    88 {
       
    89     CX_DEBUG_ENTER_FUNCTION();
       
    90 
       
    91     // Ensure safe data adding.
       
    92     // Saving thread will wait if needed, in read method, until mutex is unlocked
       
    93     mMutex.lock();
       
    94     mQueue.enqueue(data);
       
    95     // Wake up saving thread if it's sleeping
       
    96     mDataToSave.wakeOne();
       
    97     mMutex.unlock();
       
    98 
       
    99     CX_DEBUG_EXIT_FUNCTION();
       
   100 }
       
   101 
       
   102 void CxeFileSaveThreadSymbian::read()
       
   103 {
       
   104     mMutex.lock();
       
   105     mCount = mQueue.count();
       
   106     mExit = mExitThread;
       
   107     mMutex.unlock();
       
   108 }
       
   109 
       
   110 void CxeFileSaveThreadSymbian::run()
       
   111 {
       
   112     CX_DEBUG_ENTER_FUNCTION();
       
   113 
       
   114     // Init Thumbnail Manager and Harvester Control.
       
   115     init();
       
   116     mActiveHarvests = 0;
       
   117 
       
   118     // Check if there is data to save.
       
   119     // There should not be any, because the thread is just contructed
       
   120     read();
       
   121 
       
   122     while (!mExit || mCount > 0) { // Complete save before exit
       
   123         CX_DEBUG(("CxeFileSaveThreadSymbian: mCount %d", mCount));
       
   124         // Wait data
       
   125         if (!mExit && mCount == 0) {
       
   126             // If there isn't any data to save, put the thread sleeping
       
   127             mMutex.lock();
       
   128             if(mActiveHarvests > 0) {
       
   129                 // If we have active harvest requests, continue after a while to check if
       
   130                 // there are signals waiting.
       
   131                 CX_DEBUG(("CxeFileSaveThreadSymbian: %d harvesting requests active..", mActiveHarvests));
       
   132                 mDataToSave.wait(&mMutex, SLEEP_MS_FOR_SIGNALS); // waiting "wakeOne"
       
   133                 QCoreApplication::processEvents();
       
   134             } else {
       
   135                 // If no active requests, and no data,
       
   136                 // halt this thread until something to
       
   137                 // save is available.
       
   138                 CX_DEBUG(("CxeFileSaveThreadSymbian: set thread sleeping"));
       
   139                 mDataToSave.wait(&mMutex); // waiting "wakeOne"
       
   140             }
       
   141             mMutex.unlock();
       
   142             CX_DEBUG(("CxeFileSaveThreadSymbian: woken up"));
       
   143 
       
   144         }
       
   145 
       
   146         // There should be data now, because the thread is woken up
       
   147         read();
       
   148 
       
   149         if (mCount > 0) {
       
   150             // Save one item now.
       
   151             saveNow();
       
   152         }
       
   153 
       
   154         // If we did start harvesting, check if there's signal waiting
       
   155         // for harvesting completed already.
       
   156         if(mActiveHarvests > 0) {
       
   157             msleep(SLEEP_MS_FOR_SIGNALS);
       
   158             QCoreApplication::processEvents();
       
   159         }
       
   160 
       
   161         // Saving takes some seconds, there might be new data available.
       
   162         read();
       
   163     }
       
   164 
       
   165     // Cleanup in the same thread as init() was done.
       
   166     deinit();
       
   167 
       
   168     CX_DEBUG_EXIT_FUNCTION();
       
   169 }
       
   170 
       
   171 /**
       
   172 * Slot for saved video signal.
       
   173 */
       
   174 void CxeFileSaveThreadSymbian::handleVideoSaved(CxeError::Id status, const QString& filename) {
       
   175     CX_DEBUG_ENTER_FUNCTION();
       
   176     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   177     CX_DEBUG(("status = %d filename = %s", status, filename.toAscii().constData()));
       
   178 
       
   179     if (status == CxeError::None) {
       
   180         // Use a dummy "image data item" with empty data and saved state for videos.
       
   181         // We just need to harvest the file and provide snapshot to Thumbnail Manager.
       
   182         QByteArray empty;
       
   183         CxeImageDataItem* item = new CxeImageDataItemSymbian(empty, filename, CxeStillImage::INVALID_ID, CxeImageDataItem::Saved);
       
   184         if(item) {
       
   185             save(item);
       
   186         }
       
   187     }
       
   188     CX_DEBUG_EXIT_FUNCTION();
       
   189 }
       
   190 
       
   191 void CxeFileSaveThreadSymbian::handleSnapshotReady(CxeError::Id status, const QPixmap& snapshot, const QString& filename)
       
   192 {
       
   193     CX_DEBUG_ENTER_FUNCTION();
       
   194     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   195     CX_DEBUG(("status = %d filename = %s", status, filename.toAscii().constData()));
       
   196 
       
   197     if (status == CxeError::None) {
       
   198         // Store snapshot.
       
   199         if (!snapshot.isNull()) {
       
   200             // QMutexLocker handles locking and unlocking automaticly.
       
   201             QMutexLocker lock(&mSnapshotsMutex);
       
   202 
       
   203             //!@todo: Store as QImage once TNM API is fixed.
       
   204             mSnapshots.insert(filename, snapshot);
       
   205         }
       
   206     }
       
   207 
       
   208     CX_DEBUG_EXIT_FUNCTION();
       
   209 }
       
   210 
       
   211 void CxeFileSaveThreadSymbian::handleSnapshotReady(CxeError::Id status, const QPixmap& snapshot, int id)
       
   212 {
       
   213     CX_DEBUG_ENTER_FUNCTION();
       
   214     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   215     CX_DEBUG(("status = %d id = %d", status, id));
       
   216     // Using id number as "filename" for images as filename is not available
       
   217     // at the time of snapshot for still images (and preparing the filename
       
   218     // would be slowing down showing the snapshot).
       
   219     handleSnapshotReady(status, snapshot, QString::number(id));
       
   220     CX_DEBUG_EXIT_FUNCTION();
       
   221 }
       
   222 
       
   223 /**
       
   224 * Slot to handle harvested file.
       
   225 * @param status Status of the harvesting.
       
   226 * @param filename Path of the file just harvested.
       
   227 */
       
   228 void CxeFileSaveThreadSymbian::handleFileHarvested(CxeError::Id status, const QString& filename)
       
   229 {
       
   230     CX_DEBUG_ENTER_FUNCTION();
       
   231     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   232     CX_DEBUG(("status = %d filename = %s", status, filename.toAscii().constData()));
       
   233 
       
   234     // Synchronize snapshots container access.
       
   235     QMutexLocker lock(&mSnapshotsMutex);
       
   236 
       
   237     // Decrease count to enable sleeping in main loop
       
   238     // if nothing to save is available.
       
   239     --mActiveHarvests;
       
   240 
       
   241     if (status == KErrNone && mThumbnailManager) {
       
   242         if (mSnapshots.contains(filename)) {
       
   243             // File has been successfully harvested,
       
   244             // let's provide the snapshot to Thumbnail Manager.
       
   245             mThumbnailManager->createThumbnail(filename, mSnapshots[filename]);
       
   246         }
       
   247     }
       
   248 
       
   249     // Releasing the snapshot if it exists.
       
   250     mSnapshots.remove(filename);
       
   251 
       
   252     CX_DEBUG_EXIT_FUNCTION();
       
   253 }
       
   254 
       
   255 /**
       
   256 * Init the utility classes.
       
   257 */
       
   258 void CxeFileSaveThreadSymbian::init()
       
   259 {
       
   260     // Create the thumbnail manager and harvester control objects in the new thread.
       
   261     if (!mThumbnailManager) {
       
   262         mThumbnailManager = new CxeThumbnailManagerSymbian();
       
   263     }
       
   264     if (!mHarvesterControl) {
       
   265         mHarvesterControl = new CxeHarvesterControlSymbian();
       
   266         connect(mHarvesterControl, SIGNAL(fileHarvested(CxeError::Id, const QString&)),
       
   267                 this, SLOT(handleFileHarvested(CxeError::Id, const QString&)),
       
   268                 Qt::DirectConnection);
       
   269     }
       
   270 }
       
   271 
       
   272 /**
       
   273 * Clean up the utility classes
       
   274 */
       
   275 void CxeFileSaveThreadSymbian::deinit()
       
   276 {
       
   277     // Delete in the same thread where created.
       
   278     CX_DEBUG(("CxeFileSaveThreadSymbian: delete Thumbnail Manager"));
       
   279     delete mThumbnailManager;
       
   280     mThumbnailManager = NULL;
       
   281     CX_DEBUG(("CxeFileSaveThreadSymbian: delete Harvester Control"));
       
   282     delete mHarvesterControl;
       
   283     mHarvesterControl = NULL;
       
   284 }
       
   285 
       
   286 
       
   287 
       
   288 /**
       
   289 * Save the item now.
       
   290 */
       
   291 void CxeFileSaveThreadSymbian::saveNow()
       
   292 {
       
   293     CX_DEBUG_ENTER_FUNCTION();
       
   294     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   295 
       
   296     CxeImageDataItem* item(mQueue.dequeue());
       
   297     if (item ) {
       
   298         // If item needs to be saved, do it now.
       
   299         if( item->state() == CxeImageDataItem::SavePending) {
       
   300             // Save the item.
       
   301             // Error ignored since we'll check the state.
       
   302             item->save();
       
   303         }
       
   304 
       
   305         CX_DEBUG(("Item state after saving: %d", item->state()));
       
   306         // If item is saved ok, ask to harvest it now.
       
   307         if (item->state() == CxeImageDataItem::Saved) {
       
   308 
       
   309             QString path(item->path());
       
   310 
       
   311             if (item->id() != CxeStillImage::INVALID_ID) {
       
   312                 // Synchronize snapshots container access.
       
   313                 QMutexLocker lock(&mSnapshotsMutex);
       
   314 
       
   315                 // If snapshot was stored using id as a "filename", replace key with real filename now,
       
   316                 // so we can find the snapshot when harvesting is ready.
       
   317                 QString idString(QString::number(item->id()));
       
   318                 if (mSnapshots.contains(idString)) {
       
   319                     const QPixmap& snapshot(mSnapshots[idString]);
       
   320                     mSnapshots.remove(idString);
       
   321                     mSnapshots.insert(path, snapshot);
       
   322                 }
       
   323             }
       
   324 
       
   325             harvestFile(path);
       
   326         }
       
   327 
       
   328         // Delete item, since we own it
       
   329         delete item;
       
   330         item = NULL;
       
   331     }
       
   332 
       
   333     CX_DEBUG_EXIT_FUNCTION();
       
   334 }
       
   335 
       
   336 /**
       
   337 * Harvest one file.
       
   338 * @param filename Path of the file to be harvested.
       
   339 */
       
   340 void CxeFileSaveThreadSymbian::harvestFile(const QString& filename)
       
   341 {
       
   342     CX_DEBUG_ENTER_FUNCTION();
       
   343     if (mHarvesterControl) {
       
   344         // Synchronize snapshots container access.
       
   345         QMutexLocker lock(&mSnapshotsMutex);
       
   346 
       
   347         // harvest file ( filename, add to album, album id )
       
   348         CX_DEBUG(("Requesting harvesting for file: %s", filename.toAscii().constData()));
       
   349         CxeError::Id status = mHarvesterControl->harvestFile(filename, false, MDS_CAPTURED_ALBUM_ID);
       
   350         CX_DEBUG(("Status for starting harvesting: %d", status));
       
   351 
       
   352         // If there were errors, release any snapshot stored for this file.
       
   353         // Otherwise waiting for the harvesting to complete to
       
   354         // provide the snapshot to Thumbnail Manager.
       
   355         if(status != CxeError::None) {
       
   356             mSnapshots.remove(filename);
       
   357         } else {
       
   358             // Update count to process events in main loop.
       
   359             ++mActiveHarvests;
       
   360         }
       
   361     }
       
   362     CX_DEBUG_EXIT_FUNCTION();
       
   363 }