camerauis/cameraxui/cxengine/src/cxestillcapturecontroldesktop.cpp
branchRCL_3
changeset 24 bac7acad7cb3
parent 23 61bc0f252b2b
child 25 2c87b2808fd7
equal deleted inserted replaced
23:61bc0f252b2b 24:bac7acad7cb3
     1 /*
       
     2 * Copyright (c) 2010 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:
       
    15 *
       
    16 */
       
    17 
       
    18 #include <QPixmap>
       
    19 
       
    20 #include "cxestillcapturecontroldesktop.h"
       
    21 #include "cxeimagedataitemdesktop.h"
       
    22 #include "cxeimagedataqueuedesktop.h"
       
    23 #include "cxefilenamegenerator.h"
       
    24 #include "cxefilesavethreaddesktop.h"
       
    25 #include "cxutils.h"
       
    26 #include "cxecameradevicecontrol.h"
       
    27 #include "cxestillimagedesktop.h"
       
    28 #include "cxeviewfindercontrol.h"
       
    29 #include "cxeviewfindercontroldesktop.h"
       
    30 #include "cxeautofocuscontrol.h"
       
    31 #include "cxestate.h"
       
    32 #include "cxecameradevicedesktop.h"
       
    33 
       
    34 // constants
       
    35 const int KMaintainAspectRatio = false;
       
    36 
       
    37 
       
    38 
       
    39 /**
       
    40  * Constructor.
       
    41  */
       
    42 CxeStillCaptureControlDesktop::CxeStillCaptureControlDesktop(
       
    43         CxeCameraDeviceDesktop &cameraDevice,
       
    44         CxeViewfinderControl &viewfinderControl,
       
    45         CxeCameraDeviceControl &cameraDeviceControl,
       
    46         CxeFilenameGenerator &nameGenerator,
       
    47         CxeAutoFocusControl &autoFocusControl,
       
    48         CxeFileSaveThread &saveThread) :
       
    49   mCameraDevice(cameraDevice),
       
    50   mState(CxeStillCaptureControl::Uninitialized),
       
    51   mViewfinderControl(viewfinderControl),
       
    52   mCameraDeviceControl(cameraDeviceControl),
       
    53   mFilenameGenerator(nameGenerator),
       
    54   mAutoFocusControl(autoFocusControl),
       
    55   mMode(SingleImageCapture),
       
    56   mAfState(CxeAutoFocusControl::Unknown),
       
    57   mSaveThread(saveThread)
       
    58 {
       
    59     CX_DEBUG_ENTER_FUNCTION();
       
    60 
       
    61     qRegisterMetaType<CxeStillCaptureControl::State>();
       
    62     initializeStates();
       
    63     reset();
       
    64 
       
    65     mImageDataQueue = new CxeImageDataQueueDesktop();
       
    66 
       
    67     CX_DEBUG_EXIT_FUNCTION();
       
    68 }
       
    69 
       
    70 /**
       
    71  * Destructor.
       
    72  */
       
    73 CxeStillCaptureControlDesktop::~CxeStillCaptureControlDesktop()
       
    74 {
       
    75     CX_DEBUG_ENTER_FUNCTION();
       
    76 
       
    77     deinit();
       
    78     reset();
       
    79     mSupportedImageQualities.clear();
       
    80     delete mImageDataQueue;
       
    81 
       
    82     CX_DEBUG_EXIT_FUNCTION();
       
    83 }
       
    84 
       
    85 /**
       
    86  * Return the current state.
       
    87  */
       
    88 CxeStillCaptureControl::State CxeStillCaptureControlDesktop::state() const
       
    89 {
       
    90     return mState;
       
    91 }
       
    92 
       
    93 /**
       
    94  * Initialize the control states.
       
    95  */
       
    96 void CxeStillCaptureControlDesktop::initializeStates()
       
    97 {
       
    98 
       
    99     // addState( id, name, allowed next states )
       
   100 }
       
   101 
       
   102 /**
       
   103  * Initialize the still image capture control.
       
   104  */
       
   105 void CxeStillCaptureControlDesktop::init()
       
   106 {
       
   107     CX_DEBUG_ENTER_FUNCTION();
       
   108 
       
   109     if (state() == Uninitialized) {
       
   110         CxeImageDetails dummyDetails;
       
   111         dummyDetails.mAspectRatio = Cxe::AspectRatio4to3;
       
   112         dummyDetails.mEstimatedSize = 10000;
       
   113         dummyDetails.mHeight = 360;
       
   114         dummyDetails.mWidth = 640;
       
   115         mSupportedImageQualities.append(dummyDetails);
       
   116         prepare();
       
   117     }
       
   118 
       
   119     CX_DEBUG_EXIT_FUNCTION();
       
   120 }
       
   121 
       
   122 /**
       
   123  * Un-initialize the image mode.
       
   124  */
       
   125 void CxeStillCaptureControlDesktop::deinit()
       
   126 {
       
   127     CX_DEBUG_ENTER_FUNCTION();
       
   128 
       
   129     if (state() == Uninitialized) {
       
   130         // nothing to do
       
   131         CX_DEBUG_EXIT_FUNCTION();
       
   132         return;
       
   133     }
       
   134     mState = Uninitialized;
       
   135     CX_DEBUG_EXIT_FUNCTION();
       
   136 }
       
   137 
       
   138 
       
   139 /*!
       
   140  * Prepare still capture mode.
       
   141  */
       
   142 void CxeStillCaptureControlDesktop::prepare()
       
   143 {
       
   144     CX_DEBUG_ENTER_FUNCTION();
       
   145 
       
   146     if (state() != Uninitialized) {
       
   147         // wrong state and we return
       
   148         return;
       
   149     }
       
   150 
       
   151     int err = 0;
       
   152     CxeError::Id cxErr = getImageQualityDetails(mCurrentImageDetails);
       
   153     int ecamStillResolutionIndex = 0;
       
   154 
       
   155     if (cxErr == CxeError::None) {
       
   156         int imageWidth =  mCurrentImageDetails.mWidth;
       
   157         int imageHeight = mCurrentImageDetails.mHeight;
       
   158         CX_DEBUG(("CxeStillCaptureControlSymbian::prepare <> resolution = (%d, %d)", imageWidth, imageHeight));
       
   159 
       
   160         if (ecamStillResolutionIndex < 0) {
       
   161             CX_DEBUG(("CxeStillCaptureControlSymbian::prepare - WARNING! resolution not supported, falling back to index 0"));
       
   162             ecamStillResolutionIndex = 0;
       
   163         }
       
   164 
       
   165         CX_DEBUG(("PrepareImageCaptureL done, err=%d, resolution index = %d", err, ecamStillResolutionIndex));
       
   166 
       
   167         if (!err) {
       
   168             // still capture prepare went fine, try preparing snapshot
       
   169             err = prepareStillSnapshot();
       
   170         }
       
   171     } else {
       
   172         err = 0;
       
   173     }
       
   174 
       
   175     if (!err) {
       
   176         // If viewfinder is already running, this call does nothing
       
   177         mViewfinderControl.start();
       
   178         // inform zoom control to prepare zoom
       
   179         emit prepareZoomForStill(ecamStillResolutionIndex);
       
   180     } else {
       
   181         CX_DEBUG(("Image Prepare FAILED! symbian error = %d", err));
       
   182     }
       
   183     mState = Ready;
       
   184     emit imagePrepareComplete(CxeError::None);
       
   185     CX_DEBUG_EXIT_FUNCTION();
       
   186 }
       
   187 
       
   188 
       
   189 
       
   190 /*!
       
   191  Prepare still snapshot
       
   192  Returns symbian error code.
       
   193  */
       
   194 int CxeStillCaptureControlDesktop::prepareStillSnapshot()
       
   195 {
       
   196     CX_DEBUG_ENTER_FUNCTION();
       
   197 
       
   198     handleSnapshotEvent(CxeError::None);
       
   199 
       
   200     CX_DEBUG_EXIT_FUNCTION();
       
   201 
       
   202     return 0;
       
   203 }
       
   204 
       
   205 
       
   206 /*!
       
   207  imageInfo contains image qualities details
       
   208  Returns CxeError error code.
       
   209  */
       
   210 CxeError::Id CxeStillCaptureControlDesktop::getImageQualityDetails(CxeImageDetails &imageInfo)
       
   211 {
       
   212     CX_DEBUG_ENTER_FUNCTION();
       
   213 
       
   214     int imageQuality = 0;
       
   215     CxeError::Id err = CxeError::None;
       
   216     if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) {
       
   217         bool validQuality = (imageQuality >= 0 && imageQuality < mSupportedImageQualities.count());
       
   218 
       
   219         if (err == CxeError::None && validQuality ) {
       
   220             // get image quality details
       
   221             imageInfo = mSupportedImageQualities.at(imageQuality);
       
   222         } else {
       
   223             err = CxeError::NotFound;
       
   224             CX_DEBUG(("Invalid ImageQuality = %d", imageQuality));
       
   225         }
       
   226     } else {
       
   227         // we are in secondary camera
       
   228         // get secondary camera image quality details
       
   229        imageInfo = mSupportedImageQualities.at(imageQuality);
       
   230     }
       
   231 
       
   232     CX_DEBUG_EXIT_FUNCTION();
       
   233     return err;
       
   234 }
       
   235 
       
   236 
       
   237 /**
       
   238  * Command to start image capture now.
       
   239  */
       
   240 void CxeStillCaptureControlDesktop::capture()
       
   241 {
       
   242     CX_DEBUG_ENTER_FUNCTION();
       
   243 
       
   244     //! @todo: NOTE: This call may not stay here. It can move depending on the implementation for burst capture.
       
   245     if (mMode == BurstCapture) {
       
   246         // Start a new filename sequence
       
   247         mFilenameGenerator.startNewImageFilenameSequence();
       
   248     }
       
   249     emit imageCaptured(CxeError::None, 0);
       
   250     handleSnapshotEvent(CxeError::None);
       
   251     CX_DEBUG_EXIT_FUNCTION();
       
   252 }
       
   253 
       
   254 
       
   255 /**
       
   256  * Snapshot ready notification. Ask the snapshot from snapshot interface.
       
   257  * NB: Typically snapshot arrives before image data but can be in reverse
       
   258  * order as well.
       
   259  */
       
   260 void CxeStillCaptureControlDesktop::handleSnapshotEvent(CxeError::Id error)
       
   261 {
       
   262     CX_DEBUG_ENTER_FUNCTION();
       
   263 
       
   264     if (state() == CxeStillCaptureControl::Uninitialized) {
       
   265         // we ignore this event, when we are not active
       
   266         return;
       
   267     }
       
   268 
       
   269     if (error) {
       
   270         emit snapshotReady(error, QImage(), 0);
       
   271     }
       
   272 
       
   273     // Get image container for current snapshot index.
       
   274     // Remember to increment counter.
       
   275     CxeStillImageDesktop* stillImage = getImageForIndex(mNextSnapshotIndex++);
       
   276 
       
   277     // When the snapshot ready event is handled, prepare new filename.
       
   278     if (stillImage->filename().isEmpty()) {
       
   279         // Error ignored at this point, try again when image data arrives.
       
   280         prepareFilename(stillImage);
       
   281     }
       
   282 
       
   283     CxeImageDataItem* dataItem = new CxeImageDataItemDesktop(mNextImageDataIndex++, stillImage->snapshot(), stillImage->filename(), stillImage->id());
       
   284 
       
   285     stillImage->setDataItem(dataItem);
       
   286 
       
   287     mSaveThread.save(dataItem);
       
   288 
       
   289     emit snapshotReady(CxeError::None, QImage(), stillImage->id());
       
   290     emit imageCaptured(CxeError::None, stillImage->id());
       
   291 
       
   292     mState = Ready;
       
   293     emit stateChanged(mState, CxeError::None);
       
   294 
       
   295     CX_DEBUG_EXIT_FUNCTION();
       
   296 }
       
   297 
       
   298 
       
   299 
       
   300 /**
       
   301  * Settings changed, needs updated
       
   302  */
       
   303 void CxeStillCaptureControlDesktop::handleSettingValueChanged(const QString& settingId,QVariant newValue)
       
   304 {
       
   305     CX_DEBUG_ENTER_FUNCTION();
       
   306 
       
   307     if (settingId == CxeSettingIds::FLASH_MODE) {
       
   308         updateFlashSetting(newValue);
       
   309     } else if (settingId == CxeSettingIds::LIGHT_SENSITIVITY) {
       
   310         updateISOSetting(newValue);
       
   311     } else if (settingId == CxeSettingIds::EV_COMPENSATION_VALUE) {
       
   312         updateEVCompensationSetting(newValue);
       
   313     } else if (settingId == CxeSettingIds::IMAGE_QUALITY) {
       
   314         // re-prepare for still
       
   315         deinit();
       
   316         init();
       
   317     } else {
       
   318         // do nothing
       
   319     }
       
   320     CX_DEBUG_EXIT_FUNCTION();
       
   321 }
       
   322 
       
   323 /**
       
   324  * Image Scene mode changed, needs updated
       
   325  */
       
   326 void CxeStillCaptureControlDesktop::handleSceneChanged(CxeScene& scene)
       
   327 {
       
   328     CX_DEBUG_ENTER_FUNCTION();
       
   329 
       
   330     if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex){
       
   331         CX_DEBUG_ASSERT(scene.count() != 0);
       
   332         // we are interested only in the following settings in this class scope
       
   333 
       
   334         if(scene.contains(CxeSettingIds::FLASH_MODE)) {
       
   335             CX_DEBUG(("CxeStillCaptureControlSymbian::handleSceneChanged scene->mFlashMode = %d", scene[CxeSettingIds::FLASH_MODE].toInt()));
       
   336             updateFlashSetting(scene[CxeSettingIds::FLASH_MODE]);
       
   337         }
       
   338 
       
   339         if(scene.contains(CxeSettingIds::LIGHT_SENSITIVITY)) {
       
   340             updateISOSetting(scene[CxeSettingIds::LIGHT_SENSITIVITY]);
       
   341         }
       
   342 
       
   343         if(scene.contains(CxeSettingIds::EV_COMPENSATION_VALUE)) {
       
   344             updateEVCompensationSetting(scene[CxeSettingIds::EV_COMPENSATION_VALUE]);
       
   345         }
       
   346     }
       
   347 
       
   348     CX_DEBUG_EXIT_FUNCTION();
       
   349 }
       
   350 
       
   351 /**
       
   352  * UpdateFlashSetting
       
   353  */
       
   354 void CxeStillCaptureControlDesktop::updateFlashSetting(QVariant newValue)
       
   355 {
       
   356     CX_DEBUG_ENTER_FUNCTION();
       
   357 
       
   358     Q_UNUSED(newValue);
       
   359 
       
   360     CX_DEBUG_EXIT_FUNCTION();
       
   361 }
       
   362 
       
   363 /**
       
   364  * UpdateISOSetting
       
   365  */
       
   366 void CxeStillCaptureControlDesktop::updateISOSetting(QVariant newValue)
       
   367 {
       
   368     CX_DEBUG_ENTER_FUNCTION();
       
   369 
       
   370     Q_UNUSED(newValue);
       
   371 
       
   372     CX_DEBUG_EXIT_FUNCTION();
       
   373 }
       
   374 
       
   375 /**
       
   376  * UpdateEVCompensationSetting
       
   377  */
       
   378 void CxeStillCaptureControlDesktop::updateEVCompensationSetting(QVariant newValue)
       
   379 {
       
   380     CX_DEBUG_ENTER_FUNCTION();
       
   381 
       
   382     Q_UNUSED(newValue);
       
   383 
       
   384 
       
   385     CX_DEBUG_EXIT_FUNCTION();
       
   386 }
       
   387 
       
   388 
       
   389 /**
       
   390  * ECam reference changing, release resources
       
   391  */
       
   392 void CxeStillCaptureControlDesktop::prepareForCameraDelete()
       
   393 {
       
   394     CX_DEBUG_ENTER_FUNCTION();
       
   395     deinit();
       
   396     CX_DEBUG_EXIT_FUNCTION();
       
   397 }
       
   398 
       
   399 /**
       
   400  * Camera being released. Cancel ongoing capture, if any.
       
   401  */
       
   402 void CxeStillCaptureControlDesktop::prepareForRelease()
       
   403 {
       
   404     CX_DEBUG_ENTER_FUNCTION();
       
   405     deinit();
       
   406     CX_DEBUG_EXIT_FUNCTION();
       
   407 }
       
   408 
       
   409 /**
       
   410  *  New camera available,
       
   411  */
       
   412 void CxeStillCaptureControlDesktop::handleCameraAllocated(CxeError::Id error)
       
   413 {
       
   414     CX_DEBUG_ENTER_FUNCTION();
       
   415 
       
   416     if (error == CxeError::None) {
       
   417         // load all still resoultions supported by ecam
       
   418         // load all still qualities supported by icm
       
   419         mSupportedImageQualities.clear();
       
   420         // get list of supported image qualities based on camera index
       
   421 
       
   422     }
       
   423 
       
   424     CX_DEBUG_EXIT_FUNCTION();
       
   425 }
       
   426 
       
   427 /**
       
   428  * Return number of images captured (during current capture operation only).
       
   429  */
       
   430 int CxeStillCaptureControlDesktop::imageCount() const
       
   431 {
       
   432     return mImages.count();
       
   433 }
       
   434 
       
   435 /**
       
   436  * Reset the image array.
       
   437  */
       
   438 void CxeStillCaptureControlDesktop::reset()
       
   439 {
       
   440     CX_DEBUG_ENTER_FUNCTION();
       
   441 
       
   442     qDeleteAll(mImages);
       
   443     mImages.clear();
       
   444 
       
   445     mNextSnapshotIndex = 0;
       
   446     mNextImageDataIndex = 0;
       
   447 
       
   448     CX_DEBUG_EXIT_FUNCTION();
       
   449 }
       
   450 
       
   451 /**
       
   452  * This should cancel any ongoing image captures.
       
   453  */
       
   454 void CxeStillCaptureControlDesktop::cancelAll()
       
   455 {
       
   456     mImageDataQueue->clear();
       
   457     reset();
       
   458 }
       
   459 
       
   460 /**
       
   461  * Sets the current capture mode: SingleImageCapture / BurstCapture.
       
   462  */
       
   463 void CxeStillCaptureControlDesktop::setMode(CaptureMode mode)
       
   464 {
       
   465     mMode = mode;
       
   466 }
       
   467 
       
   468 /**
       
   469  * Returns the current capture mode.
       
   470  */
       
   471 CxeStillCaptureControl::CaptureMode CxeStillCaptureControlDesktop::mode() const
       
   472 {
       
   473     return mMode;
       
   474 }
       
   475 
       
   476 /**
       
   477  * Operator [] - returns the indexed image from capture array.
       
   478  */
       
   479 CxeStillImage &CxeStillCaptureControlDesktop::operator[](int index)
       
   480 {
       
   481     return *mImages[ index ];
       
   482 }
       
   483 
       
   484 /**
       
   485  * Getter for image data queue.
       
   486  */
       
   487 CxeImageDataQueue &CxeStillCaptureControlDesktop::imageDataQueue()
       
   488 {
       
   489     return *mImageDataQueue;
       
   490 }
       
   491 
       
   492 /**
       
   493  * Generates a filename and sets it in the still image object.
       
   494  * Skips the process if filename already copied exists in the object. This
       
   495  * behaviour is required in rare cases where image data arrives before snapshot.
       
   496  */
       
   497 CxeError::Id CxeStillCaptureControlDesktop::prepareFilename(CxeStillImageDesktop *stillImage)
       
   498 {
       
   499     CxeError::Id err = CxeError::None;
       
   500     if (stillImage->filename().isEmpty()) {
       
   501         QString path;
       
   502 
       
   503         QString fileExt = mCurrentImageDetails.mImageFileExtension;
       
   504 
       
   505         if (mMode == SingleImageCapture) {
       
   506             err = mFilenameGenerator.generateFilename(path, fileExt);
       
   507         }
       
   508         else {
       
   509             err = mFilenameGenerator.nextImageFilenameInSequence(path, fileExt);
       
   510         }
       
   511 
       
   512         if (!err) {
       
   513             CX_DEBUG(( "Next image file path: %s", path.toAscii().constData() ));
       
   514             stillImage->setFilename(path);
       
   515         }
       
   516         else {
       
   517             //! @todo: Error ID can be returned by this function.
       
   518             // Also error can be detected from empty filename string.
       
   519             CX_DEBUG(("ERROR in filename generation. err:%d", err));
       
   520         }
       
   521     }
       
   522     return err;
       
   523 }
       
   524 
       
   525 /*!
       
   526 * Helper method to set orientation data from the orientation sensor
       
   527 */
       
   528 void CxeStillCaptureControlDesktop::setOrientation(QVariant sensorData)
       
   529 {
       
   530     CX_DEBUG_ENTER_FUNCTION();
       
   531 
       
   532     Q_UNUSED(sensorData);
       
   533 
       
   534     CX_DEBUG_EXIT_FUNCTION();
       
   535 }
       
   536 
       
   537 /**
       
   538  * Get the image container at given index or create a new one if needed.
       
   539  */
       
   540 CxeStillImageDesktop* CxeStillCaptureControlDesktop::getImageForIndex(int index)
       
   541 {
       
   542     CxeStillImageDesktop* image(NULL);
       
   543 
       
   544     if (mImages.count() <= index) {
       
   545         image = new CxeStillImageDesktop();
       
   546         image->setSnapshot(mCameraDevice.currentSnaphot());
       
   547         mImages.append(image);
       
   548     } else {
       
   549         CX_DEBUG_ASSERT( mNextImageDataIndex >= 0 && index < mImages.count() );
       
   550         image = mImages[index];
       
   551     }
       
   552     return image;
       
   553 }
       
   554 
       
   555 
       
   556 /*!
       
   557 * Slot to handle Autofocus events.
       
   558 */
       
   559 void CxeStillCaptureControlDesktop::handleAutofocusStateChanged(
       
   560                                          CxeAutoFocusControl::State newState,
       
   561                                          CxeError::Id /*error*/ )
       
   562 {
       
   563     CX_DEBUG_ENTER_FUNCTION();
       
   564 
       
   565     mAfState = newState;
       
   566     CxeAutoFocusControl::Mode mode = mAutoFocusControl.mode();
       
   567 
       
   568     // if focused and in correct mode, play sound
       
   569     if  (newState == CxeAutoFocusControl::Ready &&
       
   570          mode != CxeAutoFocusControl::Hyperfocal &&
       
   571          mode != CxeAutoFocusControl::Infinity) {
       
   572     }
       
   573     CX_DEBUG_EXIT_FUNCTION();
       
   574 }
       
   575 
       
   576 
       
   577 /*!
       
   578 * Returns supported image qualities based on the camera index
       
   579 * (primary/secondary).
       
   580 */
       
   581 QList<CxeImageDetails> CxeStillCaptureControlDesktop::supportedImageQualities()
       
   582 {
       
   583     return QList<CxeImageDetails>();
       
   584 }
       
   585 
       
   586 /*!
       
   587 * Returns the number of images left for the current image quality setting
       
   588 */
       
   589 int CxeStillCaptureControlDesktop::imagesLeft()
       
   590 {
       
   591     return 100; // Stub: Dummy value
       
   592 }
       
   593 
       
   594 // end of file