camerauis/cameraxui/cxengine/src/cxestillcapturecontrolsymbian.cpp
changeset 19 d9aefe59d544
child 21 fa6d9f75d6a6
child 28 3075d9b614e6
equal deleted inserted replaced
3:8b2d6d0384b0 19:d9aefe59d544
       
     1 /*
       
     2 * Copyright (c) 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:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <exception>
       
    20 #include <fbs.h>
       
    21 #include <QPixmap>
       
    22 #include <coemain.h>
       
    23 #include <ECamOrientationCustomInterface2.h>
       
    24 #include <ecam/camerasnapshot.h>
       
    25 #include <ecamfacetrackingcustomapi.h>
       
    26 
       
    27 #include "cxestillcapturecontrolsymbian.h"
       
    28 #include "cxeimagedataqueuesymbian.h"
       
    29 #include "cxefilenamegenerator.h"
       
    30 #include "cxefilesavethread.h"
       
    31 #include "cxutils.h"
       
    32 #include "cxesysutil.h"
       
    33 #include "cxecameradevicecontrol.h"
       
    34 #include "cxecameradevice.h"
       
    35 #include "cxesoundplayersymbian.h"
       
    36 #include "cxestillimagesymbian.h"
       
    37 #include "cxeviewfindercontrol.h"
       
    38 #include "cxeviewfindercontrolsymbian.h"
       
    39 #include "cxesettingsmappersymbian.h"
       
    40 #include "cxestate.h"
       
    41 #include "cxesettings.h"
       
    42 #include "cxeerrormappingsymbian.h"
       
    43 #include "cxeautofocuscontrol.h"
       
    44 #include "cxesensoreventhandler.h"
       
    45 #include "cxesensoreventhandler.h"
       
    46 #include "cxequalitypresetssymbian.h"
       
    47 
       
    48 #include "OstTraceDefinitions.h"
       
    49 #ifdef OST_TRACE_COMPILER_IN_USE
       
    50 #include "cxestillcapturecontrolsymbianTraces.h"
       
    51 #endif
       
    52 
       
    53 
       
    54 // constants
       
    55 const int KMaintainAspectRatio = false;
       
    56 const TInt64 KMinRequiredSpaceImage = 2000000;
       
    57 
       
    58 
       
    59 /**
       
    60  * Constructor.
       
    61  */
       
    62 CxeStillCaptureControlSymbian::CxeStillCaptureControlSymbian(
       
    63         CxeCameraDevice &cameraDevice,
       
    64         CxeViewfinderControl &viewfinderControl,
       
    65         CxeCameraDeviceControl &cameraDeviceControl,
       
    66         CxeFilenameGenerator &nameGenerator,
       
    67         CxeSensorEventHandler &sensorEventHandler,
       
    68         CxeAutoFocusControl &autoFocusControl,
       
    69         CxeSettings &settings,
       
    70         CxeQualityPresets &qualityPresets,
       
    71         CxeFileSaveThread &fileSaveThread)
       
    72 : CxeStateMachine("CxeStillCaptureControlSymbian"),
       
    73   mCameraDevice(cameraDevice),
       
    74   mViewfinderControl(viewfinderControl),
       
    75   mCameraDeviceControl(cameraDeviceControl),
       
    76   mFilenameGenerator(nameGenerator),
       
    77   mSensorEventHandler(sensorEventHandler),
       
    78   mAutoFocusControl(autoFocusControl),
       
    79   mSettings(settings),
       
    80   mQualityPresets(qualityPresets),
       
    81   mFileSaveThread(fileSaveThread),
       
    82   mMode(SingleImageCapture),
       
    83   mAfState(CxeAutoFocusControl::Unknown)
       
    84 {
       
    85     CX_DEBUG_ENTER_FUNCTION();
       
    86 
       
    87     qRegisterMetaType<CxeStillCaptureControl::State>();
       
    88     initializeStates();
       
    89     reset();
       
    90 
       
    91     // connect signals from cameraDevice to recieve events when camera reference changes
       
    92     connect(&cameraDevice, SIGNAL(prepareForCameraDelete()),
       
    93             this, SLOT(prepareForCameraDelete()));
       
    94     connect(&cameraDevice, SIGNAL(prepareForRelease()),
       
    95             this, SLOT(prepareForRelease()));
       
    96     connect(&cameraDevice, SIGNAL(cameraAllocated(CxeError::Id)),
       
    97             this, SLOT(handleCameraAllocated(CxeError::Id)));
       
    98     connect(&mSensorEventHandler,
       
    99             SIGNAL(sensorEvent(CxeSensorEventHandler::SensorType,QVariant)),
       
   100             this, SLOT(handleSensorEvent(CxeSensorEventHandler::SensorType,QVariant)));
       
   101 
       
   102     // enabling setting change callbacks to stillcapturecontrol
       
   103     connect(&mSettings, SIGNAL(settingValueChanged(const QString&,QVariant)),
       
   104             this, SLOT(handleSettingValueChanged(const QString&,QVariant)));
       
   105 
       
   106     // Connect ECam image buffer ready event
       
   107     connect(&mCameraDeviceControl, SIGNAL(imageBufferReady(MCameraBuffer*,int)),
       
   108             this, SLOT(handleImageData(MCameraBuffer*,int)));
       
   109     // Connect signals for ECam events
       
   110     connect(&mCameraDeviceControl, SIGNAL(cameraEvent(int,int)),
       
   111             this, SLOT(handleCameraEvent(int,int)));
       
   112 
       
   113     mImageDataQueue = new CxeImageDataQueueSymbian();
       
   114     mAutoFocusSoundPlayer = new CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::AutoFocus);
       
   115     mCaptureSoundPlayer = new CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::StillCapture);
       
   116 
       
   117     CX_DEBUG_EXIT_FUNCTION();
       
   118 }
       
   119 
       
   120 /**
       
   121  * Destructor.
       
   122  */
       
   123 CxeStillCaptureControlSymbian::~CxeStillCaptureControlSymbian()
       
   124 {
       
   125     CX_DEBUG_ENTER_FUNCTION();
       
   126 
       
   127     deinit();
       
   128     reset();
       
   129     mIcmSupportedImageResolutions.clear();
       
   130     mECamSupportedImageResolutions.clear();
       
   131     delete mImageDataQueue;
       
   132     delete mCaptureSoundPlayer;
       
   133     delete mAutoFocusSoundPlayer;
       
   134 
       
   135     CX_DEBUG_EXIT_FUNCTION();
       
   136 }
       
   137 
       
   138 /**
       
   139  * Return the current state.
       
   140  */
       
   141 CxeStillCaptureControl::State CxeStillCaptureControlSymbian::state() const
       
   142 {
       
   143     return static_cast<CxeStillCaptureControl::State>( stateId() );
       
   144 }
       
   145 
       
   146 /**
       
   147  * Handle state changed event. Normally just emits the signal
       
   148  * for observers to react appropriately.
       
   149  */
       
   150 void CxeStillCaptureControlSymbian::handleStateChanged( int newStateId, CxeError::Id error )
       
   151 {
       
   152     emit stateChanged( static_cast<State>( newStateId ), error );
       
   153 }
       
   154 
       
   155 /**
       
   156  * Initialize the control states.
       
   157  */
       
   158 void CxeStillCaptureControlSymbian::initializeStates()
       
   159 {
       
   160     // addState( id, name, allowed next states )
       
   161     addState(new CxeState( Uninitialized , "Uninitialized", Ready));
       
   162     addState(new CxeState( Ready , "Ready", Uninitialized | Capturing));
       
   163     addState(new CxeState( Capturing , "Capturing", Uninitialized | Ready));
       
   164 
       
   165     setInitialState(Uninitialized);
       
   166 }
       
   167 
       
   168 /**
       
   169  * Initialize the still image capture control.
       
   170  */
       
   171 void CxeStillCaptureControlSymbian::init()
       
   172 {
       
   173     CX_DEBUG_ENTER_FUNCTION();
       
   174     OstTrace0(camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_STILL_CAPCONT_INIT 1");
       
   175 
       
   176     if (state() == Uninitialized) {
       
   177         prepare();
       
   178         // Initialize orientation sensor and other sensors
       
   179         mSensorEventHandler.init();
       
   180     }
       
   181 
       
   182     OstTrace0(camerax_performance, DUP1_CXESTILLCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_STILL_CAPCONT_INIT 0");
       
   183     CX_DEBUG_EXIT_FUNCTION();
       
   184 }
       
   185 
       
   186 /**
       
   187  * Un-initialize the image mode.
       
   188  */
       
   189 void CxeStillCaptureControlSymbian::deinit()
       
   190 {
       
   191     CX_DEBUG_ENTER_FUNCTION();
       
   192     OstTrace0( camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_STILL_CAPCONT_DEINIT 1" );
       
   193 
       
   194     if (state() == Uninitialized) {
       
   195         // nothing to do
       
   196         return;
       
   197     }
       
   198 
       
   199     //stop viewfinder
       
   200     mViewfinderControl.stop();
       
   201 
       
   202     // disable sensor event handler.
       
   203     mSensorEventHandler.deinit();
       
   204 
       
   205     if (mCameraDevice.cameraSnapshot()) {
       
   206         mCameraDevice.cameraSnapshot()->StopSnapshot();
       
   207     }
       
   208 
       
   209     if (state() == Capturing) {
       
   210         mCameraDevice.camera()->CancelCaptureImage();
       
   211     }
       
   212     setState(Uninitialized);
       
   213 
       
   214     OstTrace0( camerax_performance, DUP1_CXESTILLCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_STILL_CAPCONT_DEINIT 0" );
       
   215     CX_DEBUG_EXIT_FUNCTION();
       
   216 }
       
   217 
       
   218 
       
   219 /**!
       
   220  * Prepare still capture mode.
       
   221  */
       
   222 void CxeStillCaptureControlSymbian::prepare()
       
   223 {
       
   224     CX_DEBUG_ENTER_FUNCTION();
       
   225 
       
   226     if (state() != Uninitialized) {
       
   227         // wrong state and we return
       
   228         return;
       
   229     }
       
   230 
       
   231     OstTrace0( camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_STILLCAPCONT_PREPARE 1" );
       
   232 
       
   233     int err = KErrNone;
       
   234     CxeError::Id cxErr = getImageQualityDetails(mCurrentImageDetails);
       
   235     int ecamStillResolutionIndex = 0;
       
   236 
       
   237     if (cxErr == CxeError::None) {
       
   238         int imageWidth =  mCurrentImageDetails.mWidth;
       
   239         int imageHeight = mCurrentImageDetails.mHeight;
       
   240         CX_DEBUG(("CxeStillCaptureControlSymbian::prepare <> resolution = (%d, %d)", imageWidth, imageHeight));
       
   241 
       
   242         TSize imageSize;
       
   243         imageSize.SetSize(imageWidth, imageHeight);
       
   244 
       
   245         if (mECamSupportedImageResolutions.count() > 0) {
       
   246             ecamStillResolutionIndex = mECamSupportedImageResolutions.indexOf(imageSize);
       
   247         }
       
   248 
       
   249         if (ecamStillResolutionIndex < 0) {
       
   250             CX_DEBUG(("CxeStillCaptureControlSymbian::prepare - WARNING! resolution not supported, falling back to index 0"));
       
   251             ecamStillResolutionIndex = 0;
       
   252         }
       
   253 
       
   254         // Prepare Image capture
       
   255         CCamera::TFormat imgFormat = supportedStillFormat(mCameraDeviceControl.cameraIndex());
       
   256         OstTrace0(camerax_performance, DUP2_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_IMAGE_CAPTURE 1");
       
   257         TRAP(err, mCameraDevice.camera()->PrepareImageCaptureL(imgFormat, ecamStillResolutionIndex));
       
   258         OstTrace0(camerax_performance, DUP3_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_IMAGE_CAPTURE 0");
       
   259 
       
   260         CX_DEBUG(("PrepareImageCaptureL done, err=%d, resolution index = %d", err, ecamStillResolutionIndex));
       
   261 
       
   262         if (!err) {
       
   263             // still capture prepare went fine, try preparing snapshot
       
   264             err = prepareStillSnapshot();
       
   265         }
       
   266     } else {
       
   267         err = KErrNotFound;
       
   268     }
       
   269 
       
   270     if (!err) {
       
   271         MCameraFaceTracking *faceTracking = mCameraDevice.faceTracking();
       
   272         if (faceTracking) {
       
   273             // Enable AF reticule drawing by adaptation
       
   274             TRAP_IGNORE(faceTracking->EnableFaceIndicatorsL(ETrue));
       
   275         }
       
   276 
       
   277         // Start viewfinder before claiming to be ready,
       
   278         // as e.g. pending capture might be started by state change,
       
   279         // and viewfinder start might have problems with just started capturing.
       
   280         // If viewfinder is already running, this call does nothing.
       
   281         mViewfinderControl.start();
       
   282 
       
   283         // Still capture and still snapshot are OK.
       
   284         // We can safely set state to READY.
       
   285         setState(Ready);
       
   286 
       
   287         // inform zoom control to prepare zoom
       
   288         emit prepareZoomForStill(ecamStillResolutionIndex);
       
   289     } else {
       
   290         CX_DEBUG(("Image Prepare FAILED! symbian error = %d", err));
       
   291         // release resources
       
   292         deinit();
       
   293     }
       
   294 
       
   295     // Inform interested parties that image mode has been prepared for capture
       
   296     emit imagePrepareComplete(CxeErrorHandlingSymbian::map(err));
       
   297 
       
   298     OstTrace0( camerax_performance, DUP1_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_STILLCAPCONT_PREPARE 0" );
       
   299 
       
   300     CX_DEBUG_EXIT_FUNCTION();
       
   301 }
       
   302 
       
   303 
       
   304 
       
   305 /**!
       
   306  Prepare still snapshot
       
   307  Returns symbian error code.
       
   308  */
       
   309 int CxeStillCaptureControlSymbian::prepareStillSnapshot()
       
   310 {
       
   311     CX_DEBUG_ENTER_FUNCTION();
       
   312 
       
   313     CCamera::CCameraSnapshot *cameraSnapshot = mCameraDevice.cameraSnapshot();
       
   314     CX_ASSERT_ALWAYS(cameraSnapshot);
       
   315 
       
   316     int err = KErrNone;
       
   317     // Whether or not we have postcapture on, we need the snapshot for Thumbnail Manager.
       
   318     if (cameraSnapshot) {
       
   319         // Cancel active snapshot
       
   320         cameraSnapshot->StopSnapshot();
       
   321 
       
   322         // Prepare snapshot
       
   323         CCamera::TFormat snapFormat = CCamera::EFormatFbsBitmapColor16MU;
       
   324         OstTrace0( camerax_performance, DUP4_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_SNAPSHOT 1" );
       
   325         TRAP(err, cameraSnapshot->PrepareSnapshotL(snapFormat,
       
   326                                                    getSnapshotSize(),
       
   327                                                    KMaintainAspectRatio));
       
   328         OstTrace0( camerax_performance, DUP5_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_SNAPSHOT 0" );
       
   329         CX_DEBUG(("PrepareSnapshotL done, err=%d", err));
       
   330 
       
   331         // Start snapshot if no errors encountered.
       
   332         if (err == KErrNone) {
       
   333             CX_DEBUG(("Start still snapshot"));
       
   334             cameraSnapshot->StartSnapshot();
       
   335         }
       
   336     } else {
       
   337         // No snapshot interface available. Report error.
       
   338         // Assert above takes care of this, but keeping this as an option.
       
   339         err = KErrNotReady;
       
   340     }
       
   341 
       
   342     CX_DEBUG_EXIT_FUNCTION();
       
   343 
       
   344     return err;
       
   345 }
       
   346 
       
   347 
       
   348 /**!
       
   349  imageInfo contains image qualities details
       
   350  Returns CxeError error code.
       
   351  */
       
   352 CxeError::Id CxeStillCaptureControlSymbian::getImageQualityDetails(CxeImageDetails &imageInfo)
       
   353 {
       
   354     CX_DEBUG_ENTER_FUNCTION();
       
   355 
       
   356     int imageQuality = 0;
       
   357     CxeError::Id err = CxeError::None;
       
   358     if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) {
       
   359         err = mSettings.get(CxeSettingIds::IMAGE_QUALITY, imageQuality);
       
   360 
       
   361         bool validQuality = (imageQuality >= 0 && imageQuality < mIcmSupportedImageResolutions.count());
       
   362 
       
   363         if (err == CxeError::None && validQuality ) {
       
   364             // get image quality details
       
   365             imageInfo = mIcmSupportedImageResolutions.at(imageQuality);
       
   366         } else {
       
   367             err = CxeError::NotFound;
       
   368             CX_DEBUG(("Invalid ImageQuality = %d", imageQuality));
       
   369         }
       
   370     } else {
       
   371         // we are in secondary camera
       
   372         // get secondary camera image quality details
       
   373        imageInfo = mIcmSupportedImageResolutions.at(imageQuality);
       
   374     }
       
   375 
       
   376     CX_DEBUG_EXIT_FUNCTION();
       
   377     return err;
       
   378 }
       
   379 
       
   380 
       
   381 /*!
       
   382 * Returns snapshot size. Snapshot size is calculated based on the
       
   383 * display resolution and current image aspect ratio.
       
   384 */
       
   385 TSize CxeStillCaptureControlSymbian::getSnapshotSize() const
       
   386 {
       
   387     CX_DEBUG_ENTER_FUNCTION();
       
   388 
       
   389     TSize snapshotSize;
       
   390 
       
   391     QSize deviceResolution = mViewfinderControl.deviceDisplayResolution();
       
   392     QSize size = QSize(mCurrentImageDetails.mWidth, mCurrentImageDetails.mHeight);
       
   393 
       
   394     // scale according to aspect ratio.
       
   395     size.scale(deviceResolution.width(), deviceResolution.height(), Qt::KeepAspectRatio);
       
   396     CX_DEBUG(("Still Snapshot size, (%d,%d)", size.width(), size.height()));
       
   397     snapshotSize.SetSize(size.width(), deviceResolution.height());
       
   398 
       
   399     CX_DEBUG_EXIT_FUNCTION();
       
   400 
       
   401     return snapshotSize;
       
   402 }
       
   403 
       
   404 
       
   405 /**
       
   406  * Command to start image capture now.
       
   407  */
       
   408 void CxeStillCaptureControlSymbian::capture()
       
   409 {
       
   410     CX_DEBUG_ENTER_FUNCTION();
       
   411     CX_ASSERT_ALWAYS(mCameraDevice.camera());
       
   412 
       
   413     // Play the capture sound and start image capture
       
   414     mCaptureSoundPlayer->play();
       
   415 
       
   416     setState(Capturing);
       
   417     mCameraDevice.camera()->CaptureImage();
       
   418 
       
   419     //! @todo: NOTE: This call may not stay here. It can move depending on the implementation for burst capture.
       
   420     if (mMode == BurstCapture) {
       
   421         // Start a new filename sequence
       
   422         mFilenameGenerator.startNewImageFilenameSequence();
       
   423     }
       
   424 
       
   425     CX_DEBUG_EXIT_FUNCTION();
       
   426 }
       
   427 
       
   428 
       
   429 /* !
       
   430 @Param cameraIndex indicates which camera we are in use, primary/secondary
       
   431 Returns the format we use for specific camera index.
       
   432 */
       
   433 CCamera::TFormat CxeStillCaptureControlSymbian::supportedStillFormat(Cxe::CameraIndex cameraIndex)
       
   434 {
       
   435     CX_DEBUG_ENTER_FUNCTION();
       
   436     Q_UNUSED(cameraIndex);
       
   437 
       
   438     // The same image format used for both primary and secodary cameras
       
   439     CCamera::TFormat imgFormat = CCamera::EFormatExif;
       
   440 
       
   441     CX_DEBUG_EXIT_FUNCTION();
       
   442 
       
   443     return imgFormat;
       
   444 }
       
   445 
       
   446 
       
   447 /**
       
   448  * Camera events. Only relevant one(s) are handled.
       
   449  */
       
   450 void CxeStillCaptureControlSymbian::handleCameraEvent(int eventUid, int error)
       
   451 {
       
   452     CX_DEBUG_ENTER_FUNCTION();
       
   453 
       
   454     if (eventUid == KUidECamEventSnapshotUidValue &&
       
   455         mCameraDeviceControl.mode() == Cxe::ImageMode) {
       
   456         handleSnapshotEvent(CxeErrorHandlingSymbian::map(error));
       
   457     }
       
   458 
       
   459     CX_DEBUG_EXIT_FUNCTION();
       
   460 }
       
   461 
       
   462 /**
       
   463  * Snapshot ready notification. Ask the snapshot from snapshot interface.
       
   464  * NB: Typically snapshot arrives before image data but can be in reverse
       
   465  * order as well.
       
   466  */
       
   467 void CxeStillCaptureControlSymbian::handleSnapshotEvent(CxeError::Id error)
       
   468 {
       
   469     CX_DEBUG_ENTER_FUNCTION();
       
   470 
       
   471     if (state() == CxeStillCaptureControl::Uninitialized) {
       
   472         // we ignore this event, when we are not active
       
   473         return;
       
   474     }
       
   475 
       
   476     OstTrace0( camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_HANDLESNAPSHOTEVENT, "msg: e_CX_HANDLE_SNAPSHOT 1" );
       
   477 
       
   478     // Get image container for current snapshot index.
       
   479     // Remember to increment counter.
       
   480     CxeStillImageSymbian* stillImage = getImageForIndex(mNextSnapshotIndex++);
       
   481 
       
   482     if (error == CxeError::None) {
       
   483         try {
       
   484             stillImage->setSnapshot(extractSnapshot());
       
   485         } catch (const std::exception& ex) {
       
   486             error = CxeError::General;
       
   487         }
       
   488     }
       
   489 
       
   490     // Emit snapshotReady signal in all cases (error or not)
       
   491     emit snapshotReady(error, stillImage->snapshot(), stillImage->id());
       
   492 
       
   493     // When the snapshot ready event is handled, prepare new filename.
       
   494     if (stillImage->filename().isEmpty()) {
       
   495         // Error ignored at this point, try again when image data arrives.
       
   496         prepareFilename(stillImage);
       
   497     }
       
   498 
       
   499     CX_DEBUG_EXIT_FUNCTION();
       
   500 }
       
   501 
       
   502 /**
       
   503 * Gets QPixmap snapshot from ECAM buffer, if available.
       
   504 * @param buffer ECAM buffer containing the snapshot data. Will be released when this
       
   505 * method returns, even on exception.
       
   506 */
       
   507 QPixmap CxeStillCaptureControlSymbian::extractSnapshot()
       
   508 {
       
   509     CX_DEBUG_ENTER_FUNCTION();
       
   510     QPixmap pixmap;
       
   511 
       
   512     if (mCameraDevice.cameraSnapshot()) {
       
   513 
       
   514         QT_TRAP_THROWING({
       
   515             RArray<TInt> frameIndex;
       
   516             CleanupClosePushL(frameIndex);
       
   517 
       
   518             MCameraBuffer &buffer(mCameraDevice.cameraSnapshot()->SnapshotDataL(frameIndex));
       
   519 
       
   520             // Make sure buffer is released on leave / exception
       
   521             CxeCameraBufferCleanup cleaner(&buffer);
       
   522             TInt firstImageIndex(frameIndex.Find(0));
       
   523             CFbsBitmap &snapshot(buffer.BitmapL(firstImageIndex));
       
   524 
       
   525             CleanupStack::PopAndDestroy(); // frameIndex
       
   526 
       
   527             TSize size = snapshot.SizeInPixels();
       
   528             TInt sizeInWords = size.iHeight * CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU) / sizeof(TUint32);
       
   529             CX_DEBUG(("size %d x %d, sizeInWords = %d", size.iWidth, size.iHeight, sizeInWords ));
       
   530 
       
   531             TUint32* pixelData = new (ELeave) TUint32[ sizeInWords ];
       
   532             // Convert to QImage
       
   533             snapshot.LockHeap();
       
   534             TUint32* dataPtr = snapshot.DataAddress();
       
   535             memcpy(pixelData, dataPtr, sizeof(TUint32)*sizeInWords);
       
   536             snapshot.UnlockHeap();
       
   537 
       
   538             CX_DEBUG(("Creating QImage"));
       
   539             QImage *snapImage = new QImage((uchar*)pixelData, size.iWidth, size.iHeight,
       
   540                                            CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU),
       
   541                                            QImage::Format_RGB32);
       
   542 
       
   543             pixmap = QPixmap::fromImage(*snapImage);
       
   544             delete [] pixelData;
       
   545             delete snapImage;
       
   546         });
       
   547     }
       
   548 
       
   549     CX_DEBUG_EXIT_FUNCTION();
       
   550     return pixmap;
       
   551 }
       
   552 
       
   553 /**
       
   554  * handleImageData: Image data received from ECam
       
   555  */
       
   556 void CxeStillCaptureControlSymbian::handleImageData( MCameraBuffer* cameraBuffer, int error )
       
   557 {
       
   558     CX_DEBUG_ENTER_FUNCTION();
       
   559 
       
   560     if (state() == CxeStillCaptureControl::Uninitialized) {
       
   561         // we ignore this event, when we are not active
       
   562         cameraBuffer->Release();
       
   563         return;
       
   564     }
       
   565 
       
   566     // Get image container for current image data index.
       
   567     // Remember to increment counter.
       
   568     CxeStillImageSymbian* stillImage = getImageForIndex(mNextImageDataIndex++);
       
   569 
       
   570     if (error) {
       
   571         // Indicate error in image capture to the UI.
       
   572         cameraBuffer->Release();
       
   573         emit imageCaptured(CxeErrorHandlingSymbian::map(error), stillImage->id());
       
   574         return;
       
   575     }
       
   576 
       
   577     // If filename is not available at this stage, then generate one now
       
   578     if (stillImage->filename().isEmpty()) {
       
   579         CxeError::Id cxErr = prepareFilename(stillImage);
       
   580         if (cxErr) {
       
   581             cameraBuffer->Release();
       
   582             emit imageCaptured(cxErr, stillImage->id());
       
   583             return;
       
   584         }
       
   585     }
       
   586 
       
   587     // Get the image data from the buffer
       
   588     TDesC8* data = NULL;
       
   589     TRAPD( symbErr, data = cameraBuffer->DataL(0) );
       
   590     CX_DEBUG(("dataError: %d, data: 0x%08x", symbErr, data));
       
   591 
       
   592     if (!data && !symbErr) {
       
   593         symbErr = KErrNoMemory;
       
   594     }
       
   595 
       
   596     // If data is available, initiate saving of image
       
   597     if (!symbErr) {
       
   598         //! @todo: this does a deep copy... we want to avoid this for performance/memory consumption reasons
       
   599         QByteArray byteArray( reinterpret_cast<const char*>( data->Ptr() ), data->Size() );
       
   600         data = NULL;
       
   601 
       
   602         // Save the image data
       
   603         CxeImageDataItemSymbian* dataItem = mImageDataQueue->startSave(byteArray, stillImage->filename(), stillImage->id());
       
   604         stillImage->setDataItem(dataItem);
       
   605         mFileSaveThread.save(dataItem); // Saving thread takes ownership of dataItem.
       
   606     }
       
   607 
       
   608     // ECam Camera buffer should always be released
       
   609     cameraBuffer->Release();
       
   610 
       
   611     // Inform interested parties about image capture
       
   612     emit imageCaptured(CxeErrorHandlingSymbian::map(symbErr), stillImage->id());
       
   613 
       
   614     // set state to ready, since capturing is complete
       
   615     setState(Ready);
       
   616 
       
   617     // image capture ready, before that we check if the orientation of the device changed during capture and if so, we set the new orientation
       
   618     setOrientation(mSensorEventHandler.sensorData(CxeSensorEventHandler::OrientationSensor));
       
   619 
       
   620     CX_DEBUG_EXIT_FUNCTION();
       
   621 }
       
   622 
       
   623 
       
   624 /**
       
   625  * Settings changed, needs updated
       
   626  */
       
   627 void CxeStillCaptureControlSymbian::handleSettingValueChanged(const QString& settingId, QVariant newValue)
       
   628 {
       
   629     CX_DEBUG_ENTER_FUNCTION();
       
   630 
       
   631     Q_UNUSED(newValue);
       
   632 
       
   633     if (settingId == CxeSettingIds::IMAGE_QUALITY) {
       
   634         // re-prepare for still
       
   635         if (state() == Ready) {
       
   636             deinit();
       
   637             init();
       
   638         }
       
   639     }
       
   640 
       
   641     CX_DEBUG_EXIT_FUNCTION();
       
   642 }
       
   643 
       
   644 /**
       
   645  * ECam reference changing, release resources
       
   646  */
       
   647 void CxeStillCaptureControlSymbian::prepareForCameraDelete()
       
   648 {
       
   649     CX_DEBUG_ENTER_FUNCTION();
       
   650     deinit();
       
   651     CX_DEBUG_EXIT_FUNCTION();
       
   652 }
       
   653 
       
   654 /**
       
   655  * Camera being released. Cancel ongoing capture, if any.
       
   656  */
       
   657 void CxeStillCaptureControlSymbian::prepareForRelease()
       
   658 {
       
   659     CX_DEBUG_ENTER_FUNCTION();
       
   660     deinit();
       
   661     CX_DEBUG_EXIT_FUNCTION();
       
   662 }
       
   663 
       
   664 /**
       
   665  *  New camera available,
       
   666  */
       
   667 void CxeStillCaptureControlSymbian::handleCameraAllocated(CxeError::Id error)
       
   668 {
       
   669     CX_DEBUG_ENTER_FUNCTION();
       
   670 
       
   671     if (error == CxeError::None) {
       
   672         // load all still resoultions supported by ecam
       
   673         mECamSupportedImageResolutions.clear();
       
   674         TCameraInfo cameraInfo;
       
   675         Cxe::CameraIndex cameraIndex = mCameraDeviceControl.cameraIndex();
       
   676         CCamera::TFormat imgFormat = supportedStillFormat(cameraIndex);
       
   677         mCameraDevice.camera()->CameraInfo(cameraInfo);
       
   678 
       
   679         for(int i = 0; i < cameraInfo.iNumImageSizesSupported; i++) {
       
   680             TSize size;
       
   681             mCameraDevice.camera()->EnumerateCaptureSizes(size, i, imgFormat);
       
   682             CX_DEBUG(("ECam supported resolution <> Size (%d): (%d,%d)", i, size.iWidth, size.iHeight));
       
   683             mECamSupportedImageResolutions.insert(i, size);
       
   684         }
       
   685 
       
   686         // load all still qualities supported by icm
       
   687         mIcmSupportedImageResolutions.clear();
       
   688         // get list of supported image qualities based on camera index
       
   689         mIcmSupportedImageResolutions = mQualityPresets.imageQualityPresets(cameraIndex);
       
   690 
       
   691         CX_DEBUG(("ECAM Supported Qualities count = %d", mECamSupportedImageResolutions.count()));
       
   692         CX_DEBUG(("ICM Supported Qualities count = %d", mIcmSupportedImageResolutions.count()));
       
   693     }
       
   694 
       
   695     CX_DEBUG_EXIT_FUNCTION();
       
   696 }
       
   697 
       
   698 /**
       
   699  * Return number of images captured (during current capture operation only).
       
   700  */
       
   701 int CxeStillCaptureControlSymbian::imageCount() const
       
   702 {
       
   703     return mImages.count();
       
   704 }
       
   705 
       
   706 /**
       
   707  * Reset the image array.
       
   708  */
       
   709 void CxeStillCaptureControlSymbian::reset()
       
   710 {
       
   711     CX_DEBUG_ENTER_FUNCTION();
       
   712 
       
   713     qDeleteAll( mImages );
       
   714     mImages.clear();
       
   715 
       
   716     mNextSnapshotIndex = 0;
       
   717     mNextImageDataIndex = 0;
       
   718 
       
   719     CX_DEBUG_EXIT_FUNCTION();
       
   720 }
       
   721 
       
   722 /**
       
   723  * This should cancel any ongoing image captures.
       
   724  */
       
   725 void CxeStillCaptureControlSymbian::cancelAll()
       
   726 {
       
   727     mImageDataQueue->clear();
       
   728     reset();
       
   729 }
       
   730 
       
   731 /**
       
   732  * Sets the current capture mode: SingleImageCapture / BurstCapture.
       
   733  */
       
   734 void CxeStillCaptureControlSymbian::setMode( CaptureMode mode )
       
   735 {
       
   736     mMode = mode;
       
   737 }
       
   738 
       
   739 /**
       
   740  * Returns the current capture mode.
       
   741  */
       
   742 CxeStillCaptureControl::CaptureMode CxeStillCaptureControlSymbian::mode() const
       
   743 {
       
   744     return mMode;
       
   745 }
       
   746 
       
   747 /**
       
   748  * Operator [] - returns the indexed image from capture array.
       
   749  */
       
   750 CxeStillImage &CxeStillCaptureControlSymbian::operator[]( int index )
       
   751 {
       
   752     return *mImages[ index ];
       
   753 }
       
   754 
       
   755 /**
       
   756  * Getter for image data queue.
       
   757  */
       
   758 CxeImageDataQueue &CxeStillCaptureControlSymbian::imageDataQueue()
       
   759 {
       
   760     return *mImageDataQueue;
       
   761 }
       
   762 
       
   763 /**
       
   764  * Generates a filename and sets it in the still image object.
       
   765  * Skips the process if filename already copied exists in the object. This
       
   766  * behaviour is required in rare cases where image data arrives before snapshot.
       
   767  */
       
   768 CxeError::Id
       
   769 CxeStillCaptureControlSymbian::prepareFilename(CxeStillImageSymbian *stillImage)
       
   770 {
       
   771     CxeError::Id err = CxeError::None;
       
   772     if (stillImage->filename().isEmpty()) {
       
   773         QString path;
       
   774 
       
   775         QString fileExt = mCurrentImageDetails.mImageFileExtension;
       
   776 
       
   777         if (mMode == SingleImageCapture) {
       
   778             err = mFilenameGenerator.generateFilename(path, fileExt);
       
   779         }
       
   780         else {
       
   781             err = mFilenameGenerator.nextImageFilenameInSequence(path, fileExt);
       
   782         }
       
   783 
       
   784         if (!err) {
       
   785             CX_DEBUG(( "Next image file path: %s", path.toAscii().constData() ));
       
   786             stillImage->setFilename(path);
       
   787         }
       
   788         else {
       
   789             //! @todo: Error ID can be returned by this function.
       
   790             // Also error can be detected from empty filename string.
       
   791             CX_DEBUG(("ERROR in filename generation. err:%d", err));
       
   792         }
       
   793     }
       
   794     return err;
       
   795 }
       
   796 
       
   797 /*!
       
   798 * Helper method to set orientation data from the orientation sensor
       
   799 */
       
   800 void CxeStillCaptureControlSymbian::setOrientation(QVariant sensorData)
       
   801 {
       
   802     CX_DEBUG_ENTER_FUNCTION();
       
   803 
       
   804     if (mCameraDevice.cameraOrientation() && state() == Ready) {
       
   805         Cxe::DeviceOrientation uiOrientation = qVariantValue<Cxe::DeviceOrientation >(sensorData);
       
   806         MCameraOrientation::TOrientation currentCameraOrientation = mCameraDevice.cameraOrientation()->Orientation();
       
   807         MCameraOrientation::TOrientation newCameraOrientation = CxeSettingsMapperSymbian::Map2CameraOrientation(uiOrientation);
       
   808 
       
   809         CX_DEBUG((("cameraindex: %d mMode: %d state(): %d mAfState: %d uiOrientation: %d "),mCameraDeviceControl.cameraIndex(),
       
   810                 mMode, state(), mAfState, uiOrientation ));
       
   811         if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex &&
       
   812             mMode                              == SingleImageCapture &&
       
   813             uiOrientation                      != Cxe::OrientationNone &&
       
   814             currentCameraOrientation           != newCameraOrientation &&
       
   815            (mAfState                           == CxeAutoFocusControl::Unknown ||
       
   816             mAfState                           == CxeAutoFocusControl::Canceling)
       
   817         ) {
       
   818             CX_DEBUG(("Setting Orientation to adaptation"));
       
   819             TRAP_IGNORE(mCameraDevice.cameraOrientation()->SetOrientationL(newCameraOrientation));
       
   820         }
       
   821     }
       
   822 
       
   823     CX_DEBUG_EXIT_FUNCTION();
       
   824 }
       
   825 
       
   826 /**
       
   827  * Get the image container at given index or create a new one if needed.
       
   828  */
       
   829 CxeStillImageSymbian* CxeStillCaptureControlSymbian::getImageForIndex(int index)
       
   830 {
       
   831     CxeStillImageSymbian* image(NULL);
       
   832 
       
   833     if (mImages.count() <= index) {
       
   834         image = new CxeStillImageSymbian();
       
   835         mImages.append(image);
       
   836     } else {
       
   837         CX_DEBUG_ASSERT( mNextImageDataIndex >= 0 && index < mImages.count() );
       
   838         image = mImages[index];
       
   839     }
       
   840     return image;
       
   841 }
       
   842 
       
   843 
       
   844 /*!
       
   845 * Slot to handle Autofocus events.
       
   846 */
       
   847 void CxeStillCaptureControlSymbian::handleAutofocusStateChanged(
       
   848                                          CxeAutoFocusControl::State newState,
       
   849                                          CxeError::Id /*error*/ )
       
   850 {
       
   851     CX_DEBUG_ENTER_FUNCTION();
       
   852     mAfState = newState;
       
   853     CxeAutoFocusControl::Mode mode = mAutoFocusControl.mode();
       
   854 
       
   855     // if focused and in correct mode, play sound
       
   856     if  (newState == CxeAutoFocusControl::Ready &&
       
   857          mode != CxeAutoFocusControl::Hyperfocal &&
       
   858          mode != CxeAutoFocusControl::Infinity) {
       
   859         mAutoFocusSoundPlayer->play();
       
   860     }
       
   861     CX_DEBUG_EXIT_FUNCTION();
       
   862 }
       
   863 
       
   864 
       
   865 /*!
       
   866 * Slot that sets orientation data emited from orientation sensor
       
   867 */
       
   868 void CxeStillCaptureControlSymbian::handleSensorEvent(
       
   869                                 CxeSensorEventHandler::SensorType type,
       
   870                                 QVariant data)
       
   871 {
       
   872     CX_DEBUG_ENTER_FUNCTION();
       
   873 
       
   874     if (type == CxeSensorEventHandler::OrientationSensor) {
       
   875         setOrientation(data);
       
   876     } else {
       
   877         // nothing to do
       
   878     }
       
   879 
       
   880     CX_DEBUG_EXIT_FUNCTION();
       
   881 }
       
   882 
       
   883 
       
   884 /*!
       
   885 * Returns supported image qualities based on the camera index
       
   886 * (primary/secondary).
       
   887 */
       
   888 QList<CxeImageDetails> CxeStillCaptureControlSymbian::supportedImageQualities()
       
   889 {
       
   890     // update remaining images counter
       
   891     updateRemainingImagesCounter();
       
   892 
       
   893     return mIcmSupportedImageResolutions;
       
   894 }
       
   895 
       
   896 
       
   897 /*!
       
   898 * Updates remaining images counter to all the image qualities supported by ICM
       
   899 * this should be done whenever storage location setting changes and when values are
       
   900 * read from ICM for the first time
       
   901 */
       
   902 void CxeStillCaptureControlSymbian::updateRemainingImagesCounter()
       
   903 {
       
   904     CX_DEBUG_ENTER_FUNCTION();
       
   905 
       
   906     for( int index = 0; index < mIcmSupportedImageResolutions.count(); index++) {
       
   907         CxeImageDetails &qualityDetails = mIcmSupportedImageResolutions[index];
       
   908         qualityDetails.mPossibleImages = calculateRemainingImages(qualityDetails.mEstimatedSize);
       
   909     }
       
   910 
       
   911     CX_DEBUG_EXIT_FUNCTION();
       
   912 }
       
   913 
       
   914 
       
   915 /*!
       
   916 * Returns the number of images left for the current image quality setting
       
   917 */
       
   918 int CxeStillCaptureControlSymbian::imagesLeft()
       
   919 {
       
   920     return calculateRemainingImages(mCurrentImageDetails.mEstimatedSize);
       
   921 }
       
   922 
       
   923 
       
   924 
       
   925 /*!
       
   926 * CxeStillCaptureControlSymbian::calculateRemainingImages
       
   927 @ param estimatedImagesize, the estimated size for image resolution
       
   928 @ returns number of images remaining
       
   929 */
       
   930 int
       
   931 CxeStillCaptureControlSymbian::calculateRemainingImages(int estimatedImagesize)
       
   932 {
       
   933     CX_DEBUG_ENTER_FUNCTION();
       
   934 
       
   935     //Check the memory in-use setting
       
   936     qint64 memoryfree = CxeSysUtil::spaceAvailable(CCoeEnv::Static()->FsSession(), mSettings);
       
   937 
       
   938     memoryfree = memoryfree - KMinRequiredSpaceImage;
       
   939 
       
   940     if (memoryfree < 0) {
       
   941         memoryfree = 0; // exception, inform ui
       
   942     }
       
   943     qint64 images = memoryfree / estimatedImagesize;
       
   944 
       
   945     CX_DEBUG_EXIT_FUNCTION();
       
   946 
       
   947   return images;
       
   948 }
       
   949 
       
   950 // end of file