camerauis/cameraxui/cxengine/src/cxevideocapturecontrolsymbian.cpp
branchRCL_3
changeset 24 bac7acad7cb3
parent 23 61bc0f252b2b
child 25 2c87b2808fd7
equal deleted inserted replaced
23:61bc0f252b2b 24:bac7acad7cb3
     1 /*
       
     2 * Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include <algorithm>
       
    19 #include <exception>
       
    20 #include <QTime>
       
    21 #include <QPixmap>
       
    22 #include <coemain.h>
       
    23 #include <QStringList>
       
    24 
       
    25 #include "cxeexception.h"
       
    26 #include "cxevideocapturecontrolsymbian.h"
       
    27 #include "cxevideorecorderutilitysymbian.h"
       
    28 #include "cxecameradevicecontrolsymbian.h"
       
    29 #include "cxefilenamegeneratorsymbian.h"
       
    30 #include "cxeerrormappingsymbian.h"
       
    31 #include "cxeviewfindercontrol.h"
       
    32 #include "cxesnapshotcontrol.h"
       
    33 #include "cxestillimagesymbian.h"
       
    34 #include "cxecameradevice.h"
       
    35 #include "cxutils.h"
       
    36 #include "cxestate.h"
       
    37 #include "cxesettings.h"
       
    38 #include "cxenamespace.h"
       
    39 #include "cxesoundplayersymbian.h"
       
    40 #include "cxequalitypresetssymbian.h"
       
    41 #include "cxeviewfindercontrolsymbian.h"
       
    42 #include "cxediskmonitor.h"
       
    43 #include "cxesettingsmappersymbian.h"
       
    44 
       
    45 #include "OstTraceDefinitions.h"
       
    46 #ifdef OST_TRACE_COMPILER_IN_USE
       
    47 #include "cxevideocapturecontrolsymbianTraces.h"
       
    48 #endif
       
    49 
       
    50 
       
    51 // constants
       
    52 namespace
       
    53 {
       
    54     // TMMFEvent UIDs for Async stop
       
    55     const TUid KCamCControllerCCVideoRecordStopped = {0x2000E546};
       
    56     const TUid KCamCControllerCCVideoFileComposed = {0x2000E547};
       
    57 
       
    58     const TInt64  KMinRequiredSpaceVideo      = 4000000;
       
    59 }
       
    60 
       
    61 
       
    62 /*!
       
    63 * CxeVideoCaptureControlSymbian::CxeVideoCaptureControlSymbian
       
    64 */
       
    65 CxeVideoCaptureControlSymbian::CxeVideoCaptureControlSymbian(
       
    66     CxeCameraDevice &cameraDevice,
       
    67     CxeViewfinderControl &viewfinderControl,
       
    68     CxeSnapshotControl &snapshotControl,
       
    69     CxeCameraDeviceControl &cameraDeviceControl,
       
    70     CxeFilenameGenerator &nameGenerator,
       
    71     CxeSettings &settings,
       
    72     CxeQualityPresets &qualityPresets,
       
    73     CxeDiskMonitor &diskMonitor)
       
    74     : CxeStateMachine("CxeVideoCaptureControlSymbian"),
       
    75       mVideoRecorder(NULL),
       
    76       mCameraDevice(cameraDevice),
       
    77       mCameraDeviceControl(cameraDeviceControl),
       
    78       mViewfinderControl(viewfinderControl),
       
    79       mSnapshotControl(snapshotControl),
       
    80       mFilenameGenerator(nameGenerator),
       
    81       mSettings(settings),
       
    82       mQualityPresets(qualityPresets),
       
    83       mDiskMonitor(diskMonitor),
       
    84       mSnapshot(),
       
    85       mVideoStartSoundPlayer(NULL),
       
    86       mVideoStopSoundPlayer(NULL),
       
    87       mCurrentFilename("")
       
    88 {
       
    89     CX_DEBUG_ENTER_FUNCTION();
       
    90     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_IN, "msg: e_CX_VIDEOCAPTURECONTROL_NEW 1");
       
    91 
       
    92     qRegisterMetaType<CxeVideoCaptureControl::State> ();
       
    93     initializeStates();
       
    94 
       
    95     mVideoStopSoundPlayer = new
       
    96              CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::VideoCaptureStop,
       
    97                                    mSettings);
       
    98     mVideoStartSoundPlayer = new
       
    99              CxeSoundPlayerSymbian(CxeSoundPlayerSymbian::VideoCaptureStart,
       
   100                                    mSettings);
       
   101 
       
   102     // If camera is already allocated, call the slot ourselves.
       
   103     if (mCameraDevice.camera()) {
       
   104         handleCameraAllocated(CxeError::None);
       
   105     }
       
   106 
       
   107     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_M1, "msg: e_CX_ENGINE_CONNECT_SIGNALS 1");
       
   108     // connect signals from cameraDevice, so we recieve events when camera reference changes
       
   109     connect(&cameraDevice, SIGNAL(prepareForCameraDelete()),
       
   110             this, SLOT(prepareForCameraDelete()));
       
   111     connect(&cameraDevice, SIGNAL(prepareForRelease()),
       
   112             this, SLOT(prepareForRelease()) );
       
   113     connect(&cameraDevice, SIGNAL(cameraAllocated(CxeError::Id)),
       
   114             this, SLOT(handleCameraAllocated(CxeError::Id)));
       
   115 
       
   116     // connect playing sound signals
       
   117     connect(mVideoStartSoundPlayer, SIGNAL(playComplete(int)),
       
   118             this, SLOT(handleSoundPlayed()));
       
   119 
       
   120     // connect snapshot ready signal
       
   121     connect(&mSnapshotControl, SIGNAL(snapshotReady(CxeError::Id, const QImage&)),
       
   122             this, SLOT(handleSnapshotReady(CxeError::Id, const QImage&)));
       
   123 
       
   124     // enabling setting change callbacks to videocapturecontrol
       
   125     connect(&mSettings, SIGNAL(settingValueChanged(const QString&,QVariant)),
       
   126             this, SLOT(handleSettingValueChanged(const QString&,QVariant)));
       
   127 
       
   128     mSettings.listenForSetting(CxeSettingIds::VIDEO_SCENE, this, SLOT(handleSceneChanged(const QVariant&)));
       
   129 
       
   130     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_M2, "msg: e_CX_ENGINE_CONNECT_SIGNALS 0");
       
   131 
       
   132     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_CREATE_OUT, "msg: e_CX_VIDEOCAPTURECONTROL_NEW 0");
       
   133     CX_DEBUG_EXIT_FUNCTION();
       
   134 }
       
   135 
       
   136 /*!
       
   137 * CxeVideoCaptureControlSymbian::~CxeVideoCaptureControlSymbian()
       
   138 */
       
   139 CxeVideoCaptureControlSymbian::~CxeVideoCaptureControlSymbian()
       
   140 {
       
   141     CX_DEBUG_ENTER_FUNCTION();
       
   142 
       
   143     releaseResources();
       
   144     mIcmSupportedVideoResolutions.clear();
       
   145     delete mVideoStartSoundPlayer;
       
   146     delete mVideoStopSoundPlayer;
       
   147 
       
   148     CX_DEBUG_EXIT_FUNCTION();
       
   149 }
       
   150 
       
   151 /*!
       
   152 * Initializes resources for video recording.
       
   153 */
       
   154 void CxeVideoCaptureControlSymbian::init()
       
   155 {
       
   156     CX_DEBUG_ENTER_FUNCTION();
       
   157     OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_VIDEO_CAPCONT_INIT 1" );
       
   158 
       
   159     if (state() == Idle) {
       
   160         // start initializing resources for video capture
       
   161         initVideoRecorder();
       
   162     } else if (state() == Initialized) {
       
   163         // video recorder already initalized. Continue to prepare video reocording.
       
   164         open();
       
   165     }
       
   166 
       
   167     OstTrace0( camerax_performance, DUP1_CXEVIDEOCAPTURECONTROLSYMBIAN_INIT, "msg: e_CX_VIDEO_CAPCONT_INIT 0" );
       
   168     CX_DEBUG_EXIT_FUNCTION();
       
   169 }
       
   170 
       
   171 /*!
       
   172 * Releases all resources
       
   173 */
       
   174 void CxeVideoCaptureControlSymbian::deinit()
       
   175 {
       
   176     CX_DEBUG_ENTER_FUNCTION();
       
   177 
       
   178     // Nothing to do if already idle.
       
   179     if(state() != Idle) {
       
   180         OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_VIDEO_CAPCONT_DEINIT 1" );
       
   181 
       
   182         // first stop viewfinder
       
   183         mViewfinderControl.stop();
       
   184 
       
   185         // stop video-recording in-case if its ongoing.
       
   186         stop();
       
   187 
       
   188         // Check if state is stopping, in which case we have to inform the
       
   189         // file harvester that a file is to be completed. We would not
       
   190         // call harvestFile otherwise in this case.
       
   191         // Otherwise the video will not be found from videos app.
       
   192         if (state() == Stopping) {
       
   193             emit videoComposed(CxeError::None, mCurrentFilename);
       
   194         }
       
   195 
       
   196         mSnapshotControl.stop();
       
   197 
       
   198         if (mVideoRecorder) {
       
   199             mVideoRecorder->close();
       
   200         }
       
   201 
       
   202         setState(Idle);
       
   203 
       
   204         OstTrace0( camerax_performance, DUP1_CXEVIDEOCAPTURECONTROLSYMBIAN_DEINIT, "msg: e_CX_VIDEO_CAPCONT_DEINIT 0" );
       
   205     }
       
   206     CX_DEBUG_EXIT_FUNCTION();
       
   207 }
       
   208 
       
   209 /*!
       
   210 * Intializes VideoRecorder for recording.
       
   211 */
       
   212 void CxeVideoCaptureControlSymbian::initVideoRecorder()
       
   213 {
       
   214     CX_DEBUG_ENTER_FUNCTION();
       
   215 
       
   216     // Init needed only in Idle state
       
   217     if (state() == Idle) {
       
   218         try {
       
   219             // If video recorder is not yet created, do it now.
       
   220             createVideoRecorder();
       
   221 
       
   222             // Update current video quality details from ICM.
       
   223             // Throws an error if unable to get the quality.
       
   224             updateVideoCaptureParameters();
       
   225 
       
   226             // Video recorder is ready to open video file for recording.
       
   227             setState(Initialized);
       
   228             open();
       
   229         } catch (const std::exception &e) {
       
   230             // Handle error
       
   231             handlePrepareFailed();
       
   232         }
       
   233     }
       
   234 
       
   235     CX_DEBUG_EXIT_FUNCTION();
       
   236 }
       
   237 
       
   238 /*!
       
   239 * Opens file for video recording.
       
   240 */
       
   241 void CxeVideoCaptureControlSymbian::open()
       
   242 {
       
   243     CX_DEBUG_ENTER_FUNCTION();
       
   244 
       
   245     // Check valid state to start "open" operation
       
   246     if (state() == Initialized) {
       
   247         try {
       
   248             // generate video file name, if necessary
       
   249             generateFilename();
       
   250             CX_DEBUG(( "Next video file path: %s", mCurrentFilename.toAscii().constData() ));
       
   251 
       
   252             // Start preparing..
       
   253             setState(CxeVideoCaptureControl::Preparing);
       
   254 
       
   255             // Exception thrown if open fails.
       
   256             mVideoRecorder->open(mCameraDevice.camera()->Handle(),
       
   257                                  mCurrentFilename,
       
   258                                  mCurrentVideoDetails.mVideoFileMimeType,
       
   259                                  mCurrentVideoDetails.mPreferredSupplier,
       
   260                                  mCurrentVideoDetails.mVideoCodecMimeType,
       
   261                                  mCurrentVideoDetails.mAudioType);
       
   262         } catch (const std::exception &e) {
       
   263             handlePrepareFailed();
       
   264         }
       
   265     }
       
   266     CX_DEBUG_EXIT_FUNCTION();
       
   267 }
       
   268 
       
   269 /*!
       
   270 * Helper method for generating filename.
       
   271 * Throws exception, if file type mime is formatted wrong or
       
   272 * filename generation fails.
       
   273 */
       
   274 void CxeVideoCaptureControlSymbian::generateFilename()
       
   275 {
       
   276     CX_DEBUG_ENTER_FUNCTION();
       
   277     mCurrentFilename = QString("");
       
   278 
       
   279     QStringList list = mCurrentVideoDetails.mVideoFileMimeType.split("/");
       
   280     // Throw exception if mime string is formatted wrong.
       
   281     if (list.count() != 2) {
       
   282         throw new CxeException(CxeError::General);
       
   283     }
       
   284     QString fileExt = "." + list[1];
       
   285 
       
   286     // Generate new filename and open the file for writing video data
       
   287     CxeException::throwIfError(mFilenameGenerator.generateFilename(mCurrentFilename, fileExt));
       
   288 
       
   289     CX_DEBUG_EXIT_FUNCTION();
       
   290 }
       
   291 
       
   292 /*!
       
   293 * Prepare Video Recorder with necessary settings for video capture.
       
   294 */
       
   295 void CxeVideoCaptureControlSymbian::prepare()
       
   296 {
       
   297     CX_DEBUG_ENTER_FUNCTION();
       
   298 
       
   299     if (state() != Preparing) {
       
   300         // not valid state to continue prepare.
       
   301         return;
       
   302     }
       
   303 
       
   304     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARE_1, "msg: e_CX_VIDCAPCONT_PREPARE 1");
       
   305     QSize frameSize(mCurrentVideoDetails.mWidth, mCurrentVideoDetails.mHeight);
       
   306 
       
   307     bool muteSetting = mSettings.get<bool>(CxeSettingIds::VIDEO_MUTE_SETTING, false);
       
   308 
       
   309     // Check if scene defines frame rate.
       
   310     // Use generic frame rate defined in video details, if no value is set in scene.
       
   311     int frameRate = mSettings.get<int>(CxeSettingIds::FRAME_RATE, 0);
       
   312     if (frameRate <= 0) {
       
   313         frameRate = mCurrentVideoDetails.mVideoFrameRate;
       
   314     }
       
   315 
       
   316     CX_DEBUG(("Video resolution (%d,%d)", mCurrentVideoDetails.mWidth,
       
   317                                            mCurrentVideoDetails.mHeight));
       
   318     CX_DEBUG(("Video bitrate = %d)", mCurrentVideoDetails.mVideoBitRate));
       
   319     CX_DEBUG(("Video frame rate = %d)", frameRate));
       
   320 
       
   321     try {
       
   322         mVideoRecorder->setVideoFrameSize(frameSize);
       
   323         mVideoRecorder->setVideoFrameRate(frameRate);
       
   324         mVideoRecorder->setVideoBitRate(mCurrentVideoDetails.mVideoBitRate);
       
   325         mVideoRecorder->setAudioEnabled(!muteSetting);
       
   326         // "No limit" value is handled in video recorder wrapper.
       
   327         mVideoRecorder->setVideoMaxSize(mCurrentVideoDetails.mMaximumSizeInBytes);
       
   328 
       
   329         // Settings have been applied successfully, start to prepare.
       
   330         mVideoRecorder->prepare();
       
   331 
       
   332         // Prepare zoom only when there are no errors during prepare.
       
   333         emit prepareZoomForVideo();
       
   334         emit videoPrepareComplete(CxeError::None);
       
   335     } catch (const std::exception &e) {
       
   336         // Handle error.
       
   337         handlePrepareFailed();
       
   338     }
       
   339 
       
   340     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARE_2, "msg: e_CX_VIDCAPCONT_PREPARE 0");
       
   341     CX_DEBUG_EXIT_FUNCTION();
       
   342 }
       
   343 
       
   344 /*!
       
   345 * Prepare video snapshot.
       
   346 * Throws exception on error.
       
   347 */
       
   348 void CxeVideoCaptureControlSymbian::prepareSnapshot()
       
   349 {
       
   350     CX_DEBUG_ENTER_FUNCTION();
       
   351     OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARESNAP_1, "msg: e_CX_PREPARE_SNAPSHOT 1" );
       
   352 
       
   353     // Prepare snapshot. Snapshot control throws error if problems.
       
   354     QSize snapshotSize = mSnapshotControl.calculateSnapshotSize(
       
   355                             mViewfinderControl.deviceDisplayResolution(),
       
   356                             mCurrentVideoDetails.mAspectRatio);
       
   357     mSnapshotControl.start(snapshotSize);
       
   358 
       
   359     OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROL_PREPARESNAP_2, "msg: e_CX_PREPARE_SNAPSHOT 0" );
       
   360     CX_DEBUG_EXIT_FUNCTION();
       
   361 }
       
   362 
       
   363 /*!
       
   364   Fetch video quality details based on current video quality setting.
       
   365 */
       
   366 void CxeVideoCaptureControlSymbian::updateVideoCaptureParameters()
       
   367 {
       
   368     CX_DEBUG_ENTER_FUNCTION();
       
   369     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_UPDATEVIDEOCAPTUREPARAMETERS_1, "msg: e_CX_UPDATE_VIDEO_CAPTURE_PARAMETERS 1");
       
   370 
       
   371     int quality = 0;
       
   372 
       
   373     // Get quality index for primary camera. Only one quality for secondary camera.
       
   374     if (mCameraDeviceControl.cameraIndex() == Cxe::PrimaryCameraIndex) {
       
   375         quality = mSettings.get<int>(CxeSettingIds::VIDEO_QUALITY);
       
   376     }
       
   377 
       
   378     if (quality < 0 || quality >= mIcmSupportedVideoResolutions.count()) {
       
   379        throw new CxeException(CxeError::NotFound);
       
   380     }
       
   381 
       
   382     // Get video quality details
       
   383     mCurrentVideoDetails = mIcmSupportedVideoResolutions.at(quality);
       
   384 
       
   385     OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_UPDATEVIDEOCAPTUREPARAMETERS_2, "msg: e_CX_UPDATE_VIDEO_CAPTURE_PARAMETERS 0");
       
   386     CX_DEBUG_EXIT_FUNCTION();
       
   387 }
       
   388 
       
   389 /*!
       
   390 * Resets the video snapshot and current video filename
       
   391 */
       
   392 void CxeVideoCaptureControlSymbian::reset()
       
   393 {
       
   394     CX_DEBUG_ENTER_FUNCTION();
       
   395 
       
   396     // Snapshot will consume considerably memory.
       
   397     // Replace it with null pixmap to have it freed.
       
   398     mSnapshot = QPixmap();
       
   399     // reset the current file name.
       
   400     mCurrentFilename = QString("");
       
   401 
       
   402     CX_DEBUG_EXIT_FUNCTION();
       
   403 }
       
   404 
       
   405 /*!
       
   406 * Returns current video filename
       
   407 */
       
   408 QString CxeVideoCaptureControlSymbian::filename() const
       
   409 {
       
   410     // Simply return the current contents of mCurrentFilename.
       
   411     // If video recording was started then it returns proper filename
       
   412     // otherwise an empty string is returned.
       
   413     return mCurrentFilename;
       
   414 }
       
   415 
       
   416 /*!
       
   417 * Returns current video snapshot
       
   418 */
       
   419 QPixmap CxeVideoCaptureControlSymbian::snapshot() const
       
   420 {
       
   421     return mSnapshot;
       
   422 }
       
   423 
       
   424 /*!
       
   425 * Starts video recording if we are in appropriate state.
       
   426 */
       
   427 void CxeVideoCaptureControlSymbian::record()
       
   428 {
       
   429     CX_DEBUG_ENTER_FUNCTION();
       
   430 
       
   431     if (state() == Ready || state() == Paused) {
       
   432         // ask the player to play the sound
       
   433         // recording will start once start sound is played
       
   434         setState(CxeVideoCaptureControl::PlayingStartSound);
       
   435         mVideoStartSoundPlayer->play();
       
   436     }
       
   437 
       
   438     CX_DEBUG_EXIT_FUNCTION();
       
   439 }
       
   440 
       
   441 /*!
       
   442 * Pauses video recording.
       
   443 */
       
   444 void CxeVideoCaptureControlSymbian::pause()
       
   445 {
       
   446     CX_DEBUG_ENTER_FUNCTION();
       
   447     try {
       
   448         mVideoRecorder->pause();
       
   449         setState(CxeVideoCaptureControl::Paused);
       
   450         // play the sound, but not changing the state
       
   451         mVideoStopSoundPlayer->play();
       
   452     } catch (const std::exception &e) {
       
   453         handleComposeFailed(qt_symbian_exception2Error(e));
       
   454     }
       
   455     CX_DEBUG_EXIT_FUNCTION();
       
   456 }
       
   457 
       
   458 /*!
       
   459 * Stops video recording.
       
   460 */
       
   461 void CxeVideoCaptureControlSymbian::stop()
       
   462 {
       
   463     CX_DEBUG_ENTER_FUNCTION();
       
   464 
       
   465     if (state() == Recording || state() == Paused) {
       
   466         // first stop viewfinder
       
   467         mViewfinderControl.stop();
       
   468 
       
   469         try {
       
   470             // Try asynchronous stopping first.
       
   471             mVideoRecorder->stop(true);
       
   472             // No error from asynchronous stop -> wait for stop event
       
   473             if (state() != Ready) {
       
   474                 setState(Stopping);
       
   475             }
       
   476         } catch (const std::exception &e) {
       
   477             CX_DEBUG(("CxeVideoCaptureControlSymbian - async stop failed, try sync.."));
       
   478             try {
       
   479                 mVideoRecorder->stop(false);
       
   480                 // stopping went ok
       
   481                 emulateNormalStopping();
       
   482             } catch (const std::exception &e) {
       
   483                 // Even synchronous stopping failed -> release resources.
       
   484                 CX_DEBUG(("CxeVideoCaptureControlSymbian - sync stop failed, too!"));
       
   485                 handleComposeFailed(qt_symbian_exception2Error(e));
       
   486             }
       
   487         }
       
   488     }
       
   489 
       
   490     CX_DEBUG_EXIT_FUNCTION();
       
   491 }
       
   492 
       
   493 /*!
       
   494 * Callback when "Open" operation is complete.
       
   495 */
       
   496 void CxeVideoCaptureControlSymbian::MvruoOpenComplete(TInt aError)
       
   497 {
       
   498     CX_DEBUG_ENTER_FUNCTION();
       
   499     CX_DEBUG(("CxeVideoCaptureControlSymbian::MvruoOpenComplete, err=%d", aError));
       
   500 
       
   501     if (state() == Preparing) {
       
   502         if (!aError) {
       
   503             prepare();
       
   504         } else {
       
   505             handlePrepareFailed();
       
   506         }
       
   507     }
       
   508 
       
   509     CX_DEBUG_EXIT_FUNCTION();
       
   510 }
       
   511 
       
   512 /*!
       
   513 * Callback when "Prepare" request is complete.
       
   514 */
       
   515 void CxeVideoCaptureControlSymbian::MvruoPrepareComplete(TInt aError)
       
   516 {
       
   517     CX_DEBUG_ENTER_FUNCTION();
       
   518     CX_DEBUG(("CxeVideoCaptureControlSymbian::MvruoPrepareComplete, err=%d", aError));
       
   519 
       
   520     if (state() == Preparing) {
       
   521         try {
       
   522             // Check that no error coming in.
       
   523             CxeException::throwIfError(aError);
       
   524             // Start viewfinder
       
   525             mViewfinderControl.start();
       
   526             // Prepare snapshot (throws exception if fails).
       
   527             prepareSnapshot();
       
   528             // Ready for recording now.
       
   529             setState(CxeVideoCaptureControl::Ready);
       
   530             OstTrace0( camerax_performance, CXEVIDEOCAPTURECONTROLSYMBIAN_GOTOVIDEO, "msg: e_CX_GO_TO_VIDEO_MODE 0" );
       
   531         } catch (const std::exception &e) {
       
   532             handlePrepareFailed();
       
   533         }
       
   534     }
       
   535 
       
   536     CX_DEBUG_EXIT_FUNCTION();
       
   537 }
       
   538 
       
   539 /*!
       
   540 * Callback when "Record" operation is complete.
       
   541 */
       
   542 void CxeVideoCaptureControlSymbian::MvruoRecordComplete(TInt aError)
       
   543 {
       
   544     CX_DEBUG_ENTER_FUNCTION();
       
   545     CX_DEBUG(("CxeVideoCaptureControlSymbian::MvruoRecordComplete, err=%d", aError));
       
   546 
       
   547     //! async stop customcommand stuff
       
   548     if (aError == KErrNone) {
       
   549         setState(CxeVideoCaptureControl::Ready);
       
   550     } else if (aError == KErrCompletion) {
       
   551         // KErrCompletion is received when video recording stops
       
   552         // because of maximum clip size is reached. Emulate
       
   553         // normal stopping.
       
   554         emulateNormalStopping();
       
   555     }
       
   556     else {
       
   557         // error during recording, report to client
       
   558         handleComposeFailed(aError);
       
   559     }
       
   560 
       
   561     CX_DEBUG_EXIT_FUNCTION();
       
   562 }
       
   563 
       
   564 /*!
       
   565 * Callback from MVideoRecorderUtilityObserver
       
   566 */
       
   567 void CxeVideoCaptureControlSymbian::MvruoEvent(const TMMFEvent& aEvent)
       
   568 {
       
   569     CX_DEBUG_ENTER_FUNCTION();
       
   570 
       
   571     if (aEvent.iEventType.iUid == KCamCControllerCCVideoRecordStopped.iUid) {
       
   572         CX_DEBUG(("KCamCControllerCCVideoRecordStopped"));
       
   573         // play the sound, but not changing the state
       
   574         mVideoStopSoundPlayer->play();
       
   575     } else if (aEvent.iEventType.iUid == KCamCControllerCCVideoFileComposed.iUid) {
       
   576         CX_DEBUG(("KCamCControllerCCVideoFileComposed"));
       
   577         if (state() == Stopping) {
       
   578             // stop operation went fine, set back the state to intialized.
       
   579             setState(Initialized);
       
   580         }
       
   581         mFilenameGenerator.raiseCounterValue();
       
   582         // video file has composed, everything went well, inform the client
       
   583         emit videoComposed(CxeError::None, filename());
       
   584     } else {
       
   585         CX_DEBUG(("ignoring unknown MvruoEvent 0x%08x", aEvent.iEventType.iUid ));
       
   586     }
       
   587 
       
   588     CX_DEBUG_EXIT_FUNCTION();
       
   589 }
       
   590 
       
   591 /*!
       
   592 * camera reference changing, release resources
       
   593 */
       
   594 void CxeVideoCaptureControlSymbian::prepareForCameraDelete()
       
   595 {
       
   596     CX_DEBUG_ENTER_FUNCTION();
       
   597     releaseResources();
       
   598     CX_DEBUG_EXIT_FUNCTION();
       
   599 }
       
   600 
       
   601 /*!
       
   602 * prepare for camera release.
       
   603 */
       
   604 void CxeVideoCaptureControlSymbian::prepareForRelease()
       
   605 {
       
   606     CX_DEBUG_ENTER_FUNCTION();
       
   607     deinit();
       
   608     CX_DEBUG_EXIT_FUNCTION();
       
   609 }
       
   610 
       
   611 /*!
       
   612 * new camera available
       
   613 */
       
   614 void CxeVideoCaptureControlSymbian::handleCameraAllocated(CxeError::Id error)
       
   615 {
       
   616     CX_DEBUG_ENTER_FUNCTION();
       
   617 
       
   618     if (!error) {
       
   619         try {
       
   620             // Create the video recorder utility
       
   621             createVideoRecorder();
       
   622         } catch (...) {
       
   623             // We are just trying to create the recorder early.
       
   624             // Retry later when preparing, and fail then if
       
   625             // error still persists.
       
   626         }
       
   627         // new camera available, read supported video qualities from icm
       
   628         // load all video qualities supported by icm
       
   629         mIcmSupportedVideoResolutions.clear();
       
   630         Cxe::CameraIndex cameraIndex = mCameraDeviceControl.cameraIndex();
       
   631         // get list of supported image qualities based on camera index
       
   632         mIcmSupportedVideoResolutions =
       
   633                 mQualityPresets.videoQualityPresets(cameraIndex);
       
   634     }
       
   635 
       
   636     CX_DEBUG_EXIT_FUNCTION();
       
   637 }
       
   638 
       
   639 /*!
       
   640 * Initializes video recorder.
       
   641 * May throw exception.
       
   642 */
       
   643 void CxeVideoCaptureControlSymbian::createVideoRecorder()
       
   644 {
       
   645     CX_DEBUG_ENTER_FUNCTION();
       
   646     if (mVideoRecorder == NULL) {
       
   647         mVideoRecorder = new CxeVideoRecorderUtilitySymbian(*this);
       
   648     }
       
   649     CX_DEBUG_EXIT_FUNCTION();
       
   650 }
       
   651 
       
   652 /*!
       
   653 * releases resources used by video capture control
       
   654 */
       
   655 void CxeVideoCaptureControlSymbian::releaseResources()
       
   656 {
       
   657     CX_DEBUG_ENTER_FUNCTION();
       
   658 
       
   659     // first de-init videocapture control
       
   660     deinit();
       
   661     reset();
       
   662 
       
   663     delete mVideoRecorder;
       
   664     mVideoRecorder = NULL;
       
   665 
       
   666     CX_DEBUG_EXIT_FUNCTION();
       
   667 }
       
   668 
       
   669 /*!
       
   670 * Returns current state of video capture control
       
   671 */
       
   672 CxeVideoCaptureControl::State CxeVideoCaptureControlSymbian::state() const
       
   673 {
       
   674     return static_cast<CxeVideoCaptureControl::State> (stateId());
       
   675 }
       
   676 
       
   677 /*!
       
   678 * Called when state is changed.
       
   679 */
       
   680 void CxeVideoCaptureControlSymbian::handleStateChanged(int newStateId, CxeError::Id error)
       
   681 {
       
   682     switch (newStateId) {
       
   683     case Ready:
       
   684         if (error == CxeError::None && !mDiskMonitor.isMonitoring()) {
       
   685             mDiskMonitor.start();
       
   686             connect(&mDiskMonitor, SIGNAL(diskSpaceChanged()), this, SLOT(handleDiskSpaceChanged()));
       
   687         }
       
   688         break;
       
   689     default:
       
   690         // Stop monitoring when video mode is released.
       
   691         // Same goes during recording, as video times come from recorder.
       
   692         if (mDiskMonitor.isMonitoring()) {
       
   693             mDiskMonitor.stop();
       
   694             disconnect(&mDiskMonitor, SIGNAL(diskSpaceChanged()), this, SLOT(handleDiskSpaceChanged()));
       
   695         }
       
   696         break;
       
   697     }
       
   698     emit stateChanged(static_cast<State> (newStateId), error);
       
   699 }
       
   700 
       
   701 /*!
       
   702 * Initialize states for videocapturecontrol
       
   703 */
       
   704 void CxeVideoCaptureControlSymbian::initializeStates()
       
   705 {
       
   706     // addState( id, name, allowed next states )
       
   707     addState(new CxeState(Idle, "Idle", Initialized));
       
   708     addState(new CxeState(Initialized, "Initialized", Preparing | Idle));
       
   709     addState(new CxeState(Preparing, "Preparing", Ready | Idle));
       
   710     addState(new CxeState(Ready, "Ready", Recording | PlayingStartSound | Preparing | Idle));
       
   711     addState(new CxeState(Recording, "Recording", Recording | Paused | Stopping | Idle | Ready));
       
   712     addState(new CxeState(Paused, "Paused", Recording | Stopping | PlayingStartSound | Idle));
       
   713     addState(new CxeState(Stopping, "Stopping", Initialized | Idle | Ready));
       
   714     addState(new CxeState(PlayingStartSound, "PlayingStartSound", Recording | Idle));
       
   715 
       
   716     setInitialState(Idle);
       
   717 }
       
   718 
       
   719 /*!
       
   720 * Updates remaining video recordng time counter to all the video qualities supported by ICM
       
   721 * this should be done whenever storage location setting changes and when values are
       
   722 * read from ICM for the first time
       
   723 */
       
   724 void CxeVideoCaptureControlSymbian::updateRemainingRecordingTimeCounter()
       
   725 {
       
   726     CX_DEBUG_ENTER_FUNCTION();
       
   727 
       
   728     for( int index = 0; index < mIcmSupportedVideoResolutions.count(); index++) {
       
   729         CxeVideoDetails &qualityDetails = mIcmSupportedVideoResolutions[index];
       
   730         qualityDetails.mRemainingTime = calculateRemainingTime(qualityDetails);
       
   731     }
       
   732 
       
   733     CX_DEBUG_EXIT_FUNCTION();
       
   734 }
       
   735 
       
   736 /*!
       
   737 * calculates remaining video recording time.
       
   738 */
       
   739 void CxeVideoCaptureControlSymbian::remainingTime(int &time)
       
   740 {
       
   741     CX_DEBUG_ENTER_FUNCTION();
       
   742 
       
   743     if (state() == CxeVideoCaptureControl::Recording ||
       
   744         state() == CxeVideoCaptureControl::Paused) {
       
   745         time = mVideoRecorder->availableRecordingTime();
       
   746         CX_DEBUG(("CxeVideoCaptureControlSymbian - time remaining: %d", time));
       
   747     } else {
       
   748         // Check if we need to recalculate the remaining time.
       
   749         if (mCurrentVideoDetails.mRemainingTime == CxeVideoDetails::UNKNOWN) {
       
   750             mCurrentVideoDetails.mRemainingTime = calculateRemainingTime(mCurrentVideoDetails);
       
   751         }
       
   752         time = mCurrentVideoDetails.mRemainingTime;
       
   753     }
       
   754 
       
   755     CX_DEBUG_EXIT_FUNCTION();
       
   756 }
       
   757 
       
   758 /*!
       
   759 * Get the remaining recording time
       
   760 * @param videoDetails Contains the current video resolution that is in use.
       
   761 * @return The remaining recording time
       
   762 */
       
   763 int CxeVideoCaptureControlSymbian::calculateRemainingTime(const CxeVideoDetails& videoDetails)
       
   764 {
       
   765     CX_DEBUG_ENTER_FUNCTION();
       
   766     qint64 availableSpace = mDiskMonitor.free() - KMinRequiredSpaceVideo;
       
   767     int time = mQualityPresets.recordingTimeAvailable(videoDetails, availableSpace);
       
   768     CX_DEBUG_EXIT_FUNCTION();
       
   769     return time;
       
   770 }
       
   771 
       
   772 /*!
       
   773 * Calculates elapsed recording time during video recording
       
   774 * @return Did fetching elapsed time succeed.
       
   775 */
       
   776 bool CxeVideoCaptureControlSymbian::elapsedTime(int &time)
       
   777 {
       
   778     CX_DEBUG_ENTER_FUNCTION();
       
   779 
       
   780     bool ok = false;
       
   781     if (state() == CxeVideoCaptureControl::Recording ||
       
   782         state() == CxeVideoCaptureControl::Paused) {
       
   783         try {
       
   784             time = mVideoRecorder->duration();
       
   785             CX_DEBUG(("CxeVideoCaptureControlSymbian - elapsed: %d", time));
       
   786             ok = true;
       
   787         } catch (const std::exception &e) {
       
   788             // Returning false.
       
   789         }
       
   790     }
       
   791 
       
   792     CX_DEBUG_EXIT_FUNCTION();
       
   793     return ok;
       
   794 }
       
   795 
       
   796 /*!
       
   797 * slot called when playing a sound has finished.
       
   798 */
       
   799 void CxeVideoCaptureControlSymbian::handleSoundPlayed()
       
   800 {
       
   801     CX_DEBUG_ENTER_FUNCTION();
       
   802 
       
   803     // start recording, if we were playing capture sound
       
   804     if (state() == CxeVideoCaptureControl::PlayingStartSound) {
       
   805         setState(CxeVideoCaptureControl::Recording);
       
   806         mVideoRecorder->record();
       
   807     }
       
   808 
       
   809     // in case of video capture stop sound playing, nothing needs to be done
       
   810     // meaning the state set elsewhere, and the video capture has been stopped already
       
   811 
       
   812     CX_DEBUG_EXIT_FUNCTION();
       
   813 }
       
   814 
       
   815 /*!
       
   816 * Handle new snapshot.
       
   817 * @param status Status code for getting the snapshot.
       
   818 * @param snapshot Snapshot pixmap. Empty if error code reported.
       
   819 */
       
   820 void CxeVideoCaptureControlSymbian::handleSnapshotReady(CxeError::Id status, const QImage &snapshot)
       
   821 {
       
   822     CX_DEBUG_ENTER_FUNCTION();
       
   823 
       
   824     if (mCameraDeviceControl.mode() == Cxe::VideoMode) {
       
   825         OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_HANDLESNAPSHOT_1, "msg: e_CX_HANDLE_SNAPSHOT 1");
       
   826 
       
   827         // Need to store snapshot for ui to be able to get it also later.
       
   828         mSnapshot = QPixmap::fromImage(snapshot);
       
   829         emit snapshotReady(status, snapshot, filename());
       
   830 
       
   831         OstTrace0(camerax_performance, CXEVIDEOCAPTURECONTROL_HANDLESNAPSHOT_2, "msg: e_CX_HANDLE_SNAPSHOT 0");
       
   832     }
       
   833 
       
   834     CX_DEBUG_EXIT_FUNCTION();
       
   835 }
       
   836 
       
   837 /*!
       
   838 * setting has changed, check if we are interested.
       
   839 */
       
   840 void CxeVideoCaptureControlSymbian::handleSettingValueChanged(const QString& settingId,
       
   841                                                               QVariant newValue)
       
   842 {
       
   843     CX_DEBUG_ENTER_FUNCTION();
       
   844     Q_UNUSED(newValue);
       
   845 
       
   846     if (mCameraDeviceControl.mode() == Cxe::VideoMode) {
       
   847         if (settingId == CxeSettingIds::VIDEO_QUALITY) {
       
   848             // re-prepare for video
       
   849             if (state() == Ready) {
       
   850                 // release resources
       
   851                 deinit();
       
   852                 // initialize video recording again
       
   853                 init();
       
   854             }
       
   855         } else if (settingId == CxeSettingIds::VIDEO_MUTE_SETTING) {
       
   856             // mute setting changed, apply the new setting and re-prepare.
       
   857             setState(Preparing);
       
   858             prepare();
       
   859         } else if (settingId == CxeSettingIds::FRAME_RATE) {
       
   860             // Frame rate setting changed. Need to re-prepare if we are prepared already.
       
   861             // Otherwise can wait for next init call.
       
   862             if (state() == Ready) {
       
   863                 setState(Preparing);
       
   864                 prepare();
       
   865             }
       
   866         } else {
       
   867             // Setting not relevant to video mode
       
   868         }
       
   869     }
       
   870 
       
   871     CX_DEBUG_EXIT_FUNCTION();
       
   872 }
       
   873 
       
   874 /*!
       
   875  * Scene mode changed. We need to know about it because frame rate
       
   876  * might have changed.
       
   877  */
       
   878 void CxeVideoCaptureControlSymbian::handleSceneChanged(const QVariant& scene)
       
   879 {
       
   880     Q_UNUSED(scene)
       
   881     CX_DEBUG_ENTER_FUNCTION();
       
   882 
       
   883     // make sure we are in video mode
       
   884     if (mCameraDeviceControl.mode() == Cxe::VideoMode) {
       
   885         // Frame rate setting might have changed so re-prepare.
       
   886         if (state() == Ready) {
       
   887             setState(Preparing);
       
   888             prepare();
       
   889         }
       
   890 
       
   891     }
       
   892     CX_DEBUG_EXIT_FUNCTION();
       
   893 }
       
   894 
       
   895 /*!
       
   896 * Disk space changed.
       
   897 * Emit remaining time changed signal, if space change affects it.
       
   898 */
       
   899 void CxeVideoCaptureControlSymbian::handleDiskSpaceChanged()
       
   900 {
       
   901     CX_DEBUG_ENTER_FUNCTION();
       
   902 
       
   903     // Ignore updates on preparing phase.
       
   904     if (state() == CxeVideoCaptureControl::Ready) {
       
   905 
       
   906         int time(calculateRemainingTime(mCurrentVideoDetails));
       
   907 
       
   908         if (time !=  mCurrentVideoDetails.mRemainingTime) {
       
   909             mCurrentVideoDetails.mRemainingTime = time;
       
   910             emit remainingTimeChanged();
       
   911         }
       
   912     }
       
   913 
       
   914     CX_DEBUG_EXIT_FUNCTION();
       
   915 }
       
   916 
       
   917 /*!
       
   918     Use ECam Use Case Hint Custom API to inform ECam of our intended use case
       
   919     before calling Reserve().
       
   920 */
       
   921 void CxeVideoCaptureControlSymbian::hintUseCase()
       
   922 {
       
   923     CX_DEBUG_ENTER_FUNCTION();
       
   924 
       
   925     // Make sure ECam knows we're doing video recording so it can prepare
       
   926     // for the correct use case.
       
   927     if (mCameraDeviceControl.mode() == Cxe::VideoMode) {
       
   928         MCameraUseCaseHint *useCaseHintApi = mCameraDevice.useCaseHintApi();
       
   929         if (useCaseHintApi) {
       
   930             MCameraUseCaseHint::TVideoCodec codec =
       
   931                     MCameraUseCaseHint::ECodecUnknown;
       
   932             MCameraUseCaseHint::TVideoProfile profile =
       
   933                     MCameraUseCaseHint::EProfileUnknown;
       
   934 
       
   935             updateVideoCaptureParameters();
       
   936             CxeSettingsMapperSymbian::Map2UseCaseHintVideoParameters(
       
   937                     mCurrentVideoDetails, codec, profile);
       
   938 
       
   939             TSize resolution(mCurrentVideoDetails.mWidth,
       
   940                              mCurrentVideoDetails.mHeight);
       
   941             TRAP_IGNORE(useCaseHintApi->HintDirectVideoCaptureL(codec, profile,
       
   942                                                                 resolution));
       
   943         }
       
   944     }
       
   945 
       
   946     CX_DEBUG_EXIT_FUNCTION();
       
   947 }
       
   948 
       
   949 /*!
       
   950 * Returns QList of all supported video quality details based on the camera index
       
   951 * (primary/secondary).
       
   952 */
       
   953 QList<CxeVideoDetails> CxeVideoCaptureControlSymbian::supportedVideoQualities()
       
   954 {
       
   955     // update the remaining time counters for each quality setting
       
   956     updateRemainingRecordingTimeCounter();
       
   957     return mIcmSupportedVideoResolutions;
       
   958 }
       
   959 
       
   960 /*!
       
   961 * Helper method to handle error during preparing phase.
       
   962 */
       
   963 void CxeVideoCaptureControlSymbian::handlePrepareFailed()
       
   964 {
       
   965     CX_DEBUG_ENTER_FUNCTION();
       
   966     CX_DEBUG(("[ERROR] Preparing video failed!"));
       
   967     // Cleanup
       
   968     deinit();
       
   969     // Inform client
       
   970     emit videoPrepareComplete(CxeError::InitializationFailed);
       
   971     CX_DEBUG_EXIT_FUNCTION();
       
   972 }
       
   973 
       
   974 /*!
       
   975 * Helper method to handle error from video composing.
       
   976 * @param error Symbian error code.
       
   977 */
       
   978 void CxeVideoCaptureControlSymbian::handleComposeFailed(int error)
       
   979 {
       
   980     CX_DEBUG_ENTER_FUNCTION();
       
   981     CX_DEBUG(("[ERROR] Composing video failed!"));
       
   982     // Inform client
       
   983     emit videoComposed(CxeErrorHandlingSymbian::map(error), filename());
       
   984     // Cleanup
       
   985     deinit();
       
   986     CX_DEBUG_EXIT_FUNCTION();
       
   987 }
       
   988 
       
   989 /*!
       
   990  * Helper method to emulate video stopping events.
       
   991  */
       
   992 void CxeVideoCaptureControlSymbian::emulateNormalStopping()
       
   993 {
       
   994     CX_DEBUG_ENTER_FUNCTION();
       
   995 
       
   996     setState(Stopping);
       
   997     MvruoEvent(TMMFEvent(KCamCControllerCCVideoRecordStopped, KErrNone));
       
   998     MvruoEvent(TMMFEvent(KCamCControllerCCVideoFileComposed, KErrNone));
       
   999 
       
  1000     CX_DEBUG_EXIT_FUNCTION();
       
  1001 }
       
  1002 // End of file