camerauis/cameraxui/cxengine/src/cxevideocapturecontrolsymbian.cpp
changeset 19 d9aefe59d544
child 21 fa6d9f75d6a6
child 28 3075d9b614e6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/camerauis/cameraxui/cxengine/src/cxevideocapturecontrolsymbian.cpp	Fri Apr 16 14:51:30 2010 +0300
@@ -0,0 +1,1199 @@
+/*
+* 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 <QTime>
+#include <fbs.h>
+#include <QPixmap>
+#include <coemain.h>
+#include <QStringList>
+#include <AudioPreference.h>
+
+#include "cxevideocapturecontrolsymbian.h"
+#include "cxevideorecorderutilitysymbian.h"
+#include "cxecameradevicecontrolsymbian.h"
+#include "cxefilenamegeneratorsymbian.h"
+#include "cxeerrormappingsymbian.h"
+#include "cxeviewfindercontrol.h"
+#include "cxestillimagesymbian.h"
+#include "cxecameradevice.h"
+#include "cxutils.h"
+#include "cxesysutil.h"
+#include "cxestate.h"
+#include "cxesettings.h"
+#include "cxenamespace.h"
+#include "OstTraceDefinitions.h"
+#include "cxesoundplayersymbian.h"
+#include "cxequalitypresetssymbian.h"
+#include "cxeviewfindercontrolsymbian.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "cxevideocapturecontrolsymbianTraces.h"
+#endif
+
+
+// constants
+const TInt64  KMinRequiredSpaceVideo       = 4000000;
+const uint    KOneMillion                 = 1000000;
+const qreal   KMetaDataCoeff              = 1.03;      // Coefficient to estimate metadata amount
+const uint    KCamCMaxClipDurationInSecs  = 5400;      // Maximun video clip duration in seconds
+const qreal   KCMRAvgVideoBitRateScaler   = 0.9;       // avg video bit rate scaler
+
+
+/*!
+* CxeVideoCaptureControlSymbian::CxeVideoCaptureControlSymbian
+*/
+CxeVideoCaptureControlSymbian::CxeVideoCaptureControlSymbian(CxeCameraDevice &cameraDevice,
+                                                             CxeViewfinderControl &viewfinderControl,
+                                                             CxeCameraDeviceControl &cameraDeviceControl,
+                                                             CxeFilenameGenerator &nameGenerator,
+                                                             CxeSettings &settings,
+                                                             CxeQualityPresets &qualityPresets) :
+    CxeStateMachine("CxeVideoCaptureControlSymbian"),
+    mVideoRecorder(NULL),
+    mCameraDevice(cameraDevice),
+    mCameraDeviceControl(cameraDeviceControl),
+    mViewfinderControl(viewfinderControl),
+    mFilenameGenerator(nameGenerator),
+    mSettings(settings),
+    mQualityPresets(qualityPresets),
+    mSnapshot(),
+    mNewFileName(""),
+    mCurrentFilename("")
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    qRegisterMetaType<CxeVideoCaptureControl::State> ();
+    initializeStates();
+    mVideoStopSoundPlayer = new
+             CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::VideoCaptureStop);
+    mVideoStartSoundPlayer = new
+             CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::VideoCaptureStart);
+
+    // connect signals from cameraDevice, so we 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 playing sound signals
+    connect(mVideoStartSoundPlayer, SIGNAL(playComplete(int)),
+            this, SLOT(handleSoundPlayed()));
+
+    // enabling setting change callbacks to videocapturecontrol
+    connect(&mSettings, SIGNAL(settingValueChanged(const QString&,QVariant)),
+            this, SLOT(handleSettingValueChanged(const QString&,QVariant)));
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* CxeVideoCaptureControlSymbian::~CxeVideoCaptureControlSymbian()
+*/
+CxeVideoCaptureControlSymbian::~CxeVideoCaptureControlSymbian()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    releaseResources();
+    mIcmSupportedVideoResolutions.clear();
+    delete mVideoStartSoundPlayer;
+    delete mVideoStopSoundPlayer;
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Initializes resources for video recording.
+*/
+void CxeVideoCaptureControlSymbian::init()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_VIDEO_CAPCONT_INIT 1" );
+
+    if (state() == Idle) {
+        // start initializing resources for video capture
+        initVideoRecorder();
+    } else if (state() == Initialized) {
+        // video recorder already initalized. Continue to prepare video reocording.
+        open();
+    }
+
+    OstTrace0( camerax_performance, DUP1_CXEVIDEOCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_VIDEO_CAPCONT_INIT 0" );
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*
+* Releases all resources
+*/
+void CxeVideoCaptureControlSymbian::deinit()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_VIDEO_CAPCONT_DEINIT 1" );
+
+    if(state() == Idle) {
+        // nothing to do
+        return;
+    }
+
+    // first stop viewfinder
+    mViewfinderControl.stop();
+
+    // stop video-recording in-case if its ongoing.
+    stop();
+
+    if (mCameraDevice.cameraSnapshot()) {
+        mCameraDevice.cameraSnapshot()->StopSnapshot();
+    }
+
+    if (mVideoRecorder) {
+        mVideoRecorder->Close();
+    }
+
+    // revert back the new filename to empty string so that we generate a new file name
+    // when we init again
+    mNewFileName = QString("");
+
+    setState(Idle);
+
+    OstTrace0( camerax_performance, DUP1_CXEVIDEOCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_VIDEO_CAPCONT_DEINIT 0" );
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Intializes VideoRecorder for recording.
+*/
+void CxeVideoCaptureControlSymbian::initVideoRecorder()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() != Idle) {
+        // not valid state to start "open" operation
+        return;
+    }
+
+    if(!mVideoRecorder) {
+        // if video recorder is not created, do it now.
+        createVideoRecorder();
+    }
+
+    // update current video quality details from icm
+    CxeError::Id err = getVideoQualityDetails(mCurrentVideoDetails);
+
+    if (!err) {
+        // read videofile mime type
+        QByteArray videoFileData =
+                    mCurrentVideoDetails.mVideoFileMimeType.toLatin1();
+        TPtrC8 videoFileMimeType(reinterpret_cast<const TUint8*>
+                           (videoFileData.constData()), videoFileData.size());
+
+        // read preferred supplier
+        TPtrC16 supplier(reinterpret_cast<const TUint16*>
+                           (mCurrentVideoDetails.mPreferredSupplier.utf16()));
+
+        err = findVideoController(videoFileMimeType, supplier);
+
+        if (!err) {
+            // video recorder is ready to open video file for recording.
+            setState(Initialized);
+            open();
+        }
+    } else {
+        err = CxeErrorHandlingSymbian::map(KErrNotReady);
+    }
+
+    if (err) {
+        // In case of error
+        emit videoPrepareComplete(err);
+        deinit();
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+
+/*!
+* Opens file for video recording.
+*/
+void CxeVideoCaptureControlSymbian::open()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() != Initialized) {
+        // not valid state to start "open" operation
+        return;
+    }
+
+    CxeError::Id err = CxeError::None;
+
+    // generate video file name, if necessary
+    if (mNewFileName.isEmpty()) {
+        QStringList list = mCurrentVideoDetails.mVideoFileMimeType.split("/");
+        QString fileExt(".");
+        if (list.count() == 2) {
+            fileExt = fileExt + list[1];
+        }
+        // Generate new filename and open the file for writing video data
+        err = mFilenameGenerator.generateFilename(mNewFileName, fileExt);
+        if (err == CxeError::None) {
+            mCurrentFilename = mNewFileName;
+        } else {
+            // file name is not valid, re-initialize the value of current string
+            // back to empty string
+            mCurrentFilename = QString("");
+        }
+    }
+
+    if (!err &&
+        mVideoRecorder &&
+        !mCurrentFilename.isEmpty()) {
+
+        TPtrC16 fName(reinterpret_cast<const TUint16*>(mCurrentFilename.utf16()));
+        CX_DEBUG(( "Next video file path: %s", mCurrentFilename.toAscii().constData() ));
+
+        // read video codec mime type
+        QByteArray videoCodecData =
+                    mCurrentVideoDetails.mVideoCodecMimeType.toLatin1();
+        TPtrC8 videoCodecMimeType(reinterpret_cast<const TUint8*>
+                           (videoCodecData.constData()), videoCodecData.size());
+
+        setState(CxeVideoCaptureControl::Preparing);
+
+        TRAPD(openErr, mVideoRecorder->OpenFileL(fName,
+                       mCameraDevice.camera()->Handle(),
+                       mVideoControllerUid,
+                       mVideoFormatUid,
+                       videoCodecMimeType,
+                       audioType(mCurrentVideoDetails.mAudioType)));
+
+        err = CxeErrorHandlingSymbian::map(openErr);
+    }
+    if (err) {
+        // error occured.
+        deinit();
+        emit videoPrepareComplete(err);
+    }
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Prepare Video Recorder with necessary settings for video capture.
+*/
+TFourCC CxeVideoCaptureControlSymbian::audioType(const QString& str)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    QByteArray audioType = str.toAscii();
+
+    quint8 char1(' ');
+    quint8 char2(' ');
+    quint8 char3(' ');
+    quint8 char4(' ');
+
+    if (audioType.count() > 3) {
+        char1 = audioType[0];
+        char2 = audioType[1];
+        char3 = audioType[2];
+
+        if (audioType.count() == 4) {
+            char4 = audioType[3];
+        }
+    }
+
+    return TFourCC(char1, char2, char3, char4);
+}
+
+
+/*!
+* Prepare Video Recorder with necessary settings for video capture.
+*/
+void CxeVideoCaptureControlSymbian::prepare()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() != Preparing) {
+        // not valid state to continue prepare.
+        return;
+    }
+
+    CX_DEBUG(("Video resoulution (%d,%d)", mCurrentVideoDetails.mWidth,
+                                           mCurrentVideoDetails.mHeight));
+    CX_DEBUG(("Video bitrate = %d)", mCurrentVideoDetails.mVideoBitRate));
+    CX_DEBUG(("Video frame rate = %f)", mCurrentVideoDetails.mVideoFrameRate));
+
+    OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_VIDCAPCONT_PREPARE 1");
+    TSize frameSize;
+    frameSize.SetSize(mCurrentVideoDetails.mWidth, mCurrentVideoDetails.mHeight);
+
+    int muteSetting = 0; // audio enabled
+    mSettings.get(CxeSettingIds::VIDEO_MUTE_SETTING, muteSetting);
+
+    TRAPD(err,
+              {
+              mVideoRecorder->SetVideoFrameSizeL(frameSize);
+              mVideoRecorder->SetVideoFrameRateL(mCurrentVideoDetails.mVideoFrameRate);
+              mVideoRecorder->SetVideoBitRateL(mCurrentVideoDetails.mVideoBitRate);
+              mVideoRecorder->SetAudioEnabledL(muteSetting == 0);
+              // "No limit" value is handled in video recorder wrapper.
+              mVideoRecorder->SetMaxClipSizeL(mCurrentVideoDetails.mMaximumSizeInBytes);
+              }
+         );
+
+    if (!err) {
+        // settings have been applied successfully, start to prepare
+        mVideoRecorder->Prepare();
+        // prepare snapshot
+        err = prepareVideoSnapshot();
+    }
+
+    if (!err) {
+        // prepare zoom only when there are no errors during prepare.
+        emit prepareZoomForVideo();
+    }
+    // emit video prepare status
+    emit videoPrepareComplete(CxeErrorHandlingSymbian::map(err));
+
+    OstTrace0(camerax_performance, DUP1_CXEVIDEOCAPTURECONTROLSYMBIAN_PREPARE, "msg: e_CX_VIDCAPCONT_PREPARE 0");
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+
+/*!
+Fetches video qualites details based on video quality setting.
+Returns CxeError codes if any.
+*/
+CxeError::Id
+CxeVideoCaptureControlSymbian::getVideoQualityDetails(CxeVideoDetails &videoInfo)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    int videoQuality = 0;
+    CxeError::Id err = CxeError::None;
+
+    if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) {
+        err = mSettings.get(CxeSettingIds::VIDEO_QUALITY, videoQuality);
+
+        bool validQuality = (videoQuality >= 0 &&
+                             videoQuality < mIcmSupportedVideoResolutions.count());
+        if (err == CxeError::None && validQuality) {
+            // get video quality details
+            videoInfo = mIcmSupportedVideoResolutions.at(videoQuality);
+        } else {
+            // not valid video quality
+            err = CxeError::NotFound;
+        }
+    } else {
+        // get secondary camera video quality index
+        if (mIcmSupportedVideoResolutions.count() > 0) {
+            videoInfo = mIcmSupportedVideoResolutions.at(videoQuality);
+        } else {
+            // not valid video quality
+            err = CxeError::NotFound;
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+
+    return err;
+}
+
+
+/**!
+ Prepare snapshot
+ Returns symbian error code.
+ */
+int CxeVideoCaptureControlSymbian::prepareVideoSnapshot()
+{
+    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;
+        TRAP(err, cameraSnapshot->PrepareSnapshotL(snapFormat,
+                                                   getSnapshotSize(),
+                                                   KMaintainAspectRatio));
+        CX_DEBUG(("PrepareSnapshotL done, err=%d", err));
+        // Start snapshot if no errors encountered.
+        if (err == KErrNone) {
+            CX_DEBUG(("Start video 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;
+}
+
+
+
+/*!
+* Returns snapshot size. Snapshot size is calculated based on the
+* display resolution and current video aspect ratio.
+*/
+TSize CxeVideoCaptureControlSymbian::getSnapshotSize() const
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    TSize snapshotSize;
+
+    QSize deviceResolution = mViewfinderControl.deviceDisplayResolution();
+    QSize size = QSize(mCurrentVideoDetails.mWidth, mCurrentVideoDetails.mHeight);
+
+    // scale according to aspect ratio.
+    size.scale(deviceResolution.width(),
+               deviceResolution.height(),
+               Qt::KeepAspectRatio);
+    CX_DEBUG(("Video Snapshot size, (%d,%d)", size.width(), size.height()));
+    snapshotSize.SetSize(size.width(), deviceResolution.height());
+
+    CX_DEBUG_EXIT_FUNCTION();
+
+    return snapshotSize;
+}
+
+
+
+/**!
+* Camera events coming from ecam.
+*/
+void CxeVideoCaptureControlSymbian::handleCameraEvent(int eventUid, int error)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    if (eventUid == KUidECamEventSnapshotUidValue) {
+        handleSnapshotEvent(CxeErrorHandlingSymbian::map(error));
+    }
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Handle Snapshot event from ecam
+*/
+void CxeVideoCaptureControlSymbian::handleSnapshotEvent(CxeError::Id error)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() == Idle) {
+        // we ignore this event, when we are not in active state(s)
+        CX_DEBUG(( "wrong state, ignoring snapshot" ));
+        CX_DEBUG_EXIT_FUNCTION();
+        return;
+    }
+
+    if (error) {
+        mSnapshot = QPixmap();
+        emit snapshotReady(error, mSnapshot, filename());
+        return;
+    }
+
+    RArray<TInt> snapList;
+    MCameraBuffer* buffer(NULL);
+    // Note: Cleanup not required in this function
+    CFbsBitmap *snapshot = NULL;
+    TRAPD(snapErr,
+          buffer = &mCameraDevice.cameraSnapshot()->SnapshotDataL(snapList));
+    if (!snapErr) {
+        TInt firstImageIndex = snapList.Find(0);
+        snapList.Close();
+        TRAP(snapErr, snapshot = &(buffer->BitmapL(firstImageIndex)));
+    }
+    if (!snapErr) {
+        TSize size = snapshot->SizeInPixels();
+        TInt sizeInWords = size.iHeight * CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU)
+                / sizeof(TUint32);
+
+        TUint32 *snapshotData = NULL;
+        snapshotData = new TUint32[sizeInWords];
+
+        if (snapshotData) {
+            // Convert to QImage
+            snapshot->LockHeap();
+            TUint32* dataPtr = snapshot->DataAddress();
+            memcpy(snapshotData, dataPtr, sizeof(TUint32) * sizeInWords);
+            snapshot->UnlockHeap();
+
+
+            QImage *img = new QImage((uchar*) snapshotData, size.iWidth, size.iHeight,
+                                   CFbsBitmap::ScanLineLength(size.iWidth, EColor16MU),
+                                   QImage::Format_RGB32);
+
+            mSnapshot = QPixmap::fromImage(*img);
+            delete [] snapshotData;
+            delete img;
+        }
+    }
+    if (buffer) {
+        buffer->Release();
+    }
+    // Snapshot ready
+    emit snapshotReady(CxeErrorHandlingSymbian::map(snapErr), mSnapshot, filename());
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Resets the video snapshot and current video filename
+*/
+void CxeVideoCaptureControlSymbian::reset()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    // Snapshot will consume considerably memory.
+    // Replace it with null pixmap to have it freed.
+    mSnapshot = QPixmap();
+    // reset the current file name.
+    mCurrentFilename = QString("");
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Returns current video filename
+*/
+QString CxeVideoCaptureControlSymbian::filename() const
+{
+    // Simply return the current contents of mCurrentFilename.
+    // If video recording was started then it returns proper filename
+    // otherwise an empty string is returned.
+    return mCurrentFilename;
+}
+
+
+/*!
+* Returns current video snapshot
+*/
+QPixmap CxeVideoCaptureControlSymbian::snapshot() const
+{
+    return mSnapshot;
+}
+
+
+/*!
+* Starts video recording if we are in appropriate state.
+*/
+void CxeVideoCaptureControlSymbian::record()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() == Ready || state() == Paused) {
+        // ask the player to play the sound
+        // recording will start once start sound is played
+        setState(CxeVideoCaptureControl::PlayingStartSound);
+        mVideoStartSoundPlayer->play();
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Pauses video recording.
+*/
+void CxeVideoCaptureControlSymbian::pause()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    setState(CxeVideoCaptureControl::Paused);
+    TRAPD(pauseErr, mVideoRecorder->PauseL());
+    if (pauseErr) {
+        CX_DEBUG(("[WARNING] Error %d pausing!", pauseErr));
+        //pause operation failed, report it
+        emit videoComposed(CxeErrorHandlingSymbian::map(pauseErr), filename());
+        // release resources.
+        deinit();
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Stops video recording.
+*/
+void CxeVideoCaptureControlSymbian::stop()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() == Recording || state() == Paused) {
+        // first stop viewfinder
+        mViewfinderControl.stop();
+
+        TInt asyncStopErr = mVideoRecorder->CustomCommandSync(
+            TMMFMessageDestination(KCamCControllerImplementationUid,
+                                   KMMFObjectHandleController),
+            ECamCControllerCCVideoStopAsync,
+            KNullDesC8,
+            KNullDesC8 );
+        CX_DEBUG(("ECamCControllerCCVideoStopAsync sent, err=%d", asyncStopErr));
+        if (asyncStopErr) { // fall back to synchronous stop
+            TInt syncStopErr = mVideoRecorder->Stop();
+            if (syncStopErr) {
+                // error during stop operation, release resources
+                emit videoComposed(CxeErrorHandlingSymbian::map(asyncStopErr), filename());
+                deinit();
+            } else {
+                // stop operation went fine, set back the state to Initialized.
+                setState(Initialized);
+                mFilenameGenerator.raiseCounterValue();
+            }
+        } else {
+            // No error from asynch stop custom command... wait for stop event
+            setState(Stopping);
+            mFilenameGenerator.raiseCounterValue();
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Callback when "Open" operation is complete.
+*/
+void CxeVideoCaptureControlSymbian::MvruoOpenComplete(TInt aError)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    CX_DEBUG(("CxeVideoCaptureControlSymbian::MvruoOpenComplete, err=%d", aError));
+
+    if (state() == Preparing) {
+        if (aError != KErrNone) {
+            deinit();
+            CxeError::Id err = CxeErrorHandlingSymbian::map(KErrNotReady);
+            // report error to interested parties
+            emit videoPrepareComplete(CxeErrorHandlingSymbian::map(err));
+        } else {
+            prepare();
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Callback when "Prepare" request is complete.
+*/
+void CxeVideoCaptureControlSymbian::MvruoPrepareComplete(TInt aError)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    CX_DEBUG(("CxeVideoCaptureControlSymbian::MvruoPrepareComplete, err=%d", aError));
+
+    if (state() == Preparing) {
+        if (!aError) {
+            setState(CxeVideoCaptureControl::Ready);
+            mViewfinderControl.start();
+        } else {
+            deinit();
+            // report error to interested parties
+            CxeError::Id err = CxeErrorHandlingSymbian::map(KErrNotReady);
+            emit videoPrepareComplete(CxeErrorHandlingSymbian::map(err));
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Callback when "Record" operation is complete.
+*/
+void CxeVideoCaptureControlSymbian::MvruoRecordComplete(TInt aError)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    CX_DEBUG(("CxeVideoCaptureControlSymbian::MvruoRecordComplete, err=%d", aError));
+
+    //! async stop customcommand stuff
+    if (aError == KErrNone) {
+        setState(CxeVideoCaptureControl::Ready);
+    } else if (aError == KErrCompletion) {
+        // KErrCompletion is received when video recording stops
+        // because of maximum clip size is reached. Emulate
+        // normal stopping.
+        setState(Stopping);
+        MvruoEvent(TMMFEvent(KCamCControllerCCVideoRecordStopped, KErrNone));
+        MvruoEvent(TMMFEvent(KCamCControllerCCVideoFileComposed, KErrNone));
+    }
+    else {
+        // error during recording, report to client
+        deinit();
+        emit videoComposed(CxeErrorHandlingSymbian::map(aError), filename());
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Callback from MVideoRecorderUtilityObserver
+*/
+void CxeVideoCaptureControlSymbian::MvruoEvent(const TMMFEvent& aEvent)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (aEvent.iEventType.iUid == KCamCControllerCCVideoRecordStopped.iUid) {
+        CX_DEBUG(("KCamCControllerCCVideoRecordStopped"));
+        // play the sound, but not changing the state
+        mVideoStopSoundPlayer->play();
+    } else if (aEvent.iEventType.iUid == KCamCControllerCCVideoFileComposed.iUid) {
+        CX_DEBUG(("KCamCControllerCCVideoFileComposed"));
+        if (state() == Stopping) {
+            // stop operation went fine, set back the state to intialized.
+            setState(Initialized);
+        }
+        // video file has composed, everything went well, inform the client
+        emit videoComposed(CxeError::None, filename());
+        // revert back the new filename to empty string, since recording
+        // is complete and we need to generate a new file name
+        mNewFileName = QString("");
+    } else {
+        CX_DEBUG(("ignoring unknown MvruoEvent 0x%08x", aEvent.iEventType.iUid ));
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+Get corresponding controller for video capture.
+@param aMimeType denotes videofile mimetype,
+@param aPreferredSupplier denotes supplier.
+Returns CxeError::Id if any.
+*/
+CxeError::Id
+CxeVideoCaptureControlSymbian::findVideoController(const TDesC8& aMimeType,
+                                                   const TDesC& aSupplier)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    CX_DEBUG(("video file mime type : %s", &aMimeType));
+    CX_DEBUG(("supplier name: %s", &aSupplier));
+
+    mVideoControllerUid.iUid = 0;
+    mVideoFormatUid.iUid = 0;
+
+    // Retrieve a list of possible controllers from ECOM.
+    // Controller must support recording the requested mime type.
+    // Controller must be provided by preferred supplier.
+
+    CMMFControllerPluginSelectionParameters* cSelect(NULL);
+    CMMFFormatSelectionParameters* fSelect(NULL);
+    RMMFControllerImplInfoArray controllers;
+
+    TRAPD(err, cSelect = CMMFControllerPluginSelectionParameters::NewL());
+    if (err) {
+        return CxeErrorHandlingSymbian::map(err);
+    }
+
+    TRAP(err, fSelect = CMMFFormatSelectionParameters::NewL());
+    if (err) {
+        if(cSelect) {
+            delete cSelect;
+        }
+        return CxeErrorHandlingSymbian::map(err);
+    }
+
+    TRAP( err, {
+        fSelect->SetMatchToMimeTypeL(aMimeType);
+        cSelect->SetRequiredRecordFormatSupportL(*fSelect);
+        cSelect->SetPreferredSupplierL(aSupplier,
+                                       CMMFPluginSelectionParameters::EOnlyPreferredSupplierPluginsReturned);
+        cSelect->ListImplementationsL(controllers);
+    } );
+
+    if (!err && controllers.Count() >= 1) {
+        // KErrNotFound is returned unless a controller is found
+        err = KErrNotFound;
+        // Get the controller UID.
+        mVideoControllerUid = controllers[0]->Uid();
+
+        // Inquires the controller about supported formats.
+        // We use the first controller found having index 0.
+        RMMFFormatImplInfoArray formats;
+        formats = controllers[0]->RecordFormats();
+
+        // Get the first format that supports our mime type.
+        int count = formats.Count();
+        for (int i=0; i<count; i++) {
+            if (formats[i]->SupportsMimeType(aMimeType)) {
+                mVideoFormatUid = formats[i]->Uid(); // set the UID
+                err = KErrNone;
+                break;
+            }
+        }
+    }
+    delete cSelect;
+    delete fSelect;
+    controllers.ResetAndDestroy();
+
+    CX_DEBUG_EXIT_FUNCTION();
+
+    return CxeErrorHandlingSymbian::map(err);
+}
+
+
+/*!
+* camera reference changing, release resources
+*/
+void CxeVideoCaptureControlSymbian::prepareForCameraDelete()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    releaseResources();
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+/*!
+* prepare for camera release.
+*/
+void CxeVideoCaptureControlSymbian::prepareForRelease()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    deinit();
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* new camera available,
+*/
+void CxeVideoCaptureControlSymbian::handleCameraAllocated(CxeError::Id error)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (!error) {
+        // initialize the video recorder utility
+        createVideoRecorder();
+        // new camera available, read supported video qualities from icm
+        // load all still qualities supported by icm
+        mIcmSupportedVideoResolutions.clear();
+        Cxe::CameraIndex cameraIndex = mCameraDeviceControl.cameraIndex();
+        // get list of supported image qualities based on camera index
+        mIcmSupportedVideoResolutions =
+                mQualityPresets.videoQualityPresets(cameraIndex);
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Initializes video recorder.
+*/
+void CxeVideoCaptureControlSymbian::createVideoRecorder()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    // init video recoder
+    if (state() == CxeVideoCaptureControl::Idle) {
+        if (mVideoRecorder == NULL) {
+            TRAPD(initErr, mVideoRecorder =
+                new CxeVideoRecorderUtilitySymbian( *this ,
+                            KAudioPriorityVideoRecording,
+                            TMdaPriorityPreference( KAudioPrefVideoRecording )));
+            if (initErr) {
+                CX_DEBUG(("WARNING - VideoRecorderUtility could not be reserved. Failed with err:%d", initErr));
+                mVideoRecorder = NULL;
+            }
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* releases resources used by videocapture
+*/
+void CxeVideoCaptureControlSymbian::releaseResources()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    // Save the state and filename before releasing.
+    QString filenameCopy(filename());
+    CxeVideoCaptureControl::State stateCopy(state());
+
+    // first de-init videocapture control
+    deinit();
+    reset();
+
+    // Check if state is stopping, in which case we have to inform the
+    // file harvester that a file is to be completed. We would not
+    // call harvestFile otherwise in this case.
+    // Otherwise the video will not be found from videos app.
+    if (stateCopy == CxeVideoCaptureControl::Stopping) {
+        emit videoComposed(CxeError::None, filenameCopy);
+    }
+
+    delete mVideoRecorder;
+    mVideoRecorder = NULL;
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+Returns current state of videocapture
+*/
+CxeVideoCaptureControl::State CxeVideoCaptureControlSymbian::state() const
+{
+    return static_cast<CxeVideoCaptureControl::State> (stateId());
+}
+
+
+/*!
+* slot called when state is changed.
+*/
+void CxeVideoCaptureControlSymbian::handleStateChanged(int newStateId, CxeError::Id error)
+{
+    emit stateChanged(static_cast<State> (newStateId), error);
+}
+
+
+/*!
+* Initialize states for videocapturecontrol
+*/
+void CxeVideoCaptureControlSymbian::initializeStates()
+{
+    // addState( id, name, allowed next states )
+    addState(new CxeState(Idle, "Idle", Initialized));
+    addState(new CxeState(Initialized, "Initialized", Preparing | Idle));
+    addState(new CxeState(Preparing, "Preparing", Ready | Idle));
+    addState(new CxeState(Ready, "Ready", Recording | PlayingStartSound | Preparing | Idle));
+    addState(new CxeState(Recording, "Recording", Recording | Paused | Stopping | Idle));
+    addState(new CxeState(Paused, "Paused", Recording | Stopping | PlayingStartSound | Idle));
+    addState(new CxeState(Stopping, "Stopping", Initialized | Idle));
+    addState(new CxeState(PlayingStartSound, "PlayingStartSound", Recording | Idle));
+
+    setInitialState(Idle);
+}
+
+
+/*!
+* Updates remaining video recordng time counter to all the video 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 CxeVideoCaptureControlSymbian::updateRemainingRecordingTimeCounter()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    for( int index = 0; index < mIcmSupportedVideoResolutions.count(); index++) {
+        CxeVideoDetails &qualityDetails = mIcmSupportedVideoResolutions[index];
+        calculateRemainingTime(qualityDetails, qualityDetails.mRemainingTime);
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+/*
+* calculates remaining video recording time.
+*/
+void CxeVideoCaptureControlSymbian::remainingTime(int &time)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    if (state() == CxeVideoCaptureControl::Recording) {
+        TTimeIntervalMicroSeconds remaining = 0;
+        remaining = mVideoRecorder->RecordTimeAvailable();
+        time = remaining.Int64() * 1.0 / KOneSecond;
+        CX_DEBUG(( "timeRemaining2: %d", time ));
+    } else {
+        calculateRemainingTime(mCurrentVideoDetails, time);
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+
+/*!
+* algorithm to calculate remaining recording time
+@ param videoDetails contains the current video resolution that is in use.
+@ time contains the remaining recording time
+*/
+void CxeVideoCaptureControlSymbian::calculateRemainingTime(CxeVideoDetails videoDetails, int &time)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    TTimeIntervalMicroSeconds remaining = 0;
+
+    // get available space in the drive selected in the settings
+    // for storing videos
+    qint64 availableSpace = CxeSysUtil::spaceAvailable(CCoeEnv::Static()->FsSession(), mSettings);
+
+    availableSpace = availableSpace - KMinRequiredSpaceVideo;
+
+    // Maximum clip size may be limited for mms quality.
+    // If mMaximumSizeInBytes == 0, no limit is specified.
+    if (videoDetails.mMaximumSizeInBytes > 0 && videoDetails.mMaximumSizeInBytes < availableSpace) {
+        availableSpace = videoDetails.mMaximumSizeInBytes;
+    }
+
+    // Use average audio/video bitrates to estimate remaining time
+    quint32  averageBitRate = 0;
+    quint32  averageByteRate = 0;
+    qreal    scaler = mQualityPresets.avgVideoBitRateScaler();
+
+    if (scaler == 0) {
+        // video bit rate scaler is 0, use the constant value
+        scaler = KCMRAvgVideoBitRateScaler;
+    }
+
+    int avgVideoBitRate = (videoDetails.mVideoBitRate * scaler);
+    int avgAudioBitRate =  videoDetails.mAudioBitRate;
+
+    int muteSetting = 0; // audio enabled
+    mSettings.get(CxeSettingIds::VIDEO_MUTE_SETTING, muteSetting);
+
+    if (muteSetting == 1) {
+        // audio disabled from setting. hence no audio
+        avgAudioBitRate = 0;
+    }
+
+    averageBitRate = (quint32)(
+                     (avgVideoBitRate + avgAudioBitRate) * KMetaDataCoeff);
+
+    averageByteRate = averageBitRate / 8;
+
+    if (availableSpace <= 0) {
+        remaining = 0;
+    } else {
+        // converting microseconds to seconds
+        remaining = availableSpace * KOneMillion / averageByteRate;
+        if ( (remaining.Int64()) > (quint64(KCamCMaxClipDurationInSecs) * KOneMillion) ) {
+            remaining = (quint64(KCamCMaxClipDurationInSecs) * KOneMillion);
+        }
+    }
+    if ( remaining <= quint64(0) ) {
+        remaining = 0;
+    }
+
+    time = remaining.Int64() * 1.0 / KOneSecond;
+
+    CX_DEBUG(( "remaining time from algorithm: %d", time ));
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Calculates remaining recording time during video recording
+*/
+bool CxeVideoCaptureControlSymbian::elapsedTime(int &time)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    TTimeIntervalMicroSeconds timeElapsed = 0;
+    bool ok = false;
+    if (state() == CxeVideoCaptureControl::Recording) {
+        TRAPD( err, timeElapsed = mVideoRecorder->DurationL() );
+        if (!err) {
+            time = timeElapsed.Int64() * 1.0 / KOneSecond;
+            CX_DEBUG(("timeElapsed2: %d", time));
+            ok = true;
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+
+    return ok;
+}
+
+/*!
+* slot called when playing a sound has finished.
+*/
+void CxeVideoCaptureControlSymbian::handleSoundPlayed()
+{
+    CX_DEBUG_ENTER_FUNCTION();
+
+    // start recording, if we were playing capture sound
+    if (state() == CxeVideoCaptureControl::PlayingStartSound) {
+        setState(CxeVideoCaptureControl::Recording);
+        mVideoRecorder->Record();
+    }
+
+    // in case of video capture stop sound playing, nothing needs to be done
+    // meaning the state set elsewhere, and the video capture has been stopped already
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* setting has changed, check if we are interested.
+*/
+void CxeVideoCaptureControlSymbian::handleSettingValueChanged(const QString& settingId,
+                                                              QVariant newValue)
+{
+    CX_DEBUG_ENTER_FUNCTION();
+    Q_UNUSED(newValue);
+
+    if (mCameraDeviceControl.mode() == Cxe::VideoMode) {
+        if (settingId == CxeSettingIds::VIDEO_QUALITY) {
+            // re-prepare for video
+            if (state() == Ready) {
+                // release resources
+         	    deinit();
+                // initialize video recording again
+           	    init();
+           	}
+        } else if (settingId == CxeSettingIds::VIDEO_MUTE_SETTING) {
+            // mute setting changed, apply the new setting and re-prepare.
+            setState(Preparing);
+            prepare();
+        } else {
+            // Setting not relevant to video mode
+        }
+    }
+
+    CX_DEBUG_EXIT_FUNCTION();
+}
+
+
+/*!
+* Returns QList of all supported video quality details based on the camera index
+* (primary/secondary).
+*/
+QList<CxeVideoDetails> CxeVideoCaptureControlSymbian::supportedVideoQualities()
+{
+    // update the remaining time counters for each quality setting
+    updateRemainingRecordingTimeCounter();
+    return mIcmSupportedVideoResolutions;
+}
+
+// End of file