diff -r f54ad444594d -r 61bc0f252b2b camerauis/cameraxui/cxengine/src/cxevideocapturecontrolsymbian.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/camerauis/cameraxui/cxengine/src/cxevideocapturecontrolsymbian.cpp Tue Aug 31 15:03:46 2010 +0300 @@ -0,0 +1,1002 @@ +/* +* Copyright (c) 2009-2010 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 "cxeexception.h" +#include "cxevideocapturecontrolsymbian.h" +#include "cxevideorecorderutilitysymbian.h" +#include "cxecameradevicecontrolsymbian.h" +#include "cxefilenamegeneratorsymbian.h" +#include "cxeerrormappingsymbian.h" +#include "cxeviewfindercontrol.h" +#include "cxesnapshotcontrol.h" +#include "cxestillimagesymbian.h" +#include "cxecameradevice.h" +#include "cxutils.h" +#include "cxestate.h" +#include "cxesettings.h" +#include "cxenamespace.h" +#include "cxesoundplayersymbian.h" +#include "cxequalitypresetssymbian.h" +#include "cxeviewfindercontrolsymbian.h" +#include "cxediskmonitor.h" +#include "cxesettingsmappersymbian.h" + +#include "OstTraceDefinitions.h" +#ifdef OST_TRACE_COMPILER_IN_USE +#include "cxevideocapturecontrolsymbianTraces.h" +#endif + + +// constants +namespace +{ + // TMMFEvent UIDs for Async stop + const TUid KCamCControllerCCVideoRecordStopped = {0x2000E546}; + const TUid KCamCControllerCCVideoFileComposed = {0x2000E547}; + + const TInt64 KMinRequiredSpaceVideo = 4000000; +} + + +/*! +* CxeVideoCaptureControlSymbian::CxeVideoCaptureControlSymbian +*/ +CxeVideoCaptureControlSymbian::CxeVideoCaptureControlSymbian( + CxeCameraDevice &cameraDevice, + CxeViewfinderControl &viewfinderControl, + CxeSnapshotControl &snapshotControl, + CxeCameraDeviceControl &cameraDeviceControl, + CxeFilenameGenerator &nameGenerator, + CxeSettings &settings, + CxeQualityPresets &qualityPresets, + CxeDiskMonitor &diskMonitor) + : CxeStateMachine("CxeVideoCaptureControlSymbian"), + mVideoRecorder(NULL), + mCameraDevice(cameraDevice), + mCameraDeviceControl(cameraDeviceControl), + mViewfinderControl(viewfinderControl), + mSnapshotControl(snapshotControl), + mFilenameGenerator(nameGenerator), + mSettings(settings), + mQualityPresets(qualityPresets), + mDiskMonitor(diskMonitor), + mSnapshot(), + mVideoStartSoundPlayer(NULL), + mVideoStopSoundPlayer(NULL), + mCurrentFilename("") +{ + CX_DEBUG_ENTER_FUNCTION(); + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_IN, "msg: e_CX_VIDEOCAPTURECONTROL_NEW 1"); + + qRegisterMetaType (); + initializeStates(); + + mVideoStopSoundPlayer = new + CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::VideoCaptureStop, + mSettings); + mVideoStartSoundPlayer = new + CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::VideoCaptureStart, + mSettings); + + // If camera is already allocated, call the slot ourselves. + if (mCameraDevice.camera()) { + handleCameraAllocated(CxeError::None); + } + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_M1, "msg: e_CX_ENGINE_CONNECT_SIGNALS 1"); + // 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())); + + // connect snapshot ready signal + connect(&mSnapshotControl, SIGNAL(snapshotReady(CxeError::Id, const QImage&)), + this, SLOT(handleSnapshotReady(CxeError::Id, const QImage&))); + + // enabling setting change callbacks to videocapturecontrol + connect(&mSettings, SIGNAL(settingValueChanged(const QString&,QVariant)), + this, SLOT(handleSettingValueChanged(const QString&,QVariant))); + + mSettings.listenForSetting(CxeSettingIds::VIDEO_SCENE, this, SLOT(handleSceneChanged(const QVariant&))); + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_M2, "msg: e_CX_ENGINE_CONNECT_SIGNALS 0"); + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_OUT, "msg: e_CX_VIDEOCAPTURECONTROL_NEW 0"); + 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(); + + // Nothing to do if already idle. + if(state() != Idle) { + OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_VIDEO_CAPCONT_DEINIT 1" ); + + // first stop viewfinder + mViewfinderControl.stop(); + + // stop video-recording in-case if its ongoing. + stop(); + + // 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 (state() == Stopping) { + emit videoComposed(CxeError::None, mCurrentFilename); + } + + mSnapshotControl.stop(); + + if (mVideoRecorder) { + mVideoRecorder->close(); + } + + 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(); + + // Init needed only in Idle state + if (state() == Idle) { + try { + // If video recorder is not yet created, do it now. + createVideoRecorder(); + + // Update current video quality details from ICM. + // Throws an error if unable to get the quality. + updateVideoCaptureParameters(); + + // Video recorder is ready to open video file for recording. + setState(Initialized); + open(); + } catch (const std::exception &e) { + // Handle error + handlePrepareFailed(); + } + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Opens file for video recording. +*/ +void CxeVideoCaptureControlSymbian::open() +{ + CX_DEBUG_ENTER_FUNCTION(); + + // Check valid state to start "open" operation + if (state() == Initialized) { + try { + // generate video file name, if necessary + generateFilename(); + CX_DEBUG(( "Next video file path: %s", mCurrentFilename.toAscii().constData() )); + + // Start preparing.. + setState(CxeVideoCaptureControl::Preparing); + + // Exception thrown if open fails. + mVideoRecorder->open(mCameraDevice.camera()->Handle(), + mCurrentFilename, + mCurrentVideoDetails.mVideoFileMimeType, + mCurrentVideoDetails.mPreferredSupplier, + mCurrentVideoDetails.mVideoCodecMimeType, + mCurrentVideoDetails.mAudioType); + } catch (const std::exception &e) { + handlePrepareFailed(); + } + } + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Helper method for generating filename. +* Throws exception, if file type mime is formatted wrong or +* filename generation fails. +*/ +void CxeVideoCaptureControlSymbian::generateFilename() +{ + CX_DEBUG_ENTER_FUNCTION(); + mCurrentFilename = QString(""); + + QStringList list = mCurrentVideoDetails.mVideoFileMimeType.split("/"); + // Throw exception if mime string is formatted wrong. + if (list.count() != 2) { + throw new CxeException(CxeError::General); + } + QString fileExt = "." + list[1]; + + // Generate new filename and open the file for writing video data + CxeException::throwIfError(mFilenameGenerator.generateFilename(mCurrentFilename, fileExt)); + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* 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; + } + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARE_1, "msg: e_CX_VIDCAPCONT_PREPARE 1"); + QSize frameSize(mCurrentVideoDetails.mWidth, mCurrentVideoDetails.mHeight); + + bool muteSetting = mSettings.get(CxeSettingIds::VIDEO_MUTE_SETTING, false); + + // Check if scene defines frame rate. + // Use generic frame rate defined in video details, if no value is set in scene. + int frameRate = mSettings.get(CxeSettingIds::FRAME_RATE, 0); + if (frameRate <= 0) { + frameRate = mCurrentVideoDetails.mVideoFrameRate; + } + + CX_DEBUG(("Video resolution (%d,%d)", mCurrentVideoDetails.mWidth, + mCurrentVideoDetails.mHeight)); + CX_DEBUG(("Video bitrate = %d)", mCurrentVideoDetails.mVideoBitRate)); + CX_DEBUG(("Video frame rate = %d)", frameRate)); + + try { + mVideoRecorder->setVideoFrameSize(frameSize); + mVideoRecorder->setVideoFrameRate(frameRate); + mVideoRecorder->setVideoBitRate(mCurrentVideoDetails.mVideoBitRate); + mVideoRecorder->setAudioEnabled(!muteSetting); + // "No limit" value is handled in video recorder wrapper. + mVideoRecorder->setVideoMaxSize(mCurrentVideoDetails.mMaximumSizeInBytes); + + // Settings have been applied successfully, start to prepare. + mVideoRecorder->prepare(); + + // Prepare zoom only when there are no errors during prepare. + emit prepareZoomForVideo(); + emit videoPrepareComplete(CxeError::None); + } catch (const std::exception &e) { + // Handle error. + handlePrepareFailed(); + } + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARE_2, "msg: e_CX_VIDCAPCONT_PREPARE 0"); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Prepare video snapshot. +* Throws exception on error. +*/ +void CxeVideoCaptureControlSymbian::prepareSnapshot() +{ + CX_DEBUG_ENTER_FUNCTION(); + OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARESNAP_1, "msg: e_CX_PREPARE_SNAPSHOT 1" ); + + // Prepare snapshot. Snapshot control throws error if problems. + QSize snapshotSize = mSnapshotControl.calculateSnapshotSize( + mViewfinderControl.deviceDisplayResolution(), + mCurrentVideoDetails.mAspectRatio); + mSnapshotControl.start(snapshotSize); + + OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARESNAP_2, "msg: e_CX_PREPARE_SNAPSHOT 0" ); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! + Fetch video quality details based on current video quality setting. +*/ +void CxeVideoCaptureControlSymbian::updateVideoCaptureParameters() +{ + CX_DEBUG_ENTER_FUNCTION(); + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_UPDATEVIDEOCAPTUREPARAMETERS_1, "msg: e_CX_UPDATE_VIDEO_CAPTURE_PARAMETERS 1"); + + int quality = 0; + + // Get quality index for primary camera. Only one quality for secondary camera. + if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) { + quality = mSettings.get(CxeSettingIds::VIDEO_QUALITY); + } + + if (quality < 0 || quality >= mIcmSupportedVideoResolutions.count()) { + throw new CxeException(CxeError::NotFound); + } + + // Get video quality details + mCurrentVideoDetails = mIcmSupportedVideoResolutions.at(quality); + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_UPDATEVIDEOCAPTUREPARAMETERS_2, "msg: e_CX_UPDATE_VIDEO_CAPTURE_PARAMETERS 0"); + 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(); + try { + mVideoRecorder->pause(); + setState(CxeVideoCaptureControl::Paused); + // play the sound, but not changing the state + mVideoStopSoundPlayer->play(); + } catch (const std::exception &e) { + handleComposeFailed(qt_symbian_exception2Error(e)); + } + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Stops video recording. +*/ +void CxeVideoCaptureControlSymbian::stop() +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (state() == Recording || state() == Paused) { + // first stop viewfinder + mViewfinderControl.stop(); + + try { + // Try asynchronous stopping first. + mVideoRecorder->stop(true); + // No error from asynchronous stop -> wait for stop event + if (state() != Ready) { + setState(Stopping); + } + } catch (const std::exception &e) { + CX_DEBUG(("CxeVideoCaptureControlSymbian - async stop failed, try sync..")); + try { + mVideoRecorder->stop(false); + // stopping went ok + emulateNormalStopping(); + } catch (const std::exception &e) { + // Even synchronous stopping failed -> release resources. + CX_DEBUG(("CxeVideoCaptureControlSymbian - sync stop failed, too!")); + handleComposeFailed(qt_symbian_exception2Error(e)); + } + } + } + + 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) { + prepare(); + } else { + handlePrepareFailed(); + } + } + + 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) { + try { + // Check that no error coming in. + CxeException::throwIfError(aError); + // Start viewfinder + mViewfinderControl.start(); + // Prepare snapshot (throws exception if fails). + prepareSnapshot(); + // Ready for recording now. + setState(CxeVideoCaptureControl::Ready); + OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_GOTOVIDEO, "msg: e_CX_GO_TO_VIDEO_MODE 0" ); + } catch (const std::exception &e) { + handlePrepareFailed(); + } + } + + 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. + emulateNormalStopping(); + } + else { + // error during recording, report to client + handleComposeFailed(aError); + } + + 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); + } + mFilenameGenerator.raiseCounterValue(); + // video file has composed, everything went well, inform the client + emit videoComposed(CxeError::None, filename()); + } else { + CX_DEBUG(("ignoring unknown MvruoEvent 0x%08x", aEvent.iEventType.iUid )); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* 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) { + try { + // Create the video recorder utility + createVideoRecorder(); + } catch (...) { + // We are just trying to create the recorder early. + // Retry later when preparing, and fail then if + // error still persists. + } + // new camera available, read supported video qualities from icm + // load all video 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. +* May throw exception. +*/ +void CxeVideoCaptureControlSymbian::createVideoRecorder() +{ + CX_DEBUG_ENTER_FUNCTION(); + if (mVideoRecorder == NULL) { + mVideoRecorder = new CxeVideoRecorderUtilitySymbian(*this); + } + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* releases resources used by video capture control +*/ +void CxeVideoCaptureControlSymbian::releaseResources() +{ + CX_DEBUG_ENTER_FUNCTION(); + + // first de-init videocapture control + deinit(); + reset(); + + delete mVideoRecorder; + mVideoRecorder = NULL; + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Returns current state of video capture control +*/ +CxeVideoCaptureControl::State CxeVideoCaptureControlSymbian::state() const +{ + return static_cast (stateId()); +} + +/*! +* Called when state is changed. +*/ +void CxeVideoCaptureControlSymbian::handleStateChanged(int newStateId, CxeError::Id error) +{ + switch (newStateId) { + case Ready: + if (error == CxeError::None && !mDiskMonitor.isMonitoring()) { + mDiskMonitor.start(); + connect(&mDiskMonitor, SIGNAL(diskSpaceChanged()), this, SLOT(handleDiskSpaceChanged())); + } + break; + default: + // Stop monitoring when video mode is released. + // Same goes during recording, as video times come from recorder. + if (mDiskMonitor.isMonitoring()) { + mDiskMonitor.stop(); + disconnect(&mDiskMonitor, SIGNAL(diskSpaceChanged()), this, SLOT(handleDiskSpaceChanged())); + } + break; + } + emit stateChanged(static_cast (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 | Ready)); + addState(new CxeState(Paused, "Paused", Recording | Stopping | PlayingStartSound | Idle)); + addState(new CxeState(Stopping, "Stopping", Initialized | Idle | Ready)); + 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]; + qualityDetails.mRemainingTime = calculateRemainingTime(qualityDetails); + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* calculates remaining video recording time. +*/ +void CxeVideoCaptureControlSymbian::remainingTime(int &time) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (state() == CxeVideoCaptureControl::Recording || + state() == CxeVideoCaptureControl::Paused) { + time = mVideoRecorder->availableRecordingTime(); + CX_DEBUG(("CxeVideoCaptureControlSymbian - time remaining: %d", time)); + } else { + // Check if we need to recalculate the remaining time. + if (mCurrentVideoDetails.mRemainingTime == CxeVideoDetails::UNKNOWN) { + mCurrentVideoDetails.mRemainingTime = calculateRemainingTime(mCurrentVideoDetails); + } + time = mCurrentVideoDetails.mRemainingTime; + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Get the remaining recording time +* @param videoDetails Contains the current video resolution that is in use. +* @return The remaining recording time +*/ +int CxeVideoCaptureControlSymbian::calculateRemainingTime(const CxeVideoDetails& videoDetails) +{ + CX_DEBUG_ENTER_FUNCTION(); + qint64 availableSpace = mDiskMonitor.free() - KMinRequiredSpaceVideo; + int time = mQualityPresets.recordingTimeAvailable(videoDetails, availableSpace); + CX_DEBUG_EXIT_FUNCTION(); + return time; +} + +/*! +* Calculates elapsed recording time during video recording +* @return Did fetching elapsed time succeed. +*/ +bool CxeVideoCaptureControlSymbian::elapsedTime(int &time) +{ + CX_DEBUG_ENTER_FUNCTION(); + + bool ok = false; + if (state() == CxeVideoCaptureControl::Recording || + state() == CxeVideoCaptureControl::Paused) { + try { + time = mVideoRecorder->duration(); + CX_DEBUG(("CxeVideoCaptureControlSymbian - elapsed: %d", time)); + ok = true; + } catch (const std::exception &e) { + // Returning false. + } + } + + 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(); +} + +/*! +* Handle new snapshot. +* @param status Status code for getting the snapshot. +* @param snapshot Snapshot pixmap. Empty if error code reported. +*/ +void CxeVideoCaptureControlSymbian::handleSnapshotReady(CxeError::Id status, const QImage &snapshot) +{ + CX_DEBUG_ENTER_FUNCTION(); + + if (mCameraDeviceControl.mode() == Cxe::VideoMode) { + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_HANDLESNAPSHOT_1, "msg: e_CX_HANDLE_SNAPSHOT 1"); + + // Need to store snapshot for ui to be able to get it also later. + mSnapshot = QPixmap::fromImage(snapshot); + emit snapshotReady(status, snapshot, filename()); + + OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_HANDLESNAPSHOT_2, "msg: e_CX_HANDLE_SNAPSHOT 0"); + } + + 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 if (settingId == CxeSettingIds::FRAME_RATE) { + // Frame rate setting changed. Need to re-prepare if we are prepared already. + // Otherwise can wait for next init call. + if (state() == Ready) { + setState(Preparing); + prepare(); + } + } else { + // Setting not relevant to video mode + } + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! + * Scene mode changed. We need to know about it because frame rate + * might have changed. + */ +void CxeVideoCaptureControlSymbian::handleSceneChanged(const QVariant& scene) +{ + Q_UNUSED(scene) + CX_DEBUG_ENTER_FUNCTION(); + + // make sure we are in video mode + if (mCameraDeviceControl.mode() == Cxe::VideoMode) { + // Frame rate setting might have changed so re-prepare. + if (state() == Ready) { + setState(Preparing); + prepare(); + } + + } + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Disk space changed. +* Emit remaining time changed signal, if space change affects it. +*/ +void CxeVideoCaptureControlSymbian::handleDiskSpaceChanged() +{ + CX_DEBUG_ENTER_FUNCTION(); + + // Ignore updates on preparing phase. + if (state() == CxeVideoCaptureControl::Ready) { + + int time(calculateRemainingTime(mCurrentVideoDetails)); + + if (time != mCurrentVideoDetails.mRemainingTime) { + mCurrentVideoDetails.mRemainingTime = time; + emit remainingTimeChanged(); + } + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! + Use ECam Use Case Hint Custom API to inform ECam of our intended use case + before calling Reserve(). +*/ +void CxeVideoCaptureControlSymbian::hintUseCase() +{ + CX_DEBUG_ENTER_FUNCTION(); + + // Make sure ECam knows we're doing video recording so it can prepare + // for the correct use case. + if (mCameraDeviceControl.mode() == Cxe::VideoMode) { + MCameraUseCaseHint *useCaseHintApi = mCameraDevice.useCaseHintApi(); + if (useCaseHintApi) { + MCameraUseCaseHint::TVideoCodec codec = + MCameraUseCaseHint::ECodecUnknown; + MCameraUseCaseHint::TVideoProfile profile = + MCameraUseCaseHint::EProfileUnknown; + + updateVideoCaptureParameters(); + CxeSettingsMapperSymbian::Map2UseCaseHintVideoParameters( + mCurrentVideoDetails, codec, profile); + + TSize resolution(mCurrentVideoDetails.mWidth, + mCurrentVideoDetails.mHeight); + TRAP_IGNORE(useCaseHintApi->HintDirectVideoCaptureL(codec, profile, + resolution)); + } + } + + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Returns QList of all supported video quality details based on the camera index +* (primary/secondary). +*/ +QList CxeVideoCaptureControlSymbian::supportedVideoQualities() +{ + // update the remaining time counters for each quality setting + updateRemainingRecordingTimeCounter(); + return mIcmSupportedVideoResolutions; +} + +/*! +* Helper method to handle error during preparing phase. +*/ +void CxeVideoCaptureControlSymbian::handlePrepareFailed() +{ + CX_DEBUG_ENTER_FUNCTION(); + CX_DEBUG(("[ERROR] Preparing video failed!")); + // Cleanup + deinit(); + // Inform client + emit videoPrepareComplete(CxeError::InitializationFailed); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! +* Helper method to handle error from video composing. +* @param error Symbian error code. +*/ +void CxeVideoCaptureControlSymbian::handleComposeFailed(int error) +{ + CX_DEBUG_ENTER_FUNCTION(); + CX_DEBUG(("[ERROR] Composing video failed!")); + // Inform client + emit videoComposed(CxeErrorHandlingSymbian::map(error), filename()); + // Cleanup + deinit(); + CX_DEBUG_EXIT_FUNCTION(); +} + +/*! + * Helper method to emulate video stopping events. + */ +void CxeVideoCaptureControlSymbian::emulateNormalStopping() +{ + CX_DEBUG_ENTER_FUNCTION(); + + setState(Stopping); + MvruoEvent(TMMFEvent(KCamCControllerCCVideoRecordStopped, KErrNone)); + MvruoEvent(TMMFEvent(KCamCControllerCCVideoFileComposed, KErrNone)); + + CX_DEBUG_EXIT_FUNCTION(); +} +// End of file