diff -r 8b2d6d0384b0 -r d9aefe59d544 camerauis/cameraxui/cxengine/src/cxestillcapturecontrolsymbian.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/camerauis/cameraxui/cxengine/src/cxestillcapturecontrolsymbian.cpp Fri Apr 16 14:51:30 2010 +0300 @@ -0,0 +1,950 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include +#include +#include +#include +#include +#include +#include + +#include "cxestillcapturecontrolsymbian.h" +#include "cxeimagedataqueuesymbian.h" +#include "cxefilenamegenerator.h" +#include "cxefilesavethread.h" +#include "cxutils.h" +#include "cxesysutil.h" +#include "cxecameradevicecontrol.h" +#include "cxecameradevice.h" +#include "cxesoundplayersymbian.h" +#include "cxestillimagesymbian.h" +#include "cxeviewfindercontrol.h" +#include "cxeviewfindercontrolsymbian.h" +#include "cxesettingsmappersymbian.h" +#include "cxestate.h" +#include "cxesettings.h" +#include "cxeerrormappingsymbian.h" +#include "cxeautofocuscontrol.h" +#include "cxesensoreventhandler.h" +#include "cxesensoreventhandler.h" +#include "cxequalitypresetssymbian.h" + +#include "OstTraceDefinitions.h" +#ifdef OST_TRACE_COMPILER_IN_USE +#include "cxestillcapturecontrolsymbianTraces.h" +#endif + + +// constants +const int KMaintainAspectRatio = false; +const TInt64 KMinRequiredSpaceImage = 2000000; + + +/** + * Constructor. + */ +CxeStillCaptureControlSymbian::CxeStillCaptureControlSymbian( + CxeCameraDevice &cameraDevice, + CxeViewfinderControl &viewfinderControl, + CxeCameraDeviceControl &cameraDeviceControl, + CxeFilenameGenerator &nameGenerator, + CxeSensorEventHandler &sensorEventHandler, + CxeAutoFocusControl &autoFocusControl, + CxeSettings &settings, + CxeQualityPresets &qualityPresets, + CxeFileSaveThread &fileSaveThread) +: CxeStateMachine("CxeStillCaptureControlSymbian"), + mCameraDevice(cameraDevice), + mViewfinderControl(viewfinderControl), + mCameraDeviceControl(cameraDeviceControl), + mFilenameGenerator(nameGenerator), + mSensorEventHandler(sensorEventHandler), + mAutoFocusControl(autoFocusControl), + mSettings(settings), + mQualityPresets(qualityPresets), + mFileSaveThread(fileSaveThread), + mMode(SingleImageCapture), + mAfState(CxeAutoFocusControl::Unknown) +{ + CX_DEBUG_ENTER_FUNCTION(); + + qRegisterMetaType(); + initializeStates(); + reset(); + + // connect signals from cameraDevice to recieve events when camera reference changes + connect(&cameraDevice, SIGNAL(prepareForCameraDelete()), + this, SLOT(prepareForCameraDelete())); + connect(&cameraDevice, SIGNAL(prepareForRelease()), + this, SLOT(prepareForRelease())); + connect(&cameraDevice, SIGNAL(cameraAllocated(CxeError::Id)), + this, SLOT(handleCameraAllocated(CxeError::Id))); + connect(&mSensorEventHandler, + SIGNAL(sensorEvent(CxeSensorEventHandler::SensorType,QVariant)), + this, SLOT(handleSensorEvent(CxeSensorEventHandler::SensorType,QVariant))); + + // enabling setting change callbacks to stillcapturecontrol + connect(&mSettings, SIGNAL(settingValueChanged(const QString&,QVariant)), + this, SLOT(handleSettingValueChanged(const QString&,QVariant))); + + // Connect ECam image buffer ready event + connect(&mCameraDeviceControl, SIGNAL(imageBufferReady(MCameraBuffer*,int)), + this, SLOT(handleImageData(MCameraBuffer*,int))); + // Connect signals for ECam events + connect(&mCameraDeviceControl, SIGNAL(cameraEvent(int,int)), + this, SLOT(handleCameraEvent(int,int))); + + mImageDataQueue = new CxeImageDataQueueSymbian(); + mAutoFocusSoundPlayer = new CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::AutoFocus); + mCaptureSoundPlayer = new CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::StillCapture); + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Destructor. + */ +CxeStillCaptureControlSymbian::~CxeStillCaptureControlSymbian() +{ + CX_DEBUG_ENTER_FUNCTION(); + + deinit(); + reset(); + mIcmSupportedImageResolutions.clear(); + mECamSupportedImageResolutions.clear(); + delete mImageDataQueue; + delete mCaptureSoundPlayer; + delete mAutoFocusSoundPlayer; + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Return the current state. + */ +CxeStillCaptureControl::State CxeStillCaptureControlSymbian::state() const +{ + return static_cast( stateId() ); +} + +/** + * Handle state changed event. Normally just emits the signal + * for observers to react appropriately. + */ +void CxeStillCaptureControlSymbian::handleStateChanged( int newStateId, CxeError::Id error ) +{ + emit stateChanged( static_cast( newStateId ), error ); +} + +/** + * Initialize the control states. + */ +void CxeStillCaptureControlSymbian::initializeStates() +{ + // addState( id, name, allowed next states ) + addState(new CxeState( Uninitialized , "Uninitialized", Ready)); + addState(new CxeState( Ready , "Ready", Uninitialized | Capturing)); + addState(new CxeState( Capturing , "Capturing", Uninitialized | Ready)); + + setInitialState(Uninitialized); +} + +/** + * Initialize the still image capture control. + */ +void CxeStillCaptureControlSymbian::init() +{ + CX_DEBUG_ENTER_FUNCTION(); + OstTrace0(camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_STILL_CAPCONT_INIT 1"); + + if (state() == Uninitialized) { + prepare(); + // Initialize orientation sensor and other sensors + mSensorEventHandler.init(); + } + + OstTrace0(camerax_performance, DUP1_CXESTILLCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_STILL_CAPCONT_INIT 0"); + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Un-initialize the image mode. + */ +void CxeStillCaptureControlSymbian::deinit() +{ + CX_DEBUG_ENTER_FUNCTION(); + OstTrace0( camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_STILL_CAPCONT_DEINIT 1" ); + + if (state() == Uninitialized) { + // nothing to do + return; + } + + //stop viewfinder + mViewfinderControl.stop(); + + // disable sensor event handler. + mSensorEventHandler.deinit(); + + if (mCameraDevice.cameraSnapshot()) { + mCameraDevice.cameraSnapshot()->StopSnapshot(); + } + + if (state() == Capturing) { + mCameraDevice.camera()->CancelCaptureImage(); + } + setState(Uninitialized); + + OstTrace0( camerax_performance, DUP1_CXESTILLCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_STILL_CAPCONT_DEINIT 0" ); + CX_DEBUG_EXIT_FUNCTION(); +} + + +/**! + * Prepare still capture mode. + */ +void CxeStillCaptureControlSymbian::prepare() +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (state() != Uninitialized) { + // wrong state and we return + return; + } + + OstTrace0( camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_STILLCAPCONT_PREPARE 1" ); + + int err = KErrNone; + CxeError::Id cxErr = getImageQualityDetails(mCurrentImageDetails); + int ecamStillResolutionIndex = 0; + + if (cxErr == CxeError::None) { + int imageWidth = mCurrentImageDetails.mWidth; + int imageHeight = mCurrentImageDetails.mHeight; + CX_DEBUG(("CxeStillCaptureControlSymbian::prepare <> resolution = (%d, %d)", imageWidth, imageHeight)); + + TSize imageSize; + imageSize.SetSize(imageWidth, imageHeight); + + if (mECamSupportedImageResolutions.count() > 0) { + ecamStillResolutionIndex = mECamSupportedImageResolutions.indexOf(imageSize); + } + + if (ecamStillResolutionIndex < 0) { + CX_DEBUG(("CxeStillCaptureControlSymbian::prepare - WARNING! resolution not supported, falling back to index 0")); + ecamStillResolutionIndex = 0; + } + + // Prepare Image capture + CCamera::TFormat imgFormat = supportedStillFormat(mCameraDeviceControl.cameraIndex()); + OstTrace0(camerax_performance, DUP2_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_IMAGE_CAPTURE 1"); + TRAP(err, mCameraDevice.camera()->PrepareImageCaptureL(imgFormat, ecamStillResolutionIndex)); + OstTrace0(camerax_performance, DUP3_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_IMAGE_CAPTURE 0"); + + CX_DEBUG(("PrepareImageCaptureL done, err=%d, resolution index = %d", err, ecamStillResolutionIndex)); + + if (!err) { + // still capture prepare went fine, try preparing snapshot + err = prepareStillSnapshot(); + } + } else { + err = KErrNotFound; + } + + if (!err) { + MCameraFaceTracking *faceTracking = mCameraDevice.faceTracking(); + if (faceTracking) { + // Enable AF reticule drawing by adaptation + TRAP_IGNORE(faceTracking->EnableFaceIndicatorsL(ETrue)); + } + + // Start viewfinder before claiming to be ready, + // as e.g. pending capture might be started by state change, + // and viewfinder start might have problems with just started capturing. + // If viewfinder is already running, this call does nothing. + mViewfinderControl.start(); + + // Still capture and still snapshot are OK. + // We can safely set state to READY. + setState(Ready); + + // inform zoom control to prepare zoom + emit prepareZoomForStill(ecamStillResolutionIndex); + } else { + CX_DEBUG(("Image Prepare FAILED! symbian error = %d", err)); + // release resources + deinit(); + } + + // Inform interested parties that image mode has been prepared for capture + emit imagePrepareComplete(CxeErrorHandlingSymbian::map(err)); + + OstTrace0( camerax_performance, DUP1_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_STILLCAPCONT_PREPARE 0" ); + + CX_DEBUG_EXIT_FUNCTION(); +} + + + +/**! + Prepare still snapshot + Returns symbian error code. + */ +int CxeStillCaptureControlSymbian::prepareStillSnapshot() +{ + CX_DEBUG_ENTER_FUNCTION(); + + CCamera::CCameraSnapshot *cameraSnapshot = mCameraDevice.cameraSnapshot(); + CX_ASSERT_ALWAYS(cameraSnapshot); + + int err = KErrNone; + // Whether or not we have postcapture on, we need the snapshot for Thumbnail Manager. + if (cameraSnapshot) { + // Cancel active snapshot + cameraSnapshot->StopSnapshot(); + + // Prepare snapshot + CCamera::TFormat snapFormat = CCamera::EFormatFbsBitmapColor16MU; + OstTrace0( camerax_performance, DUP4_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_SNAPSHOT 1" ); + TRAP(err, cameraSnapshot->PrepareSnapshotL(snapFormat, + getSnapshotSize(), + KMaintainAspectRatio)); + OstTrace0( camerax_performance, DUP5_CXESTILLCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_PREPARE_SNAPSHOT 0" ); + CX_DEBUG(("PrepareSnapshotL done, err=%d", err)); + + // Start snapshot if no errors encountered. + if (err == KErrNone) { + CX_DEBUG(("Start still snapshot")); + cameraSnapshot->StartSnapshot(); + } + } else { + // No snapshot interface available. Report error. + // Assert above takes care of this, but keeping this as an option. + err = KErrNotReady; + } + + CX_DEBUG_EXIT_FUNCTION(); + + return err; +} + + +/**! + imageInfo contains image qualities details + Returns CxeError error code. + */ +CxeError::Id CxeStillCaptureControlSymbian::getImageQualityDetails(CxeImageDetails &imageInfo) +{ + CX_DEBUG_ENTER_FUNCTION(); + + int imageQuality = 0; + CxeError::Id err = CxeError::None; + if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) { + err = mSettings.get(CxeSettingIds::IMAGE_QUALITY, imageQuality); + + bool validQuality = (imageQuality >= 0 && imageQuality < mIcmSupportedImageResolutions.count()); + + if (err == CxeError::None && validQuality ) { + // get image quality details + imageInfo = mIcmSupportedImageResolutions.at(imageQuality); + } else { + err = CxeError::NotFound; + CX_DEBUG(("Invalid ImageQuality = %d", imageQuality)); + } + } else { + // we are in secondary camera + // get secondary camera image quality details + imageInfo = mIcmSupportedImageResolutions.at(imageQuality); + } + + CX_DEBUG_EXIT_FUNCTION(); + return err; +} + + +/*! +* Returns snapshot size. Snapshot size is calculated based on the +* display resolution and current image aspect ratio. +*/ +TSize CxeStillCaptureControlSymbian::getSnapshotSize() const +{ + CX_DEBUG_ENTER_FUNCTION(); + + TSize snapshotSize; + + QSize deviceResolution = mViewfinderControl.deviceDisplayResolution(); + QSize size = QSize(mCurrentImageDetails.mWidth, mCurrentImageDetails.mHeight); + + // scale according to aspect ratio. + size.scale(deviceResolution.width(), deviceResolution.height(), Qt::KeepAspectRatio); + CX_DEBUG(("Still Snapshot size, (%d,%d)", size.width(), size.height())); + snapshotSize.SetSize(size.width(), deviceResolution.height()); + + CX_DEBUG_EXIT_FUNCTION(); + + return snapshotSize; +} + + +/** + * Command to start image capture now. + */ +void CxeStillCaptureControlSymbian::capture() +{ + CX_DEBUG_ENTER_FUNCTION(); + CX_ASSERT_ALWAYS(mCameraDevice.camera()); + + // Play the capture sound and start image capture + mCaptureSoundPlayer->play(); + + setState(Capturing); + mCameraDevice.camera()->CaptureImage(); + + //! @todo: NOTE: This call may not stay here. It can move depending on the implementation for burst capture. + if (mMode == BurstCapture) { + // Start a new filename sequence + mFilenameGenerator.startNewImageFilenameSequence(); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + + +/* ! +@Param cameraIndex indicates which camera we are in use, primary/secondary +Returns the format we use for specific camera index. +*/ +CCamera::TFormat CxeStillCaptureControlSymbian::supportedStillFormat(Cxe::CameraIndex cameraIndex) +{ + CX_DEBUG_ENTER_FUNCTION(); + Q_UNUSED(cameraIndex); + + // The same image format used for both primary and secodary cameras + CCamera::TFormat imgFormat = CCamera::EFormatExif; + + CX_DEBUG_EXIT_FUNCTION(); + + return imgFormat; +} + + +/** + * Camera events. Only relevant one(s) are handled. + */ +void CxeStillCaptureControlSymbian::handleCameraEvent(int eventUid, int error) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (eventUid == KUidECamEventSnapshotUidValue && + mCameraDeviceControl.mode() == Cxe::ImageMode) { + handleSnapshotEvent(CxeErrorHandlingSymbian::map(error)); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Snapshot ready notification. Ask the snapshot from snapshot interface. + * NB: Typically snapshot arrives before image data but can be in reverse + * order as well. + */ +void CxeStillCaptureControlSymbian::handleSnapshotEvent(CxeError::Id error) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (state() == CxeStillCaptureControl::Uninitialized) { + // we ignore this event, when we are not active + return; + } + + OstTrace0( camerax_performance, CXESTILLCAPTURECONTROLSYMBIAN_HANDLESNAPSHOTEVENT, "msg: e_CX_HANDLE_SNAPSHOT 1" ); + + // Get image container for current snapshot index. + // Remember to increment counter. + CxeStillImageSymbian* stillImage = getImageForIndex(mNextSnapshotIndex++); + + if (error == CxeError::None) { + try { + stillImage->setSnapshot(extractSnapshot()); + } catch (const std::exception& ex) { + error = CxeError::General; + } + } + + // Emit snapshotReady signal in all cases (error or not) + emit snapshotReady(error, stillImage->snapshot(), stillImage->id()); + + // When the snapshot ready event is handled, prepare new filename. + if (stillImage->filename().isEmpty()) { + // Error ignored at this point, try again when image data arrives. + prepareFilename(stillImage); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** +* Gets QPixmap snapshot from ECAM buffer, if available. +* @param buffer ECAM buffer containing the snapshot data. Will be released when this +* method returns, even on exception. +*/ +QPixmap CxeStillCaptureControlSymbian::extractSnapshot() +{ + CX_DEBUG_ENTER_FUNCTION(); + QPixmap pixmap; + + if (mCameraDevice.cameraSnapshot()) { + + QT_TRAP_THROWING({ + RArray frameIndex; + CleanupClosePushL(frameIndex); + + MCameraBuffer &buffer(mCameraDevice.cameraSnapshot()->SnapshotDataL(frameIndex)); + + // Make sure buffer is released on leave / exception + CxeCameraBufferCleanup cleaner(&buffer); + TInt firstImageIndex(frameIndex.Find(0)); + CFbsBitmap &snapshot(buffer.BitmapL(firstImageIndex)); + + CleanupStack::PopAndDestroy(); // frameIndex + + TSize size = snapshot.SizeInPixels(); + TInt sizeInWords = size.iHeight * CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU) / sizeof(TUint32); + CX_DEBUG(("size %d x %d, sizeInWords = %d", size.iWidth, size.iHeight, sizeInWords )); + + TUint32* pixelData = new (ELeave) TUint32[ sizeInWords ]; + // Convert to QImage + snapshot.LockHeap(); + TUint32* dataPtr = snapshot.DataAddress(); + memcpy(pixelData, dataPtr, sizeof(TUint32)*sizeInWords); + snapshot.UnlockHeap(); + + CX_DEBUG(("Creating QImage")); + QImage *snapImage = new QImage((uchar*)pixelData, size.iWidth, size.iHeight, + CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU), + QImage::Format_RGB32); + + pixmap = QPixmap::fromImage(*snapImage); + delete [] pixelData; + delete snapImage; + }); + } + + CX_DEBUG_EXIT_FUNCTION(); + return pixmap; +} + +/** + * handleImageData: Image data received from ECam + */ +void CxeStillCaptureControlSymbian::handleImageData( MCameraBuffer* cameraBuffer, int error ) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (state() == CxeStillCaptureControl::Uninitialized) { + // we ignore this event, when we are not active + cameraBuffer->Release(); + return; + } + + // Get image container for current image data index. + // Remember to increment counter. + CxeStillImageSymbian* stillImage = getImageForIndex(mNextImageDataIndex++); + + if (error) { + // Indicate error in image capture to the UI. + cameraBuffer->Release(); + emit imageCaptured(CxeErrorHandlingSymbian::map(error), stillImage->id()); + return; + } + + // If filename is not available at this stage, then generate one now + if (stillImage->filename().isEmpty()) { + CxeError::Id cxErr = prepareFilename(stillImage); + if (cxErr) { + cameraBuffer->Release(); + emit imageCaptured(cxErr, stillImage->id()); + return; + } + } + + // Get the image data from the buffer + TDesC8* data = NULL; + TRAPD( symbErr, data = cameraBuffer->DataL(0) ); + CX_DEBUG(("dataError: %d, data: 0x%08x", symbErr, data)); + + if (!data && !symbErr) { + symbErr = KErrNoMemory; + } + + // If data is available, initiate saving of image + if (!symbErr) { + //! @todo: this does a deep copy... we want to avoid this for performance/memory consumption reasons + QByteArray byteArray( reinterpret_cast( data->Ptr() ), data->Size() ); + data = NULL; + + // Save the image data + CxeImageDataItemSymbian* dataItem = mImageDataQueue->startSave(byteArray, stillImage->filename(), stillImage->id()); + stillImage->setDataItem(dataItem); + mFileSaveThread.save(dataItem); // Saving thread takes ownership of dataItem. + } + + // ECam Camera buffer should always be released + cameraBuffer->Release(); + + // Inform interested parties about image capture + emit imageCaptured(CxeErrorHandlingSymbian::map(symbErr), stillImage->id()); + + // set state to ready, since capturing is complete + setState(Ready); + + // image capture ready, before that we check if the orientation of the device changed during capture and if so, we set the new orientation + setOrientation(mSensorEventHandler.sensorData(CxeSensorEventHandler::OrientationSensor)); + + CX_DEBUG_EXIT_FUNCTION(); +} + + +/** + * Settings changed, needs updated + */ +void CxeStillCaptureControlSymbian::handleSettingValueChanged(const QString& settingId, QVariant newValue) +{ + CX_DEBUG_ENTER_FUNCTION(); + + Q_UNUSED(newValue); + + if (settingId == CxeSettingIds::IMAGE_QUALITY) { + // re-prepare for still + if (state() == Ready) { + deinit(); + init(); + } + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * ECam reference changing, release resources + */ +void CxeStillCaptureControlSymbian::prepareForCameraDelete() +{ + CX_DEBUG_ENTER_FUNCTION(); + deinit(); + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Camera being released. Cancel ongoing capture, if any. + */ +void CxeStillCaptureControlSymbian::prepareForRelease() +{ + CX_DEBUG_ENTER_FUNCTION(); + deinit(); + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * New camera available, + */ +void CxeStillCaptureControlSymbian::handleCameraAllocated(CxeError::Id error) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (error == CxeError::None) { + // load all still resoultions supported by ecam + mECamSupportedImageResolutions.clear(); + TCameraInfo cameraInfo; + Cxe::CameraIndex cameraIndex = mCameraDeviceControl.cameraIndex(); + CCamera::TFormat imgFormat = supportedStillFormat(cameraIndex); + mCameraDevice.camera()->CameraInfo(cameraInfo); + + for(int i = 0; i < cameraInfo.iNumImageSizesSupported; i++) { + TSize size; + mCameraDevice.camera()->EnumerateCaptureSizes(size, i, imgFormat); + CX_DEBUG(("ECam supported resolution <> Size (%d): (%d,%d)", i, size.iWidth, size.iHeight)); + mECamSupportedImageResolutions.insert(i, size); + } + + // load all still qualities supported by icm + mIcmSupportedImageResolutions.clear(); + // get list of supported image qualities based on camera index + mIcmSupportedImageResolutions = mQualityPresets.imageQualityPresets(cameraIndex); + + CX_DEBUG(("ECAM Supported Qualities count = %d", mECamSupportedImageResolutions.count())); + CX_DEBUG(("ICM Supported Qualities count = %d", mIcmSupportedImageResolutions.count())); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Return number of images captured (during current capture operation only). + */ +int CxeStillCaptureControlSymbian::imageCount() const +{ + return mImages.count(); +} + +/** + * Reset the image array. + */ +void CxeStillCaptureControlSymbian::reset() +{ + CX_DEBUG_ENTER_FUNCTION(); + + qDeleteAll( mImages ); + mImages.clear(); + + mNextSnapshotIndex = 0; + mNextImageDataIndex = 0; + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * This should cancel any ongoing image captures. + */ +void CxeStillCaptureControlSymbian::cancelAll() +{ + mImageDataQueue->clear(); + reset(); +} + +/** + * Sets the current capture mode: SingleImageCapture / BurstCapture. + */ +void CxeStillCaptureControlSymbian::setMode( CaptureMode mode ) +{ + mMode = mode; +} + +/** + * Returns the current capture mode. + */ +CxeStillCaptureControl::CaptureMode CxeStillCaptureControlSymbian::mode() const +{ + return mMode; +} + +/** + * Operator [] - returns the indexed image from capture array. + */ +CxeStillImage &CxeStillCaptureControlSymbian::operator[]( int index ) +{ + return *mImages[ index ]; +} + +/** + * Getter for image data queue. + */ +CxeImageDataQueue &CxeStillCaptureControlSymbian::imageDataQueue() +{ + return *mImageDataQueue; +} + +/** + * Generates a filename and sets it in the still image object. + * Skips the process if filename already copied exists in the object. This + * behaviour is required in rare cases where image data arrives before snapshot. + */ +CxeError::Id +CxeStillCaptureControlSymbian::prepareFilename(CxeStillImageSymbian *stillImage) +{ + CxeError::Id err = CxeError::None; + if (stillImage->filename().isEmpty()) { + QString path; + + QString fileExt = mCurrentImageDetails.mImageFileExtension; + + if (mMode == SingleImageCapture) { + err = mFilenameGenerator.generateFilename(path, fileExt); + } + else { + err = mFilenameGenerator.nextImageFilenameInSequence(path, fileExt); + } + + if (!err) { + CX_DEBUG(( "Next image file path: %s", path.toAscii().constData() )); + stillImage->setFilename(path); + } + else { + //! @todo: Error ID can be returned by this function. + // Also error can be detected from empty filename string. + CX_DEBUG(("ERROR in filename generation. err:%d", err)); + } + } + return err; +} + +/*! +* Helper method to set orientation data from the orientation sensor +*/ +void CxeStillCaptureControlSymbian::setOrientation(QVariant sensorData) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (mCameraDevice.cameraOrientation() && state() == Ready) { + Cxe::DeviceOrientation uiOrientation = qVariantValue(sensorData); + MCameraOrientation::TOrientation currentCameraOrientation = mCameraDevice.cameraOrientation()->Orientation(); + MCameraOrientation::TOrientation newCameraOrientation = CxeSettingsMapperSymbian::Map2CameraOrientation(uiOrientation); + + CX_DEBUG((("cameraindex: %d mMode: %d state(): %d mAfState: %d uiOrientation: %d "),mCameraDeviceControl.cameraIndex(), + mMode, state(), mAfState, uiOrientation )); + if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex && + mMode == SingleImageCapture && + uiOrientation != Cxe::OrientationNone && + currentCameraOrientation != newCameraOrientation && + (mAfState == CxeAutoFocusControl::Unknown || + mAfState == CxeAutoFocusControl::Canceling) + ) { + CX_DEBUG(("Setting Orientation to adaptation")); + TRAP_IGNORE(mCameraDevice.cameraOrientation()->SetOrientationL(newCameraOrientation)); + } + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/** + * Get the image container at given index or create a new one if needed. + */ +CxeStillImageSymbian* CxeStillCaptureControlSymbian::getImageForIndex(int index) +{ + CxeStillImageSymbian* image(NULL); + + if (mImages.count() <= index) { + image = new CxeStillImageSymbian(); + mImages.append(image); + } else { + CX_DEBUG_ASSERT( mNextImageDataIndex >= 0 && index < mImages.count() ); + image = mImages[index]; + } + return image; +} + + +/*! +* Slot to handle Autofocus events. +*/ +void CxeStillCaptureControlSymbian::handleAutofocusStateChanged( + CxeAutoFocusControl::State newState, + CxeError::Id /*error*/ ) +{ + CX_DEBUG_ENTER_FUNCTION(); + mAfState = newState; + CxeAutoFocusControl::Mode mode = mAutoFocusControl.mode(); + + // if focused and in correct mode, play sound + if (newState == CxeAutoFocusControl::Ready && + mode != CxeAutoFocusControl::Hyperfocal && + mode != CxeAutoFocusControl::Infinity) { + mAutoFocusSoundPlayer->play(); + } + CX_DEBUG_EXIT_FUNCTION(); +} + + +/*! +* Slot that sets orientation data emited from orientation sensor +*/ +void CxeStillCaptureControlSymbian::handleSensorEvent( + CxeSensorEventHandler::SensorType type, + QVariant data) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (type == CxeSensorEventHandler::OrientationSensor) { + setOrientation(data); + } else { + // nothing to do + } + + CX_DEBUG_EXIT_FUNCTION(); +} + + +/*! +* Returns supported image qualities based on the camera index +* (primary/secondary). +*/ +QList CxeStillCaptureControlSymbian::supportedImageQualities() +{ + // update remaining images counter + updateRemainingImagesCounter(); + + return mIcmSupportedImageResolutions; +} + + +/*! +* Updates remaining images counter to all the image qualities supported by ICM +* this should be done whenever storage location setting changes and when values are +* read from ICM for the first time +*/ +void CxeStillCaptureControlSymbian::updateRemainingImagesCounter() +{ + CX_DEBUG_ENTER_FUNCTION(); + + for( int index = 0; index < mIcmSupportedImageResolutions.count(); index++) { + CxeImageDetails &qualityDetails = mIcmSupportedImageResolutions[index]; + qualityDetails.mPossibleImages = calculateRemainingImages(qualityDetails.mEstimatedSize); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + + +/*! +* Returns the number of images left for the current image quality setting +*/ +int CxeStillCaptureControlSymbian::imagesLeft() +{ + return calculateRemainingImages(mCurrentImageDetails.mEstimatedSize); +} + + + +/*! +* CxeStillCaptureControlSymbian::calculateRemainingImages +@ param estimatedImagesize, the estimated size for image resolution +@ returns number of images remaining +*/ +int +CxeStillCaptureControlSymbian::calculateRemainingImages(int estimatedImagesize) +{ + CX_DEBUG_ENTER_FUNCTION(); + + //Check the memory in-use setting + qint64 memoryfree = CxeSysUtil::spaceAvailable(CCoeEnv::Static()->FsSession(), mSettings); + + memoryfree = memoryfree - KMinRequiredSpaceImage; + + if (memoryfree < 0) { + memoryfree = 0; // exception, inform ui + } + qint64 images = memoryfree / estimatedImagesize; + + CX_DEBUG_EXIT_FUNCTION(); + + return images; +} + +// end of file