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 |
|