camerauis/cameraxui/cxengine/src/cxefilesavethreadsymbian.cpp
branchRCL_3
changeset 54 bac7acad7cb3
parent 53 61bc0f252b2b
child 57 2c87b2808fd7
equal deleted inserted replaced
53:61bc0f252b2b 54:bac7acad7cb3
     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,
       
   184                                                              filename,
       
   185                                                              CxeStillImage::INVALID_ID,
       
   186                                                              false,
       
   187                                                              CxeImageDataItem::Saved);
       
   188         if (item) {
       
   189             save(item);
       
   190         }
       
   191     }
       
   192 
       
   193     CX_DEBUG_EXIT_FUNCTION();
       
   194 }
       
   195 
       
   196 /*!
       
   197  * Handles snapshot event from CxeStillCaptureControl and CxeVideoCaptureControl.
       
   198  *
       
   199  * @param status Status of snapshot creation. CxeError::None if no error, otherwise contains the error code
       
   200  * @param snapshot Snapshot as QImage
       
   201  * @param filename Name of the file that the snapshot is from
       
   202  */
       
   203 void CxeFileSaveThreadSymbian::handleSnapshotReady(CxeError::Id status, const QImage& snapshot, const QString& filename)
       
   204 {
       
   205     CX_DEBUG_ENTER_FUNCTION();
       
   206     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   207     CX_DEBUG(("status = %d filename = %s", status, filename.toAscii().constData()));
       
   208 
       
   209     if (status == CxeError::None) {
       
   210         // Store snapshot.
       
   211         if (!snapshot.isNull()) {
       
   212             // QMutexLocker handles locking and unlocking automaticly.
       
   213             QMutexLocker lock(&mSnapshotsMutex);
       
   214             mSnapshots.insert(filename, snapshot);
       
   215         }
       
   216     }
       
   217 
       
   218     CX_DEBUG_EXIT_FUNCTION();
       
   219 }
       
   220 
       
   221 /*!
       
   222  * Handles snapshot event from CxeStillCaptureControl and CxeVideoCaptureControl.
       
   223  *
       
   224  * @param status Status of snapshot creation. CxeError::None if no error, otherwise contains the error code
       
   225  * @param snapshot Snapshot as QImage
       
   226  * @param id Id of the file that the snapshot is from
       
   227  */
       
   228 void CxeFileSaveThreadSymbian::handleSnapshotReady(CxeError::Id status, const QImage& snapshot, int id)
       
   229 {
       
   230     CX_DEBUG_ENTER_FUNCTION();
       
   231     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   232     CX_DEBUG(("status = %d id = %d", status, id));
       
   233     // Using id number as "filename" for images as filename is not available
       
   234     // at the time of snapshot for still images (and preparing the filename
       
   235     // would be slowing down showing the snapshot).
       
   236     handleSnapshotReady(status, snapshot, QString::number(id));
       
   237     CX_DEBUG_EXIT_FUNCTION();
       
   238 }
       
   239 
       
   240 /**
       
   241 * Slot to handle harvested file.
       
   242 * @param status Status of the harvesting.
       
   243 * @param filename Path of the file just harvested.
       
   244 */
       
   245 void CxeFileSaveThreadSymbian::handleFileHarvested(CxeError::Id status, const QString& filename)
       
   246 {
       
   247     CX_DEBUG_ENTER_FUNCTION();
       
   248     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   249     CX_DEBUG(("status = %d filename = %s", status, filename.toAscii().constData()));
       
   250 
       
   251     // Synchronize snapshots container access.
       
   252     QMutexLocker lock(&mSnapshotsMutex);
       
   253 
       
   254     // Decrease count to enable sleeping in main loop
       
   255     // if nothing to save is available.
       
   256     --mActiveHarvests;
       
   257 
       
   258     if (status == KErrNone && mThumbnailManager) {
       
   259         if (mSnapshots.contains(filename)) {
       
   260             // File has been successfully harvested,
       
   261             // let's provide the snapshot to Thumbnail Manager.
       
   262             mThumbnailManager->createThumbnail(filename, mSnapshots[filename]);
       
   263         }
       
   264     }
       
   265 
       
   266     // Releasing the snapshot if it exists.
       
   267     mSnapshots.remove(filename);
       
   268 
       
   269     CX_DEBUG_EXIT_FUNCTION();
       
   270 }
       
   271 
       
   272 /**
       
   273 * Init the utility classes.
       
   274 */
       
   275 void CxeFileSaveThreadSymbian::init()
       
   276 {
       
   277     // Create the thumbnail manager and harvester control objects in the new thread.
       
   278     if (!mThumbnailManager) {
       
   279         mThumbnailManager = new CxeThumbnailManagerSymbian();
       
   280     }
       
   281     if (!mHarvesterControl) {
       
   282         mHarvesterControl = new CxeHarvesterControlSymbian();
       
   283         connect(mHarvesterControl, SIGNAL(fileHarvested(CxeError::Id, const QString&)),
       
   284                 this, SLOT(handleFileHarvested(CxeError::Id, const QString&)),
       
   285                 Qt::DirectConnection);
       
   286     }
       
   287 }
       
   288 
       
   289 /**
       
   290 * Clean up the utility classes
       
   291 */
       
   292 void CxeFileSaveThreadSymbian::deinit()
       
   293 {
       
   294     // Delete in the same thread where created.
       
   295     CX_DEBUG(("CxeFileSaveThreadSymbian: delete Thumbnail Manager"));
       
   296     delete mThumbnailManager;
       
   297     mThumbnailManager = NULL;
       
   298     CX_DEBUG(("CxeFileSaveThreadSymbian: delete Harvester Control"));
       
   299     delete mHarvesterControl;
       
   300     mHarvesterControl = NULL;
       
   301 }
       
   302 
       
   303 
       
   304 
       
   305 /**
       
   306 * Save the item now.
       
   307 */
       
   308 void CxeFileSaveThreadSymbian::saveNow()
       
   309 {
       
   310     CX_DEBUG_ENTER_FUNCTION();
       
   311     CX_DEBUG(("[INFO] current thread 0x%x", QThread::currentThreadId()));
       
   312 
       
   313     CxeImageDataItem* item(mQueue.dequeue());
       
   314     if (item ) {
       
   315         // If item needs to be saved, do it now.
       
   316         if( item->state() == CxeImageDataItem::SavePending) {
       
   317             // Save the item.
       
   318             // Error ignored since we'll check the state.
       
   319             item->save();
       
   320         }
       
   321 
       
   322         CX_DEBUG(("Item state after saving: %d", item->state()));
       
   323         // If item is saved ok, ask to harvest it now.
       
   324         if (item->state() == CxeImageDataItem::Saved) {
       
   325 
       
   326             QString path(item->path());
       
   327 
       
   328             if (item->id() != CxeStillImage::INVALID_ID) {
       
   329                 // Synchronize snapshots container access.
       
   330                 QMutexLocker lock(&mSnapshotsMutex);
       
   331 
       
   332                 // If snapshot was stored using id as a "filename", replace key with real filename now,
       
   333                 // so we can find the snapshot when harvesting is ready.
       
   334                 QString idString(QString::number(item->id()));
       
   335                 if (mSnapshots.contains(idString)) {
       
   336                     QImage snapshot(mSnapshots[idString]);
       
   337                     mSnapshots.remove(idString);
       
   338                     mSnapshots.insert(path, snapshot);
       
   339                 }
       
   340             }
       
   341             CxeImageDataItemSymbian* item_s = qobject_cast<CxeImageDataItemSymbian*>(item);
       
   342             if (item_s) {
       
   343                 harvestFile(path, item_s->isLocationEnabled());
       
   344             }
       
   345         }
       
   346 
       
   347         // Delete item, since we own it
       
   348         delete item;
       
   349         item = NULL;
       
   350     }
       
   351 
       
   352     CX_DEBUG_EXIT_FUNCTION();
       
   353 }
       
   354 
       
   355 /**
       
   356 * Harvest one file.
       
   357 * @param filename Path of the file to be harvested.
       
   358 */
       
   359 void CxeFileSaveThreadSymbian::harvestFile(const QString& filename, bool addLocation)
       
   360 {
       
   361     CX_DEBUG_ENTER_FUNCTION();
       
   362     if (mHarvesterControl) {
       
   363         // Synchronize snapshots container access.
       
   364         QMutexLocker lock(&mSnapshotsMutex);
       
   365 
       
   366         // harvest file ( filename, add to album, album id )
       
   367         CX_DEBUG(("Requesting harvesting for file: %s addLocation = %d", filename.toAscii().constData(), addLocation));
       
   368         CxeError::Id status = mHarvesterControl->harvestFile(filename, addLocation, MDS_CAPTURED_ALBUM_ID);
       
   369         CX_DEBUG(("Status for starting harvesting: %d", status));
       
   370 
       
   371         // If there were errors, release any snapshot stored for this file.
       
   372         // Otherwise waiting for the harvesting to complete to
       
   373         // provide the snapshot to Thumbnail Manager.
       
   374         if(status != CxeError::None) {
       
   375             mSnapshots.remove(filename);
       
   376         } else {
       
   377             // Update count to process events in main loop.
       
   378             ++mActiveHarvests;
       
   379         }
       
   380     }
       
   381     CX_DEBUG_EXIT_FUNCTION();
       
   382 }