|
1 /* |
|
2 * Copyright (c) 2002-2008 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: Implementation for video recorder |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 #include "mmf/common/mmfbase.h" |
|
21 #include "CCMRRecorderBase.h" |
|
22 #include "CCMRVideoSettings.h" // default video settings |
|
23 #include "CCMRSupportedCodecs.h" |
|
24 #include "CCMRVideoHWParams.h" |
|
25 #include "CCMRVideoRecorder.h" |
|
26 #include "CCMRMediaRecorder.h" // for bitrate control mode |
|
27 #include "CCMRVideoThreadProxy.h" |
|
28 #include "CCMRFifo.h" |
|
29 #include "CCMRActiveOutput.h" |
|
30 #include "CCMRVideoCodecDataH263.h" |
|
31 #include "CCMRVideoCodecDataMPEG4.h" |
|
32 #include "CCMRVideoCodecDataH264AVC.h" |
|
33 #include <mmf/common/mmfvideo.h> |
|
34 |
|
35 /* |
|
36 #include "OstTraceDefinitions.h" |
|
37 #ifdef OST_TRACE_COMPILER_IN_USE |
|
38 #include "CCMRMDFVideoRecorderTraces.h" |
|
39 #endif |
|
40 */ |
|
41 |
|
42 // MACROS |
|
43 // Assertion macro wrapper for code cleanup |
|
44 #define VRASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CCMRMDFVIDEORECORDER"), EInternalAssertionFailure)) |
|
45 |
|
46 // Debug print macro |
|
47 #ifdef _DEBUG |
|
48 #include <e32svr.h> |
|
49 #define PRINT(x) RDebug::Print x; |
|
50 #else |
|
51 #define PRINT(x) |
|
52 #endif |
|
53 |
|
54 // ============================= LOCAL FUNCTIONS =============================== |
|
55 |
|
56 // ----------------------------------------------------------------------------- |
|
57 // convertFrameRateToInterval Converts framerate to frame time interval |
|
58 // (time between 2 consecutive frames). |
|
59 // Returns: TInt time between 2 consecutive frames |
|
60 // ----------------------------------------------------------------------------- |
|
61 // |
|
62 static TInt convertFrameRateToInterval(TReal32 aFrameRate) |
|
63 { |
|
64 return (TInt(1E6/aFrameRate + 0.5)); |
|
65 } |
|
66 |
|
67 |
|
68 // ----------------------------------------------------------------------------- |
|
69 // convertFrameRateToInterval Converts framerate to frame time interval |
|
70 // (time between 2 consecutive frames). |
|
71 // Returns: TInt time between 2 consecutive frames |
|
72 // ----------------------------------------------------------------------------- |
|
73 // |
|
74 static TInt TLinearOrderFuncVideoSizeRate(const TPictureRateAndSize& aPictureRateAndSize1, |
|
75 const TPictureRateAndSize& aPictureRateAndSize2 ) |
|
76 { |
|
77 if ( (aPictureRateAndSize1.iPictureSize.iWidth == aPictureRateAndSize2.iPictureSize.iWidth) && |
|
78 (aPictureRateAndSize1.iPictureSize.iHeight == aPictureRateAndSize2.iPictureSize.iHeight) && |
|
79 (aPictureRateAndSize1.iPictureRate == aPictureRateAndSize2.iPictureRate) ) |
|
80 { |
|
81 return 0; |
|
82 } |
|
83 |
|
84 if ( (aPictureRateAndSize1.iPictureSize.iWidth < aPictureRateAndSize2.iPictureSize.iWidth) || |
|
85 (aPictureRateAndSize1.iPictureSize.iHeight < aPictureRateAndSize2.iPictureSize.iHeight) || |
|
86 (aPictureRateAndSize1.iPictureRate < aPictureRateAndSize2.iPictureRate)) |
|
87 { |
|
88 return -1; |
|
89 } |
|
90 else |
|
91 { |
|
92 return 1; |
|
93 } |
|
94 } |
|
95 |
|
96 // ================= MEMBER FUNCTIONS ======================= |
|
97 |
|
98 // --------------------------------------------------------- |
|
99 // CCMRVideoRecorder::NewL |
|
100 // Two-phased constructor. |
|
101 // --------------------------------------------------------- |
|
102 // |
|
103 CCMRVideoRecorder* CCMRVideoRecorder::NewL(MAsyncEventHandler& aEventHandler, CCMRConfigManager* aConfig ) |
|
104 { |
|
105 PRINT((_L("CCMRVideoRecorder::NewL(), In: MDF"))) |
|
106 |
|
107 CCMRVideoRecorder* self = new (ELeave) CCMRVideoRecorder(aEventHandler); |
|
108 CleanupStack::PushL( self ); |
|
109 self->ConstructL(aConfig); |
|
110 CleanupStack::Pop(); |
|
111 |
|
112 PRINT((_L("CCMRVideoRecorder::NewL(), Out: MDF"))) |
|
113 return self; |
|
114 } |
|
115 |
|
116 |
|
117 // --------------------------------------------------------- |
|
118 // CCMRVideoRecorder::ConstructL() |
|
119 // Symbian 2nd phase constructor can leave. |
|
120 // --------------------------------------------------------- |
|
121 // |
|
122 void CCMRVideoRecorder::ConstructL(CCMRConfigManager* aConfig) |
|
123 { |
|
124 PRINT((_L("CCMRVideoRecorder::ConstructL(), In"))) |
|
125 |
|
126 SetState(EStateNone); |
|
127 |
|
128 iConfig = aConfig; |
|
129 iNumCameraBuffers = iConfig->PluginSettings().iCMRNumCameraBuffers; |
|
130 // Create input fifo |
|
131 iSourceFifo = CCMRFifo::NewL(iNumCameraBuffers); |
|
132 iCodingFifo = CCMRFifo::NewL(iNumCameraBuffers); |
|
133 |
|
134 iOutputSinkBuffer = new (ELeave) CCMRMediaBuffer; |
|
135 |
|
136 iSizeIndex = -1; |
|
137 iSizeIndex420 = -1; |
|
138 iSizeIndex422 = -1; |
|
139 iSizeIndexDCEncoder = -1; |
|
140 iRateIndex = -1; |
|
141 iRateIndex420 = -1; |
|
142 iRateIndex422 = -1; |
|
143 iRateIndexDCEncoder = -1; |
|
144 iDevVideoRec = NULL; |
|
145 iEncoderHWDeviceId = 0; |
|
146 iPreProcessorHWDeviceId = 0; |
|
147 iOutputVideoBuffer = NULL; |
|
148 iVideoBufferType = CCMRMediaBuffer::EVideoH263; |
|
149 iClockSource = NULL; |
|
150 iDecSpecInfoLength = 0; |
|
151 iPreferredEncoderUID = KNullUid; |
|
152 iPreferredEncapsulationSet = EFalse; |
|
153 iFrameSize.SetSize( KCMRFrameWidth, KCMRFrameHeight ); |
|
154 iSourceFrameRate = KCMRFrameRate; |
|
155 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
156 iEncodingFrameRate = KCMRFrameRate; |
|
157 iMaxFrameRate4GivenSize = KCMRFrameRate; |
|
158 iRequestedFrameRate = KCMRFrameRate; |
|
159 CCMRRecorderBase::SetTargetBitRateL( KCMRTargetBitRate ); |
|
160 |
|
161 iMinRandomAccessPeriodInSeconds = KCMRMinRandomAccessPeriod; |
|
162 |
|
163 iMimeType = KCMRMimeTypeH263BaselineProfile; //copy |
|
164 iMimeType += _L8( "; level=10" ); // append |
|
165 iVideoCodecData = new (ELeave) CCMRVideoCodecDataH263(10); // default is H.263 level 10 |
|
166 |
|
167 iBitRateMode = EBitRateConstant; |
|
168 |
|
169 iTimeWhenPaused = 0; |
|
170 iTotalPausedTime = 0; |
|
171 |
|
172 iErrorCode = KErrNone; |
|
173 |
|
174 iEncoderInputQueueLength = 0; |
|
175 |
|
176 iNumberOfCapturedFrames = 0; |
|
177 iNumberOfEncodedFrames = 0; |
|
178 |
|
179 iMutexObj.CreateLocal(); |
|
180 iMutexCreated = ETrue; |
|
181 iBufferReturnAO = CCMRReturnAO::NewL(this); |
|
182 |
|
183 iFatalError = EFalse; |
|
184 iInputEnd = EFalse; |
|
185 iStreamEnd = EFalse; |
|
186 |
|
187 // Direct capture |
|
188 iDirectCapture = EFalse; |
|
189 iCameraHandle = 0; |
|
190 iSkipBuffers = EFalse; |
|
191 iDriftFrameSkipCount = 0; |
|
192 iAddedFrameDurationCount = 0; |
|
193 iPreviousCameraFrameIndex = 0; |
|
194 |
|
195 #ifdef _DEBUG |
|
196 iLastCapture = 0; |
|
197 iCumulativeEncodingTime = iCumulativeCaptureTime = 0; |
|
198 iAverageEncodingTime = iAverageCaptureTime = 0; |
|
199 #endif |
|
200 iDevVideoRec = CMMFDevVideoRecord::NewL( *this ); |
|
201 iAvailableVideoEncoders.Reset(); |
|
202 iAvailableVideoFrameSizesRates.Reset(); |
|
203 |
|
204 PRINT((_L("CCMRVideoRecorder::ConstructL() looking for defaul video codec encoder(s)"))); |
|
205 iDevVideoRec->FindEncodersL(iMimeType, 0 /* aPreProc */, iAvailableVideoEncoders, EFalse ); |
|
206 PRINT((_L("CCMRVideoRecorder::ConstructL() search found %d encoder(s)"), iAvailableVideoEncoders.Count() )); |
|
207 |
|
208 if ( iConfig ) |
|
209 { |
|
210 iConfig->SetVideoCodec(iMimeType); |
|
211 iConfig->SetVideoPixelAspectRatio(KCMRAspectRatioNum, KCMRAspectRatioDenom); |
|
212 |
|
213 // fill out defaults for Rate Control from ICM. |
|
214 iRateControlOptions.iPictureQuality = iConfig->PluginSettings().iCMRPictureQuality; |
|
215 iRateControlOptions.iLatencyQualityTradeoff = iConfig->PluginSettings().iCMRLatencyQualityTradeoff; // latency vs. quality |
|
216 iRateControlOptions.iQualityTemporalTradeoff = iConfig->PluginSettings().iCMRQualityTemporalTradeoff; // spatial vs. temporal quality |
|
217 } |
|
218 UpdateSupportedVideoFrameSizesRates(); |
|
219 PRINT((_L("CCMRVideoRecorder::ConstructL(), Out"))) |
|
220 } |
|
221 |
|
222 |
|
223 // --------------------------------------------------------- |
|
224 // CCMRVideoRecorder::~CCMRVideoRecorder() |
|
225 // Destructor |
|
226 // --------------------------------------------------------- |
|
227 // |
|
228 CCMRVideoRecorder::~CCMRVideoRecorder() |
|
229 { |
|
230 PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder(), In"))); |
|
231 // This is the counterpart to NewL & OpenL, e.g. Close & Delete |
|
232 // free all memory allocated and uninitalize & delete objects created, e.g. DevVideoRecord |
|
233 |
|
234 #if defined VIDEO_FILE_OUTPUT || defined VIDEO_BS_FILE_OUTPUT |
|
235 iOutputFile.Close(); |
|
236 iFs.Close(); |
|
237 #endif |
|
238 |
|
239 // to make PC Lint happy |
|
240 iOutputVideoBuffer = NULL; |
|
241 iOutput = NULL; |
|
242 iClockSource = NULL; |
|
243 |
|
244 // delete DevVideoRecord instance |
|
245 delete iDevVideoRec; |
|
246 PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() devvideorec deleted"))); |
|
247 |
|
248 iAvailableVideoFrameSizesRates.Close(); |
|
249 iAvailableVideoEncoders.Close(); |
|
250 |
|
251 delete iOutputSinkBuffer; |
|
252 iOutputSinkBuffer = NULL; |
|
253 |
|
254 delete iVideoCodecData; |
|
255 iVideoCodecData = NULL; |
|
256 |
|
257 // empty the source fifo, just in case once more; this should be done a) by encoder and b) by MdvroStreamEnd() |
|
258 MFrameBuffer* cbuffer; |
|
259 if ( iSourceFifo ) |
|
260 { |
|
261 while ( !iSourceFifo->IsEmpty() ) |
|
262 { |
|
263 cbuffer = reinterpret_cast<MFrameBuffer*>(iSourceFifo->Get()); |
|
264 // Release camera API buffer |
|
265 cbuffer->Release(); |
|
266 } |
|
267 delete iSourceFifo; |
|
268 iSourceFifo = NULL; |
|
269 } |
|
270 TVideoPicture* picture; |
|
271 if ( iCodingFifo ) |
|
272 { |
|
273 // delete the empty devvr picture-holders stored in the fifo |
|
274 while ( !iCodingFifo->IsEmpty() ) |
|
275 { |
|
276 picture = reinterpret_cast<TVideoPicture*>(iCodingFifo->Get()); |
|
277 PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() deleting %x"),picture)); |
|
278 delete picture; |
|
279 } |
|
280 delete iCodingFifo; |
|
281 iCodingFifo = NULL; |
|
282 } |
|
283 PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() fifos deleted"))); |
|
284 |
|
285 if ( iDecSpecInfo ) |
|
286 { |
|
287 // We still have MPEG-4 decoder configuration info stored |
|
288 delete iDecSpecInfo; |
|
289 iDecSpecInfo = NULL; |
|
290 } |
|
291 |
|
292 // delete camera |
|
293 delete iSource; |
|
294 iSource = NULL; |
|
295 PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() camera deleted"))); |
|
296 |
|
297 if ( iBufferReturnAO ) |
|
298 { |
|
299 iBufferReturnAO->Cancel(); |
|
300 delete iBufferReturnAO; |
|
301 } |
|
302 |
|
303 if ( iThreadHandleOpened ) |
|
304 { |
|
305 iOutputThreadHandle.Close(); |
|
306 iThreadHandleOpened = EFalse; |
|
307 } |
|
308 |
|
309 if ( iMutexCreated ) |
|
310 { |
|
311 iMutexObj.Close(); |
|
312 } |
|
313 |
|
314 SetState(EStateNone); |
|
315 |
|
316 PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder(), Out"))); |
|
317 } |
|
318 |
|
319 |
|
320 // --------------------------------------------------------- |
|
321 // CCMRVideoRecorder::SetOutputL |
|
322 // Sets output active object |
|
323 // (other items were commented in a header). |
|
324 // --------------------------------------------------------- |
|
325 // |
|
326 void CCMRVideoRecorder::SetOutputL(CCMRActiveOutput* aOutput) |
|
327 { |
|
328 iOutput = aOutput; |
|
329 iOutput->RegisterSourceL( this ); |
|
330 if ( iSource && iThreadHandleOpened ) |
|
331 { |
|
332 SetState( EStateOpen ); |
|
333 } |
|
334 } |
|
335 |
|
336 // --------------------------------------------------------- |
|
337 // CCMRVideoRecorder::SetClockSourceL |
|
338 // Set clock source |
|
339 // (other items were commented in a header). |
|
340 // --------------------------------------------------------- |
|
341 // |
|
342 void CCMRVideoRecorder::SetClockSource(MMMFClockSource* aClockSource) |
|
343 { |
|
344 iClockSource = aClockSource; |
|
345 } |
|
346 |
|
347 // --------------------------------------------------------- |
|
348 // CCMRVideoRecorder::SetOutputThreadIdL |
|
349 // Sets id of the output thread |
|
350 // (other items were commented in a header). |
|
351 // --------------------------------------------------------- |
|
352 // |
|
353 void CCMRVideoRecorder::SetOutputThreadIdL(TUint aThreadId) |
|
354 { |
|
355 User::LeaveIfError( iOutputThreadHandle.Open(aThreadId) ); |
|
356 |
|
357 iThreadHandleOpened = ETrue; |
|
358 if ( iOutput && iSource ) |
|
359 { |
|
360 SetState( EStateOpen ); |
|
361 } |
|
362 } |
|
363 |
|
364 |
|
365 // --------------------------------------------------------- |
|
366 // CCMRVideoRecorder::SetCameraHandleL |
|
367 // Sets camera handle and creates camera instance |
|
368 // (other items were commented in a header). |
|
369 // --------------------------------------------------------- |
|
370 // |
|
371 void CCMRVideoRecorder::SetCameraHandleL(TInt aCameraHandle) |
|
372 { |
|
373 PRINT((_L("CCMRVideoRecorder::SetCameraHandleL(), In"))) |
|
374 |
|
375 // Create video source |
|
376 #ifdef VIDEO_FILE_INPUT |
|
377 iSource = CCMRVideoFileSource::NewL(this); |
|
378 #else |
|
379 iSource = CCMRVideoCameraSource::NewL(this, aCameraHandle); |
|
380 #endif |
|
381 |
|
382 // Store a camera handle for future use |
|
383 iCameraHandle = aCameraHandle; |
|
384 |
|
385 // get camera info |
|
386 iSource->CameraInfo(iCameraInfo); |
|
387 |
|
388 #if defined VIDEO_FILE_OUTPUT || defined VIDEO_BS_FILE_OUTPUT |
|
389 User::LeaveIfError(iFs.Connect()); |
|
390 User::LeaveIfError(iOutputFile.Replace(iFs, _L("videorec_out.bin"), EFileWrite | EFileShareExclusive)); |
|
391 #endif |
|
392 |
|
393 if ( iOutput && iThreadHandleOpened ) |
|
394 { |
|
395 SetState( EStateOpen ); |
|
396 } |
|
397 |
|
398 PRINT((_L("CCMRVideoRecorder::SetCameraHandleL(), Out"))) |
|
399 } |
|
400 |
|
401 // --------------------------------------------------------- |
|
402 // CCMRVideoRecorder::SetupEncoderL |
|
403 // Private helper method to select & setup the encoder |
|
404 // plugin devvr must use |
|
405 // (other items were commented in a header). |
|
406 // --------------------------------------------------------- |
|
407 // |
|
408 void CCMRVideoRecorder::SetupEncoderL() |
|
409 { |
|
410 #ifdef _DEBUG |
|
411 TBuf<256> mime; |
|
412 mime.Copy(iMimeType); |
|
413 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() in, video mime-type: %S "), &mime )); |
|
414 #endif |
|
415 |
|
416 if ( iPreferredEncoderUID != KNullUid ) |
|
417 {// We have preferred encoder UID from client - override encoder search and use it instead. |
|
418 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using API user encoder: %d "), iPreferredEncoderUID.iUid)); |
|
419 iAvailableVideoEncoders.Reset(); |
|
420 iAvailableVideoEncoders.AppendL(iPreferredEncoderUID); |
|
421 } |
|
422 else if ( iConfig && |
|
423 ( iConfig->IsICMConfigDataAvailable() ) && |
|
424 ( iConfig->VideoQualitySettings().iVideoEncoderUID != KNullUid ) ) |
|
425 {// Video quality set has set UID value - override encoder search and use it instead. |
|
426 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using ICM config encoder: %d "), iPreferredEncoderUID.iUid)); |
|
427 iAvailableVideoEncoders.Reset(); |
|
428 iAvailableVideoEncoders.AppendL(iPreferredEncoderUID); |
|
429 } |
|
430 |
|
431 // uncompressed format structures for YUV420 planar |
|
432 TBool cameraSupports420 = ETrue; |
|
433 |
|
434 if ( (iSizeIndex420 < 0) || (iRateIndex420 < 0) ) |
|
435 { |
|
436 cameraSupports420 = EFalse; |
|
437 } |
|
438 else |
|
439 { |
|
440 cameraSupports420 = ETrue; |
|
441 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() camera supports YUV420 planar") )); |
|
442 } |
|
443 |
|
444 // uncompressed format structures for YUV422 |
|
445 TBool cameraSupports422 = ETrue; |
|
446 if ( (iSizeIndex422 < 0) || (iRateIndex422 < 0) ) |
|
447 { |
|
448 cameraSupports422 = EFalse; |
|
449 } |
|
450 else |
|
451 { |
|
452 cameraSupports422 = ETrue; |
|
453 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() camera supports YUV422 interleaved") )); |
|
454 } |
|
455 |
|
456 // Output format |
|
457 CCompressedVideoFormat *comprFormat = CCompressedVideoFormat::NewL( iMimeType ); |
|
458 CleanupStack::PushL( comprFormat ); |
|
459 |
|
460 // index for encoder candidate. Have to go through the list to find an accerated encoder |
|
461 TInt encoderIndex = -1; |
|
462 TUncompressedVideoFormat encoderUncompFormat; |
|
463 |
|
464 // encoder info for retrieving capabilities |
|
465 CVideoEncoderInfo* encoderInfo = NULL; |
|
466 |
|
467 // this is needed if init of HW accelerated codec failed and we retry => forces to select ARM codec |
|
468 TBool alreadyFailedWithHWAccelerated = iVideoCodecHWAccelerated; |
|
469 iVideoCodecHWAccelerated = EFalse; |
|
470 |
|
471 TInt infoError = KErrNone; |
|
472 TBool encoderSupports422 = EFalse; |
|
473 TBool encoderSupports420 = EFalse; |
|
474 |
|
475 TYuvCoefficients preproInputYuvCoefficient; |
|
476 TYuvCoefficients preproOutputYuvCoefficient; |
|
477 TYuvCoefficients encoderInputYuvCoefficient; |
|
478 TUint aspectRatioNum = 0; |
|
479 TUint aspectRatioDenom = 0; |
|
480 TVideoDataUnitEncapsulation outputFormatEncapsulation = EDuElementaryStream; |
|
481 |
|
482 if( KCMRMimeTypeH263() == iMimeType.Left( KCMRMimeTypeH263().Length() )) |
|
483 {// H.263 |
|
484 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - setting H.263 YUVs") )); |
|
485 preproInputYuvCoefficient = EYuvBt601Range1; |
|
486 preproOutputYuvCoefficient = EYuvBt601Range0; |
|
487 encoderInputYuvCoefficient = EYuvBt601Range0; |
|
488 iVideoBufferType = CCMRMediaBuffer::EVideoH263; |
|
489 // pixel aspect ratios |
|
490 if ( iConfig && iConfig->IsICMConfigDataAvailable() ) |
|
491 { |
|
492 aspectRatioNum = iConfig->VideoQualitySettings().iVideoPixelAspectRatioNum; |
|
493 aspectRatioDenom = iConfig->VideoQualitySettings().iVideoPixelAspectRatioDenom; |
|
494 } |
|
495 else |
|
496 { |
|
497 aspectRatioNum = KCMRAspectRatioNum; |
|
498 aspectRatioDenom = KCMRAspectRatioDenom; |
|
499 } |
|
500 } |
|
501 else if ( KCMRMimeTypeMPEG4V() == iMimeType.Left( KCMRMimeTypeMPEG4V().Length() )) |
|
502 {// MPEG-4 |
|
503 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - setting MPEG4 YUVs") )); |
|
504 preproInputYuvCoefficient = EYuvBt709Range1; |
|
505 preproOutputYuvCoefficient = EYuvBt709Range1; |
|
506 encoderInputYuvCoefficient = EYuvBt709Range1; |
|
507 // pixel aspect ratios |
|
508 if ( iConfig && iConfig->IsICMConfigDataAvailable() ) |
|
509 { |
|
510 aspectRatioNum = iConfig->VideoQualitySettings().iVideoPixelAspectRatioNum; |
|
511 aspectRatioDenom = iConfig->VideoQualitySettings().iVideoPixelAspectRatioDenom; |
|
512 } |
|
513 else |
|
514 { |
|
515 aspectRatioNum = KCMRMPEG4AspectRatioNum; |
|
516 aspectRatioDenom = KCMRMPEG4AspectRatioDenom; |
|
517 } |
|
518 iVideoBufferType = CCMRMediaBuffer::EVideoMPEG4; |
|
519 } |
|
520 else |
|
521 {// H.264 AVC |
|
522 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - setting H.264 AVC YUVs") )); |
|
523 preproInputYuvCoefficient = EYuvBt709Range1; |
|
524 preproOutputYuvCoefficient = EYuvBt709Range1; |
|
525 encoderInputYuvCoefficient = EYuvBt709Range1; |
|
526 // pixel aspect ratios 1:1 |
|
527 if ( iConfig && iConfig->IsICMConfigDataAvailable() ) |
|
528 { |
|
529 aspectRatioNum = iConfig->VideoQualitySettings().iVideoPixelAspectRatioNum; |
|
530 aspectRatioDenom = iConfig->VideoQualitySettings().iVideoPixelAspectRatioDenom; |
|
531 } |
|
532 else |
|
533 { |
|
534 aspectRatioNum = KCMRMPEG4AspectRatioNum; |
|
535 aspectRatioDenom = KCMRMPEG4AspectRatioDenom; |
|
536 } |
|
537 // output format encapsulation |
|
538 iVideoBufferType = CCMRMediaBuffer::EVideoH264NAL; |
|
539 outputFormatEncapsulation = EDuGenericPayload; |
|
540 } |
|
541 |
|
542 TBool directCaptureEncoder = EFalse; |
|
543 TInt supportedEncoderInputsCount = 0; |
|
544 // find an encoder with matching capabilities |
|
545 for ( TInt i = 0 ; i < iAvailableVideoEncoders.Count(); i++ ) |
|
546 { |
|
547 encoderInfo = NULL; |
|
548 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - getting info from a plugin index[%d] with Uid 0x%x"), i, iAvailableVideoEncoders[i].iUid )); |
|
549 TRAPD(error, (encoderInfo = ReadEncoderInfoL(iAvailableVideoEncoders[i])) ); |
|
550 |
|
551 if ( encoderInfo == NULL ) |
|
552 { |
|
553 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - getting info from a plugin failed, skipping") )); |
|
554 infoError = error; |
|
555 } |
|
556 else |
|
557 { |
|
558 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - got an info from a plugin, checking...") )); |
|
559 |
|
560 // item was popped in CheckEncoderInfoL, push it back to stack |
|
561 CleanupStack::PushL( encoderInfo ); |
|
562 |
|
563 // check if compressed video format matches |
|
564 if ( encoderInfo->SupportsOutputFormat(*comprFormat) ) // max picture size & bit-rate was checked in the level of comprFormat |
|
565 { |
|
566 // check input format of encoder. |
|
567 // a candidate encoder supporting the required compressed format was found |
|
568 encoderSupports422 = EFalse; |
|
569 encoderSupports420 = EFalse; |
|
570 |
|
571 RArray<TUncompressedVideoFormat> supportedEncoderInputs = encoderInfo->SupportedInputFormats(); |
|
572 supportedEncoderInputsCount = supportedEncoderInputs.Count(); |
|
573 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports %d input format(s), checking for support"), i, supportedEncoderInputs.Count() )); |
|
574 |
|
575 // Go through supported input format and look for match to important parameters. |
|
576 for(TInt j = 0; j < supportedEncoderInputsCount; j++ ) |
|
577 { |
|
578 if ( !encoderSupports422 && |
|
579 cameraSupports422 && |
|
580 supportedEncoderInputs[j].iDataFormat == EYuvRawData && |
|
581 supportedEncoderInputs[j].iYuvFormat.iCoefficients == encoderInputYuvCoefficient && |
|
582 ( supportedEncoderInputs[j].iYuvFormat.iDataLayout == EYuvDataInterleavedLE || |
|
583 supportedEncoderInputs[j].iYuvFormat.iDataLayout == EYuvDataInterleavedBE ) && |
|
584 supportedEncoderInputs[j].iYuvFormat.iYuv2RgbMatrix == NULL && |
|
585 supportedEncoderInputs[j].iYuvFormat.iRgb2YuvMatrix == NULL && |
|
586 supportedEncoderInputs[j].iYuvFormat.iAspectRatioNum == aspectRatioNum && |
|
587 supportedEncoderInputs[j].iYuvFormat.iAspectRatioDenom == aspectRatioDenom && |
|
588 ( supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv422Chroma1 || |
|
589 supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv422Chroma2 ) ) |
|
590 { |
|
591 // YUV 422 input format can be used with this encoder |
|
592 encoderSupports422 = ETrue; |
|
593 encoderUncompFormat = supportedEncoderInputs[j]; |
|
594 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports YUV422 interleaved"), i )); |
|
595 break; |
|
596 } |
|
597 if ( !encoderSupports420 && |
|
598 !encoderSupports422 && |
|
599 cameraSupports420 && |
|
600 supportedEncoderInputs[j].iDataFormat == EYuvRawData && |
|
601 supportedEncoderInputs[j].iYuvFormat.iCoefficients == encoderInputYuvCoefficient && |
|
602 supportedEncoderInputs[j].iYuvFormat.iDataLayout == EYuvDataPlanar && |
|
603 supportedEncoderInputs[j].iYuvFormat.iYuv2RgbMatrix == NULL && |
|
604 supportedEncoderInputs[j].iYuvFormat.iRgb2YuvMatrix == NULL && |
|
605 supportedEncoderInputs[j].iYuvFormat.iAspectRatioNum == aspectRatioNum && |
|
606 supportedEncoderInputs[j].iYuvFormat.iAspectRatioDenom == aspectRatioDenom && |
|
607 ( supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv420Chroma1 || |
|
608 supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv420Chroma2 ) ) |
|
609 { |
|
610 // YUV 420 planar input format can be used with this encoder |
|
611 encoderSupports420 = ETrue; |
|
612 encoderUncompFormat = supportedEncoderInputs[j]; |
|
613 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports YUV420 planar"), i )); |
|
614 if( !cameraSupports422 ) |
|
615 { |
|
616 break; |
|
617 } |
|
618 } |
|
619 } |
|
620 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports: 420[%d], 422[%d]"), i, encoderSupports420, encoderSupports422 )); |
|
621 |
|
622 // Check directCapture support for current codec |
|
623 directCaptureEncoder = encoderInfo->SupportsDirectCapture(); |
|
624 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports DirectCapture:[%d]."), i, directCaptureEncoder)); |
|
625 |
|
626 // determine H.264 AVC encapsulation |
|
627 if ( (iVideoBufferType == CCMRMediaBuffer::EVideoH264NAL) || |
|
628 (iVideoBufferType == CCMRMediaBuffer::EVideoH264Bytestream) ) |
|
629 { |
|
630 if (( iPreferredEncapsulationSet ) && |
|
631 ( encoderInfo->SupportedDataUnitEncapsulations() & iPreferredEncapsulation )) |
|
632 { |
|
633 outputFormatEncapsulation = iPreferredEncapsulation; |
|
634 } |
|
635 else |
|
636 { |
|
637 if (encoderInfo->SupportedDataUnitEncapsulations() & EDuGenericPayload) |
|
638 { |
|
639 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() H.264 Encoder at index[%d] set to EDuGenericPayload encapsulation."), i)); |
|
640 outputFormatEncapsulation = EDuGenericPayload; |
|
641 } |
|
642 else |
|
643 { |
|
644 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() H.264 Encoder at index[%d] set to EDuElementaryStream encapsulation."), i)); |
|
645 outputFormatEncapsulation = EDuElementaryStream; |
|
646 } |
|
647 } |
|
648 |
|
649 if ( outputFormatEncapsulation == EDuGenericPayload ) |
|
650 { |
|
651 iVideoBufferType = CCMRMediaBuffer::EVideoH264NAL; |
|
652 } |
|
653 else |
|
654 { |
|
655 iVideoBufferType = CCMRMediaBuffer::EVideoH264Bytestream; |
|
656 } |
|
657 } |
|
658 |
|
659 if (directCaptureEncoder && (supportedEncoderInputsCount != 0)) |
|
660 { |
|
661 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Warning - Encoder at index[%d] publish input formats even though it supports directcapture - ERROR!."), i)); |
|
662 } |
|
663 |
|
664 if ( encoderSupports422 || encoderSupports420 || (directCaptureEncoder && (supportedEncoderInputsCount == 0)) ) |
|
665 { |
|
666 // encoder's input format matches with camera's output |
|
667 if ( encoderInfo->Accelerated() && (alreadyFailedWithHWAccelerated == EFalse) ) |
|
668 // assume there is only 1 HW accelerated codec, and if it was selected previously we come here only if the init failed |
|
669 // => must use non-hw-accelerated codec |
|
670 { |
|
671 // no need to search for more, accelerated encoder is preferred |
|
672 encoderIndex = i; |
|
673 iVideoCodecHWAccelerated = ETrue; |
|
674 iDirectCapture = directCaptureEncoder; |
|
675 // HW accelerated is preferred regardless of the input format, but if both formats are supported, then 422 is preferred |
|
676 // need to set the camera variables accordingly |
|
677 if ( !(directCaptureEncoder && (supportedEncoderInputsCount == 0)) ) |
|
678 { |
|
679 if ( encoderSupports422 ) |
|
680 { |
|
681 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV422 interleaved selected as input format") )); |
|
682 iSizeIndex = iSizeIndex422; |
|
683 iRateIndex = iRateIndex422; |
|
684 iVideoFormat = CCamera::EFormatYUV422; |
|
685 } |
|
686 else if (encoderSupports420) |
|
687 { |
|
688 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV420 planar selected as input format") )); |
|
689 iSizeIndex = iSizeIndex420; |
|
690 iRateIndex = iRateIndex420; |
|
691 iVideoFormat = CCamera::EFormatYUV420Planar; |
|
692 } |
|
693 } |
|
694 // check max framerate for given picture size |
|
695 RArray<TPictureRateAndSize> rateAndSize = encoderInfo->MaxPictureRates(); |
|
696 TUint rates = rateAndSize.Count(); |
|
697 for ( TUint j = 0; j < rates; j++ ) |
|
698 { |
|
699 if ( rateAndSize[j].iPictureSize == iFrameSize ) |
|
700 { |
|
701 iMaxFrameRate4GivenSize = rateAndSize[j].iPictureRate; |
|
702 break; |
|
703 } |
|
704 } |
|
705 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - there is a suitable HW accelerated plugin, don't check other plugins") )); |
|
706 CleanupStack::PopAndDestroy( encoderInfo ); |
|
707 break; |
|
708 } |
|
709 else if ( encoderIndex < 0 ) |
|
710 { |
|
711 // accept also non-accelerated if no other is available |
|
712 encoderIndex = i; |
|
713 // encoder is selected regardless of the input format, but if both formats are supported, then 422 is preferred |
|
714 // need to set the camera variables accordingly |
|
715 if ( !(directCaptureEncoder && (supportedEncoderInputsCount == 0)) ) |
|
716 { |
|
717 if ( encoderSupports422 ) |
|
718 { |
|
719 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV422 interleaved selected as input format") )); |
|
720 iSizeIndex = iSizeIndex422; |
|
721 iRateIndex = iRateIndex422; |
|
722 iVideoFormat = CCamera::EFormatYUV422; |
|
723 } |
|
724 else if (encoderSupports420) |
|
725 { |
|
726 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV420 planar selected as input format") )); |
|
727 iSizeIndex = iSizeIndex420; |
|
728 iRateIndex = iRateIndex420; |
|
729 iVideoFormat = CCamera::EFormatYUV420Planar; |
|
730 } |
|
731 } |
|
732 |
|
733 // check max framerate for given picture size |
|
734 RArray<TPictureRateAndSize> rateAndSize = encoderInfo->MaxPictureRates(); |
|
735 TUint rates = rateAndSize.Count(); |
|
736 |
|
737 for ( TUint j = 0; j < rates; j++ ) |
|
738 { |
|
739 if ( rateAndSize[j].iPictureSize == iFrameSize ) |
|
740 { |
|
741 iMaxFrameRate4GivenSize = rateAndSize[j].iPictureRate; |
|
742 break; |
|
743 } |
|
744 } |
|
745 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - there is a suitable SW plugin.") )); |
|
746 } |
|
747 else |
|
748 { |
|
749 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - there is already similar encoder - preferring first.") )); |
|
750 // this kind of encoder already found |
|
751 } |
|
752 |
|
753 } |
|
754 else |
|
755 { |
|
756 // skip this encoder, done in the following lines |
|
757 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() encoder doesn't support YUV420/YUV422 input format or isn't directcapture encoder") )); |
|
758 } |
|
759 } |
|
760 else |
|
761 { |
|
762 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() encoder at index[%d] doesn't support given compressed output format"), i )); |
|
763 } |
|
764 CleanupStack::PopAndDestroy( encoderInfo ); |
|
765 } |
|
766 } |
|
767 |
|
768 TUncompressedVideoFormat preproInputFormat = encoderUncompFormat; |
|
769 TUncompressedVideoFormat preproOutputFormat = encoderUncompFormat; |
|
770 preproInputFormat.iYuvFormat.iCoefficients = preproInputYuvCoefficient; |
|
771 preproOutputFormat.iYuvFormat.iCoefficients = preproOutputYuvCoefficient; |
|
772 |
|
773 if ( encoderIndex >= 0 ) |
|
774 { |
|
775 if ( iVideoCodecHWAccelerated ) |
|
776 { |
|
777 iNumCameraBuffers = iConfig->PluginSettings().iCMRNumCameraBuffers; |
|
778 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - found a suitable HW accelerated video encoder"))); |
|
779 } |
|
780 else |
|
781 { |
|
782 iNumCameraBuffers = iConfig->PluginSettings().iCMRNumCameraBuffersARM; |
|
783 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - found a suitable ARM video encoder"))); |
|
784 } |
|
785 |
|
786 // if encoder doesn´t support directcapture try to find preprocessor that does. |
|
787 if ( !iDirectCapture && iVideoCodecHWAccelerated ) |
|
788 { |
|
789 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Searching preprocessor."))); |
|
790 RArray<TUid> preprocessors; |
|
791 CleanupClosePushL( preprocessors ); |
|
792 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Search starting"))); |
|
793 |
|
794 TInt preproSearchErr = KErrNone; |
|
795 TRAP(preproSearchErr, iDevVideoRec->FindPreProcessorsL(EPpYuvToYuv, preprocessors)); |
|
796 if (preproSearchErr == KErrNone) |
|
797 { |
|
798 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Search found %d preprocessor(s)"), preprocessors.Count() )); |
|
799 CPreProcessorInfo* preprocessorInfo = NULL; |
|
800 // find a preprocessor with matching capabilities to encoder |
|
801 for ( TInt k = 0; k < preprocessors.Count(); k++ ) |
|
802 { |
|
803 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Checking preprocessor at index[%d] with Uid 0x%x"), k, preprocessors[k].iUid )); |
|
804 preprocessorInfo = iDevVideoRec->PreProcessorInfoLC(preprocessors[k]); |
|
805 |
|
806 if ( preprocessorInfo->SupportsInputFormat(preproInputFormat) && |
|
807 preprocessorInfo->SupportsOutputFormat(preproOutputFormat) && |
|
808 preprocessorInfo->SupportsDirectCapture() ) |
|
809 { |
|
810 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() preprocessor[%d] is suitable, setting it as preprocessor"), k )); |
|
811 iDirectCapture = ETrue; |
|
812 iPreProcessorHWDeviceId = iDevVideoRec->SelectPreProcessorL(preprocessors[k]); |
|
813 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() preprocessor selected"))); |
|
814 CleanupStack::PopAndDestroy(preprocessorInfo); |
|
815 break; |
|
816 } |
|
817 CleanupStack::PopAndDestroy(preprocessorInfo); |
|
818 } |
|
819 } |
|
820 else if (preproSearchErr == KErrNotFound) |
|
821 { |
|
822 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() didn't find any preprocessors"))); |
|
823 } |
|
824 else |
|
825 { |
|
826 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() preprocessors search error: %d"), preproSearchErr)); |
|
827 CleanupStack::PopAndDestroy(); //preprocessors |
|
828 User::Leave(preproSearchErr); |
|
829 } |
|
830 CleanupStack::PopAndDestroy(); //preprocessors |
|
831 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Searching preprocessor done."))); |
|
832 } |
|
833 } |
|
834 else |
|
835 { |
|
836 if ( infoError != KErrNone ) |
|
837 { |
|
838 // there is an encoder but it can't be used |
|
839 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() there is an encoder but it can't be used - info error=%d"), infoError )); |
|
840 User::Leave( infoError ); |
|
841 } |
|
842 else |
|
843 { |
|
844 // No suitable encoder found. This should not be possible if the codec was properly set beforehand |
|
845 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() No suitable encoder found."))); |
|
846 User::Leave( KErrNotSupported ); |
|
847 } |
|
848 } |
|
849 |
|
850 iEncoderHWDeviceId = iDevVideoRec->SelectEncoderL(iAvailableVideoEncoders[encoderIndex]); |
|
851 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() encoder selected"))); |
|
852 |
|
853 // Set input format only for non-directcapture encoders |
|
854 if ( (directCaptureEncoder && (supportedEncoderInputsCount == 0)) ) |
|
855 { |
|
856 // Direct capture encoders should ignore |
|
857 TUncompressedVideoFormat ignoredFormat; |
|
858 iDevVideoRec->SetInputFormatL(iEncoderHWDeviceId, ignoredFormat, iFrameSize); |
|
859 } |
|
860 else |
|
861 { |
|
862 iDevVideoRec->SetInputFormatL(iEncoderHWDeviceId, encoderUncompFormat, iFrameSize); |
|
863 } |
|
864 |
|
865 if ( iPreProcessorHWDeviceId ) |
|
866 { |
|
867 iDevVideoRec->SetInputFormatL(iPreProcessorHWDeviceId, preproInputFormat, iFrameSize); |
|
868 } |
|
869 |
|
870 // Buffer options |
|
871 TEncoderBufferOptions bufferOptions; |
|
872 bufferOptions.iHrdVbvParams.Set(NULL, 0); |
|
873 bufferOptions.iHrdVbvSpec = EHrdVbvNone; |
|
874 bufferOptions.iMaxPreEncoderBufferPictures = iConfig->PluginSettings().iCMRNumCameraBuffers; |
|
875 bufferOptions.iMinNumOutputBuffers = iConfig->PluginSettings().iCMRMinNumOutputBuffers; |
|
876 |
|
877 bufferOptions.iMaxCodedSegmentSize = |
|
878 bufferOptions.iMaxOutputBufferSize = |
|
879 bufferOptions.iMaxCodedPictureSize = iVideoCodecData->MaxBufferLength(iFrameSize); |
|
880 |
|
881 iDevVideoRec->SetBufferOptionsL(bufferOptions); |
|
882 |
|
883 // Set output format |
|
884 iDevVideoRec->SetOutputFormatL(iEncoderHWDeviceId, *comprFormat, EDuCodedPicture, |
|
885 outputFormatEncapsulation, EFalse /* aSegmentationAllowed */); |
|
886 |
|
887 if( iPreProcessorHWDeviceId) |
|
888 { |
|
889 iDevVideoRec->SetOutputFormatL(iPreProcessorHWDeviceId, preproOutputFormat); |
|
890 } |
|
891 |
|
892 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() MinRandomAccess= %d"), iMinRandomAccessPeriodInSeconds )); |
|
893 if ( iConfig && iConfig->IsICMConfigDataAvailable() ) |
|
894 { |
|
895 iMinRandomAccessPeriodInSeconds = iConfig->VideoQualitySettings().iRandomAccessRate; |
|
896 } |
|
897 else |
|
898 { |
|
899 if ( (iFrameSize.iWidth >= KCMRCIFWidth) && (iFrameSize.iHeight >= KCMRCIFHeight) ) |
|
900 { |
|
901 iMinRandomAccessPeriodInSeconds = KCMRMinRandomAccessPeriodHighRes; |
|
902 } |
|
903 } |
|
904 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Set to MinRandomAccess= %d"), iMinRandomAccessPeriodInSeconds )); |
|
905 |
|
906 // Set random access in fps |
|
907 if ( iMinRandomAccessPeriodInSeconds > 0 ) |
|
908 { |
|
909 iDevVideoRec->SetMinRandomAccessRate( TReal(1) / TReal(iMinRandomAccessPeriodInSeconds) ); |
|
910 } |
|
911 else |
|
912 { |
|
913 // there is no concept of disabling random access in MSL, hence use the default |
|
914 iDevVideoRec->SetMinRandomAccessRate( TReal(1) / TReal(KCMRMinRandomAccessPeriod) ); |
|
915 } |
|
916 |
|
917 CleanupStack::PopAndDestroy( comprFormat ); |
|
918 |
|
919 // set codec specific settings |
|
920 iVideoCodecData->SetPreInitParamsL(iDevVideoRec); |
|
921 |
|
922 if (iDirectCapture) |
|
923 { |
|
924 TInt status = KErrNone; |
|
925 // Set the data source to a camera |
|
926 TRAP( status, iDevVideoRec->SetSourceCameraL( iCameraHandle, TReal(iSourceFrameRate)) ); |
|
927 |
|
928 if ( status != KErrNone ) |
|
929 { |
|
930 // Probably it's not supported, although directCapture was declared in the hwdevice info. |
|
931 // Leave or to give one more chance to encoder, to use src memory as a source ? |
|
932 // Yes, otherwise User::Leave(status); |
|
933 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Setting camerasource to MDF failed."))); |
|
934 } |
|
935 else |
|
936 { |
|
937 if ( iClockSource ) |
|
938 { |
|
939 iDevVideoRec->SetClockSource( iClockSource ); |
|
940 } |
|
941 // Ok, use direct capture |
|
942 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() out"))); |
|
943 return; |
|
944 } |
|
945 } |
|
946 |
|
947 // Set source memory is allocated & released by camera API |
|
948 iDevVideoRec->SetSourceMemoryL( TReal(iSourceFrameRate), ETrue, KCMREncodingRealTime); |
|
949 // Set the source to memory buffers |
|
950 iDirectCapture = EFalse; |
|
951 PRINT((_L("CCMRVideoRecorder::SetupEncoderL() out"))); |
|
952 } |
|
953 |
|
954 |
|
955 // --------------------------------------------------------- |
|
956 // CCMRVideoRecorder::ReadEncoderInfoL |
|
957 // Read encoder information object. The object is popped from |
|
958 // stack and MUST be handled properly by the caller |
|
959 // (other items were commented in a header). |
|
960 // --------------------------------------------------------- |
|
961 // |
|
962 CVideoEncoderInfo* CCMRVideoRecorder::ReadEncoderInfoL(TUid aUid) |
|
963 { |
|
964 PRINT((_L("CCMRVideoRecorder::ReadEncoderInfoL(), In"))) |
|
965 CVideoEncoderInfo* info = iDevVideoRec->VideoEncoderInfoLC( aUid ); |
|
966 CleanupStack::Pop(info); |
|
967 |
|
968 PRINT((_L("CCMRVideoRecorder::ReadEncoderInfoL(), Out"))) |
|
969 return info; |
|
970 } |
|
971 |
|
972 |
|
973 // --------------------------------------------------------- |
|
974 // CCMRVideoRecorder::PrepareL |
|
975 // Prepares the recorder for recording |
|
976 // (other items were commented in a header). |
|
977 // --------------------------------------------------------- |
|
978 // |
|
979 void CCMRVideoRecorder::PrepareL() |
|
980 { |
|
981 PRINT((_L("CCMRVideoRecorder::PrepareL(), In"))); |
|
982 |
|
983 if ( (State() != EStateOpen) && (State() != EStateReadyToRecord) ) |
|
984 { |
|
985 PRINT((_L("CCMRVideoRecorder::PrepareL() wrong state"))); |
|
986 User::Leave( KErrNotReady ); |
|
987 } |
|
988 |
|
989 if ( State() == EStateReadyToRecord ) |
|
990 { |
|
991 // No prepare needed... already ready. |
|
992 // everything ok, inform observer that we are prepared. |
|
993 PRINT((_L("CCMRVideoRecorder::PrepareL(), Already prepared. Return right away"))); |
|
994 DoSendEventToClient( KCMRPrepareComplete, KErrNone ); |
|
995 return; |
|
996 } |
|
997 |
|
998 if (iDevVideoRec) |
|
999 { |
|
1000 delete iDevVideoRec; |
|
1001 iDevVideoRec = NULL; |
|
1002 } |
|
1003 |
|
1004 iDevVideoRec = CMMFDevVideoRecord::NewL( *this ); |
|
1005 |
|
1006 // reset error code |
|
1007 iErrorCode = KErrNone; |
|
1008 |
|
1009 // If the user of the recorder API has not set valid settings, |
|
1010 // use default ones |
|
1011 |
|
1012 if ( ((iSizeIndex420 < 0) && (iSizeIndex422 < 0) && (iSizeIndexDCEncoder < 0)) |
|
1013 || ((iSizeIndex420 >= iCameraInfo.iNumVideoFrameSizesSupported) && (iSizeIndex422 >= iCameraInfo.iNumVideoFrameSizesSupported)) ) |
|
1014 { |
|
1015 // set default frame size |
|
1016 SetFrameSizeL( TSize( KCMRFrameWidth, KCMRFrameHeight ) ); |
|
1017 } |
|
1018 |
|
1019 if ( ((iRateIndex420 < 0) && (iRateIndex422 < 0) && (iRateIndexDCEncoder < 0)) |
|
1020 || ((iRateIndex420 >= iCameraInfo.iNumVideoFrameRatesSupported) && (iRateIndex422 >= iCameraInfo.iNumVideoFrameRatesSupported)) ) |
|
1021 { |
|
1022 // set default frame rate |
|
1023 SetFrameRateL( KCMRFrameRate ); |
|
1024 } |
|
1025 |
|
1026 // if during previous run a new frame rate was requested; when requested it affected only on encoding rate |
|
1027 if ( iRequestedFrameRate != iSourceFrameRate ) |
|
1028 { |
|
1029 SetState(EStateOpen);//change state to make the SetFrameRate work correctly |
|
1030 SetFrameRateL( iRequestedFrameRate ); |
|
1031 } |
|
1032 |
|
1033 // reset init completion flags |
|
1034 iEncoderInitComplete = EFalse; |
|
1035 iSourceInitComplete = EFalse; |
|
1036 iVideoCodecHWAccelerated = EFalse; |
|
1037 // Select & set parameters to video encoder |
|
1038 TRAPD(err, SetupEncoderL()); |
|
1039 if ( err == KErrHardwareNotAvailable && iVideoCodecHWAccelerated ) |
|
1040 { |
|
1041 // HW codec exists but can't be used, try again with ARM codec |
|
1042 SetupEncoderL(); |
|
1043 } |
|
1044 else if ( err != KErrNone ) |
|
1045 { |
|
1046 // some other error |
|
1047 PRINT((_L("CCMRVideoRecorder::PrepareL(), error [%d]"), err)); |
|
1048 User::Leave( err ); |
|
1049 } |
|
1050 |
|
1051 SetState(EStatePreparing); |
|
1052 |
|
1053 // Reserve camera for use |
|
1054 // Possibly asynchronous call (if not already reserved), completion is anyway informed using this->ReserveComplete() |
|
1055 // iSource has to be reserved only if we don't set hwdevice to use DirectCapture. |
|
1056 if ( !iDirectCapture ) |
|
1057 { |
|
1058 iSource->Reserve(); |
|
1059 } |
|
1060 |
|
1061 // Initialize DevVideoRec |
|
1062 // asynchronous call, completion informed using this->MdvroInitializeComplete() |
|
1063 iDevVideoRec->Initialize(); |
|
1064 |
|
1065 PRINT((_L("CCMRVideoRecorder::PrepareL(), Out"))); |
|
1066 } |
|
1067 |
|
1068 |
|
1069 // --------------------------------------------------------- |
|
1070 // CCMRVideoRecorder::RecordL |
|
1071 // Starts recording |
|
1072 // (other items were commented in a header). |
|
1073 // --------------------------------------------------------- |
|
1074 // |
|
1075 void CCMRVideoRecorder::RecordL() |
|
1076 { |
|
1077 PRINT((_L("CCMRVideoRecorder::RecordL() - START - iRequestStatus: 0x%08x"), iRequestStatus )); |
|
1078 |
|
1079 if ( (State() == EStateRecording) || (State() == EStatePaused) ) |
|
1080 { |
|
1081 // ignore, already recording |
|
1082 PRINT((_L("CCMRVideoRecorder::RecordL() ignore"))); |
|
1083 return; |
|
1084 } |
|
1085 |
|
1086 if ( State() != EStateReadyToRecord ) |
|
1087 { |
|
1088 PRINT((_L("CCMRVideoRecorder::RecordL() not ready"))); |
|
1089 User::Leave(KErrNotReady); |
|
1090 } |
|
1091 |
|
1092 // check exposure setting from camera => decide framerates |
|
1093 CheckExposure(); |
|
1094 |
|
1095 #ifdef _DEBUG |
|
1096 iRecordStartTime.UniversalTime(); |
|
1097 iLastCapture.UniversalTime(); |
|
1098 #endif |
|
1099 iNumberOfCapturedFrames = 0; |
|
1100 iNumberOfEncodedFrames = 0; |
|
1101 iEncoderInputQueueLength = 0; |
|
1102 iDriftFrameSkipCount = 0; |
|
1103 iAddedFrameDurationCount = 0; |
|
1104 iPreviousCameraFrameIndex = 0; |
|
1105 iDecSpecInfoLength = 0; |
|
1106 |
|
1107 // reset pause time adjustments variables |
|
1108 iTimeWhenPaused = 0; |
|
1109 iTotalPausedTime = 0; |
|
1110 iSystemClockDelta = 0; |
|
1111 iLatestUsedTimeStamp = -iSourceFrameInterval; |
|
1112 iLatestAbsoluteTimeStamp = 0; |
|
1113 iNumberOfCapturedFrames = 0; |
|
1114 iNumberOfVideoOutputBuffers = 0; |
|
1115 |
|
1116 if ( iVideoCodecData->DecoderConfigInfoUsed() ) |
|
1117 { |
|
1118 // Read decoder specific information from the encoder |
|
1119 PRINT((_L("CCMRVideoRecorder::RecordL() asking CodingStandardSpecificInitOutputLC from the encoder."))); |
|
1120 iDecSpecInfo = iDevVideoRec->CodingStandardSpecificInitOutputLC(); |
|
1121 if ( iDecSpecInfo ) |
|
1122 { |
|
1123 PRINT((_L("CCMRVideoRecorder::RecordL() CodingStandardSpecificInitOutputLC received."))); |
|
1124 // it was placed to cleanupstack, pop it now since it takes some time before |
|
1125 // this ptr can be destructed, and if destructed from the stack, there may |
|
1126 // be newer objects in the stack at that time. The ptr is also now stored |
|
1127 // to member variable which must not be in stack |
|
1128 CleanupStack::Pop(iDecSpecInfo); |
|
1129 |
|
1130 // Inform the output that we have new data; it will read it in callback |
|
1131 if ( iRequestStatus ) |
|
1132 { |
|
1133 PRINT((_L("CCMRVideoRecorder::RecordL() - completing output request..." ))); |
|
1134 iOutputThreadHandle.RequestComplete( iRequestStatus, KErrNone ); |
|
1135 } |
|
1136 } |
|
1137 else |
|
1138 { |
|
1139 // This codec should have decoder specific info field in metadata, hence leave with error |
|
1140 PRINT((_L("CCMRVideoRecorder::RecordL() no decoder specific info available from the encoder!?!"))); |
|
1141 User::Leave( KErrNotSupported ); |
|
1142 } |
|
1143 } |
|
1144 |
|
1145 // Start encoding |
|
1146 iDevVideoRec->Start(); |
|
1147 iSkipBuffers = EFalse; |
|
1148 |
|
1149 iInputEnd = EFalse; |
|
1150 iStreamEnd = EFalse; |
|
1151 |
|
1152 // Start capturing |
|
1153 // StartCapture in case, if we don't use direct capture mode |
|
1154 if ( !iDirectCapture ) |
|
1155 { |
|
1156 iSource->StartCapture(); |
|
1157 } |
|
1158 |
|
1159 SetState(EStateRecording); |
|
1160 |
|
1161 PRINT((_L("CCMRVideoRecorder::RecordL() - END - iRequestStatus: 0x%08x"), iRequestStatus )); |
|
1162 } |
|
1163 |
|
1164 |
|
1165 // --------------------------------------------------------- |
|
1166 // CCMRVideoRecorder::StopL |
|
1167 // Stops recording |
|
1168 // (other items were commented in a header). |
|
1169 // --------------------------------------------------------- |
|
1170 // |
|
1171 void CCMRVideoRecorder::StopL() |
|
1172 { |
|
1173 PRINT((_L("CCMRVideoRecorder::StopL(), In"))) |
|
1174 |
|
1175 if ( (State() == EStateRecording) || (State() == EStatePaused) ) |
|
1176 { |
|
1177 PRINT((_L("CCMRVideoRecorder::StopL(), Stop capture"))); |
|
1178 |
|
1179 // Stop capturing |
|
1180 // Stop capture only incase, if we don't use direct capture mode |
|
1181 if ( !iDirectCapture ) |
|
1182 { |
|
1183 iSource->StopCapture(); |
|
1184 PRINT((_L("CCMRVideoRecorder::StopL() camera stopped"))); |
|
1185 } |
|
1186 |
|
1187 |
|
1188 // Stopping is async => state can't be "recording" |
|
1189 SetState(EStateStopping); |
|
1190 |
|
1191 // Stop encoding |
|
1192 if ( !iFatalError ) |
|
1193 { |
|
1194 iInputEnd = ETrue; |
|
1195 PRINT((_L("CCMRVideoRecorder::StopL(), calling DevVideo::InputEnd()."))); |
|
1196 iDevVideoRec->InputEnd(); |
|
1197 // try to free buffers for video adaptation to complete video bitstream / EOS marker. |
|
1198 PRINT((_L("CCMRVideoRecorder::StopL(), flushing written frames back to DevVideo."))); |
|
1199 iBufferReturnAO->Flush(); |
|
1200 |
|
1201 // get all available buffers from devvideo |
|
1202 PRINT((_L("CCMRVideoRecorder::StopL(), getting all encoded frames from DevVideo."))); |
|
1203 TVideoOutputBuffer* buffer = NULL; |
|
1204 for (;;) |
|
1205 { |
|
1206 TRAPD( err, ( buffer = iDevVideoRec->NextBufferL())); |
|
1207 if ( err != KErrNone || buffer == NULL) |
|
1208 { |
|
1209 break; |
|
1210 } |
|
1211 // enter restricted area |
|
1212 iMutexObj.Wait(); |
|
1213 // store |
|
1214 TInt timestamp = I64INT(buffer->iCaptureTimestamp.Int64()); |
|
1215 PRINT((_L("CCMRVideoRecorder::StopL(), storing buffer: 0x%x, timestamp:%d"), buffer, timestamp )); |
|
1216 iVideoOutputBufferInputQue.AddLast(*buffer); |
|
1217 iNumberOfVideoOutputBuffers++; |
|
1218 |
|
1219 // leave restricted area |
|
1220 iMutexObj.Signal(); |
|
1221 } |
|
1222 } |
|
1223 else |
|
1224 { |
|
1225 PRINT((_L("CCMRVideoRecorder::StopL(), Fatal error was reported by devVideo, next step is to delete it"))); |
|
1226 |
|
1227 // set state & inform MR => it can return from stop |
|
1228 SetState( EStateReadyToRecord ); |
|
1229 |
|
1230 // everything ok, inform observer that we are ready for a new recording (iStopping does it too, though). |
|
1231 DoSendEventToClient( KCMRRecordingComplete, KErrNone ); |
|
1232 } |
|
1233 |
|
1234 PRINT((_L("CCMRVideoRecorder::StopL() out, must wait for state change before stop completed"))); |
|
1235 } |
|
1236 else |
|
1237 { |
|
1238 DoSendEventToClient( KCMRRecordingComplete, KErrNone ); |
|
1239 PRINT((_L("CCMRVideoRecorder::StopL() out, already stopped"))); |
|
1240 } |
|
1241 } |
|
1242 |
|
1243 // --------------------------------------------------------- |
|
1244 // CCMRVideoRecorder::RequestBuffersAndWaitEOSL |
|
1245 // While stopping keep requesting buffers from adaptation and waiting for EOS marker encodc signal |
|
1246 // (other items were commented in a header). |
|
1247 // --------------------------------------------------------- |
|
1248 // |
|
1249 |
|
1250 void CCMRVideoRecorder::RequestBuffersAndWaitEOSL(TInt& aVideoEOSReached) |
|
1251 { |
|
1252 PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), in"))) |
|
1253 PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), flushing written frames back to DevVideo."))); |
|
1254 iBufferReturnAO->Flush(); |
|
1255 |
|
1256 // get all available buffers from devvideo |
|
1257 PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), getting all encoded frames from DevVideo."))); |
|
1258 TVideoOutputBuffer* buffer = NULL; |
|
1259 for (;;) |
|
1260 { |
|
1261 TRAPD( err, ( buffer = iDevVideoRec->NextBufferL())); |
|
1262 if ( err != KErrNone || buffer == NULL) |
|
1263 { |
|
1264 break; |
|
1265 } |
|
1266 // enter restricted area |
|
1267 iMutexObj.Wait(); |
|
1268 // store |
|
1269 TInt timestamp = I64INT(buffer->iCaptureTimestamp.Int64()); |
|
1270 PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), storing buffer: 0x%x, timestamp:%d"), buffer, timestamp)); |
|
1271 iVideoOutputBufferInputQue.AddLast(*buffer); |
|
1272 iNumberOfVideoOutputBuffers++; |
|
1273 |
|
1274 // leave restricted area |
|
1275 iMutexObj.Signal(); |
|
1276 } |
|
1277 |
|
1278 aVideoEOSReached = iStreamEnd; |
|
1279 PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL() out, aVideoEOSReached=%d"), aVideoEOSReached)); |
|
1280 } |
|
1281 |
|
1282 // --------------------------------------------------------- |
|
1283 // CCMRVideoRecorder::PauseL |
|
1284 // Pauses recording |
|
1285 // (other items were commented in a header). |
|
1286 // --------------------------------------------------------- |
|
1287 // |
|
1288 void CCMRVideoRecorder::PauseL() |
|
1289 { |
|
1290 PRINT((_L("CCMRVideoRecorder::PauseL(), In"))) |
|
1291 |
|
1292 if ( State() != EStateRecording ) |
|
1293 { |
|
1294 return; |
|
1295 } |
|
1296 |
|
1297 SetState( EStatePaused ); |
|
1298 |
|
1299 // Take the time stamp and later subtract it from real stamps |
|
1300 iTimeWhenPaused.UniversalTime(); |
|
1301 PRINT((_L("CCMRVideoRecorder::PauseL() at %i:%i"),I64LOW(iTimeWhenPaused.Int64()), I64HIGH(iTimeWhenPaused.Int64()) )); |
|
1302 |
|
1303 // Adjust in the clock time changes, so we don't add it in twice during resume |
|
1304 iTimeWhenPaused = iTimeWhenPaused + iSystemClockDelta; |
|
1305 PRINT((_L("CCMRVideoRecorder::PauseL() at %i:%i"),I64LOW(iTimeWhenPaused.Int64()), I64HIGH(iTimeWhenPaused.Int64()) )); |
|
1306 |
|
1307 // Pause encoding |
|
1308 iDevVideoRec->Pause(); |
|
1309 PRINT((_L("CCMRVideoRecorder::PauseL(), In"))) |
|
1310 } |
|
1311 |
|
1312 |
|
1313 // --------------------------------------------------------- |
|
1314 // CCMRVideoRecorder::ResumeL |
|
1315 // Resumes recording |
|
1316 // (other items were commented in a header). |
|
1317 // --------------------------------------------------------- |
|
1318 // |
|
1319 void CCMRVideoRecorder::ResumeL() |
|
1320 { |
|
1321 PRINT((_L("CCMRVideoRecorder::ResumeL(), In"))) |
|
1322 |
|
1323 if ( State() != EStatePaused ) |
|
1324 { |
|
1325 return; |
|
1326 } |
|
1327 |
|
1328 // Resume encoding |
|
1329 iDevVideoRec->Resume(); |
|
1330 |
|
1331 // measure the time we were paused; remember that this could have been Nth pause |
|
1332 TTime current; |
|
1333 current.UniversalTime(); |
|
1334 iTotalPausedTime = iTotalPausedTime.Int64() + current.MicroSecondsFrom(iTimeWhenPaused-iSystemClockDelta).Int64(); |
|
1335 PRINT((_L("CCMRVideoRecorder::ResumeL() at %i:%i, iTotalPausedTime now %d, iSystemClockDelta now %d"),I64LOW(current.Int64()), |
|
1336 I64HIGH(current.Int64()), |
|
1337 I64INT(iTotalPausedTime.Int64()), |
|
1338 I64INT(iSystemClockDelta.Int64()) )); |
|
1339 |
|
1340 SetState( EStateRecording ); |
|
1341 PRINT((_L("CCMRVideoRecorder::ResumeL(), Out"))) |
|
1342 } |
|
1343 |
|
1344 |
|
1345 // ----------------------------------------------------------------------------- |
|
1346 // CCMRVideoRecorder::SetVideoCodecL |
|
1347 // Set video codec. |
|
1348 // (other items were commented in a header). |
|
1349 // ----------------------------------------------------------------------------- |
|
1350 // |
|
1351 void CCMRVideoRecorder::SetVideoCodecL(const TDesC8& aMimeType) |
|
1352 { |
|
1353 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() in"))); |
|
1354 if ( ( State() != EStateOpen ) && ( State() != EStateReadyToRecord ) ) |
|
1355 { |
|
1356 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() wrong state"))); |
|
1357 User::Leave(KErrNotReady); |
|
1358 } |
|
1359 |
|
1360 if ( iMimeType == aMimeType ) |
|
1361 { |
|
1362 // the same codec was already selected, no need to change anything |
|
1363 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() out, no change needed. Requested codec already in use."))); |
|
1364 return; |
|
1365 } |
|
1366 |
|
1367 TInt numerator = KCMRAspectRatioNum; |
|
1368 TInt denominator = KCMRAspectRatioDenom; |
|
1369 TInt videoCodecLevel = 10; // default: H.263 p0 level 10 |
|
1370 TBuf8<256> newMimeType; |
|
1371 if ( aMimeType == KNullDesC8 ) |
|
1372 { |
|
1373 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() Requested NULL video codec, default H.263 Baseline profile, level 10 in use."))); |
|
1374 // use default (H.263 p0 level 10); theoretically this could be useful if codec is first set to smth else and then reset to default |
|
1375 newMimeType = KCMRMimeTypeH263BaselineProfile; //copy the contents |
|
1376 newMimeType += _L8( "; level=10" ); //append level |
|
1377 videoCodecLevel = 10; |
|
1378 } |
|
1379 else { |
|
1380 // check the given type first |
|
1381 TBuf8<256> string; |
|
1382 string = KCMRMimeTypeH263; |
|
1383 string += _L8( "*" ); |
|
1384 |
|
1385 // the client-class checked the availability of the codec in the system already |
|
1386 |
|
1387 if ( aMimeType.MatchF( (const TDesC8& )string ) != KErrNotFound ) |
|
1388 { |
|
1389 // H.263 |
|
1390 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263 requested"))); |
|
1391 newMimeType = KCMRMimeTypeH263; //copy the contents |
|
1392 |
|
1393 if ( aMimeType.MatchF( _L8("*profile*") ) != KErrNotFound ) |
|
1394 { |
|
1395 // profile given, check if we support it |
|
1396 if ( aMimeType.MatchF( _L8("*profile=0*")) != KErrNotFound ) |
|
1397 { |
|
1398 // profile 0 requested |
|
1399 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, profile 0 requested"))); |
|
1400 newMimeType += _L8( "; profile=0" ); //append |
|
1401 } |
|
1402 else if ( aMimeType.MatchF( _L8("*profile=3*")) != KErrNotFound ) |
|
1403 { |
|
1404 // profile 3 requested |
|
1405 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, profile 3 requested"))); |
|
1406 newMimeType += _L8( "; profile=3" ); //append |
|
1407 } |
|
1408 else |
|
1409 { |
|
1410 // no other profiles supported |
|
1411 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported profile"))); |
|
1412 User::Leave(KErrNotSupported); |
|
1413 } |
|
1414 } |
|
1415 else |
|
1416 { |
|
1417 // no profile is given => assume 0 |
|
1418 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, no profile requested - default to 0."))); |
|
1419 newMimeType += _L8( "; profile=0" ); //append |
|
1420 } |
|
1421 |
|
1422 if ( aMimeType.MatchF( _L8("*level=10*") ) != KErrNotFound ) |
|
1423 { |
|
1424 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 10 requested."))); |
|
1425 videoCodecLevel = 10; |
|
1426 newMimeType += _L8( "; level=10" ); //append |
|
1427 } |
|
1428 else if ( aMimeType.MatchF( _L8("*level=20*") ) != KErrNotFound ) |
|
1429 { |
|
1430 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 20 requested."))); |
|
1431 videoCodecLevel = 20; |
|
1432 newMimeType += _L8( "; level=20" ); //append |
|
1433 } |
|
1434 else if ( aMimeType.MatchF( _L8("*level=30*") ) != KErrNotFound ) |
|
1435 { |
|
1436 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 30 requested."))); |
|
1437 videoCodecLevel = 30; |
|
1438 newMimeType += _L8( "; level=30" ); //append |
|
1439 } |
|
1440 else if ( aMimeType.MatchF( _L8("*level=40*") ) != KErrNotFound ) |
|
1441 { |
|
1442 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 40 requested."))); |
|
1443 videoCodecLevel = 40; |
|
1444 newMimeType += _L8( "; level=40" ); //append |
|
1445 } |
|
1446 else if ( aMimeType.MatchF( _L8("*level=45*") ) != KErrNotFound ) |
|
1447 { |
|
1448 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 45 requested."))); |
|
1449 videoCodecLevel = 45; |
|
1450 newMimeType += _L8( "; level=45" ); //append |
|
1451 } |
|
1452 else if ( aMimeType.MatchF( _L8("*level=50*") ) != KErrNotFound ) |
|
1453 { |
|
1454 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 50 requested."))); |
|
1455 videoCodecLevel = 50; |
|
1456 newMimeType += _L8( "; level=50" ); //append |
|
1457 } |
|
1458 else if ( aMimeType.MatchF( _L8("*level*") ) != KErrNotFound ) |
|
1459 { |
|
1460 // no other levels supported |
|
1461 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported level requested."))); |
|
1462 User::Leave(KErrNotSupported); |
|
1463 } |
|
1464 else |
|
1465 { |
|
1466 // if no level is given assume 10 |
|
1467 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, no level requested - default to 10."))); |
|
1468 newMimeType += _L8( "; level=10" ); //append |
|
1469 videoCodecLevel = 10; |
|
1470 } |
|
1471 |
|
1472 // recreate the codec data object |
|
1473 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263 recreating codecdata."))); |
|
1474 delete iVideoCodecData; |
|
1475 iVideoCodecData = NULL; |
|
1476 iVideoCodecData = new (ELeave) CCMRVideoCodecDataH263(videoCodecLevel); |
|
1477 } |
|
1478 else |
|
1479 { |
|
1480 numerator = KCMRMPEG4AspectRatioNum; |
|
1481 denominator = KCMRMPEG4AspectRatioDenom; |
|
1482 |
|
1483 string = KCMRMimeTypeMPEG4V; |
|
1484 string += _L8( "*" ); |
|
1485 |
|
1486 if ( aMimeType.MatchF( string ) != KErrNotFound ) |
|
1487 { |
|
1488 // MPEG-4 Visual |
|
1489 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4 Visual requested"))); |
|
1490 newMimeType = KCMRMimeTypeMPEG4VSP; //copy the contents |
|
1491 if ( aMimeType.MatchF( _L8("*profile-level-id=8*") ) != KErrNotFound ) |
|
1492 { |
|
1493 // simple profile level 0 |
|
1494 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 0 requested."))); |
|
1495 videoCodecLevel = 0; |
|
1496 newMimeType += _L8("8"); |
|
1497 } |
|
1498 else if ( aMimeType.MatchF( _L8("*profile-level-id=9*") ) != KErrNotFound ) |
|
1499 { |
|
1500 // simple profile level 0b |
|
1501 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 0b requested."))); |
|
1502 videoCodecLevel = KCMRMPEG4SPLevel0B; |
|
1503 newMimeType += _L8("9"); |
|
1504 } |
|
1505 else if ( aMimeType.MatchF( _L8("*profile-level-id=1*") ) != KErrNotFound ) |
|
1506 { |
|
1507 // simple profile level 1 |
|
1508 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 1 requested."))); |
|
1509 videoCodecLevel = 1; |
|
1510 newMimeType += _L8("1"); |
|
1511 } |
|
1512 else if ( aMimeType.MatchF( _L8("*profile-level-id=2*") ) != KErrNotFound ) |
|
1513 { |
|
1514 // simple profile level 2 |
|
1515 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 2 requested."))); |
|
1516 videoCodecLevel = 2; |
|
1517 newMimeType += _L8("2"); |
|
1518 } |
|
1519 else if ( aMimeType.MatchF( _L8("*profile-level-id=3*") ) != KErrNotFound ) |
|
1520 { |
|
1521 // simple profile level 3 |
|
1522 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 3 requested."))); |
|
1523 videoCodecLevel = 3; |
|
1524 newMimeType += _L8("3"); |
|
1525 } |
|
1526 else if ( aMimeType.MatchF( _L8("*profile-level-id=4*") ) != KErrNotFound ) |
|
1527 { |
|
1528 // simple profile level 4 |
|
1529 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 4a requested."))); |
|
1530 videoCodecLevel = 4; |
|
1531 newMimeType += _L8("4"); |
|
1532 } |
|
1533 else if ( aMimeType.MatchF( _L8("*profile-level-id=5*") ) != KErrNotFound ) |
|
1534 { |
|
1535 // simple profile level 5 |
|
1536 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 5 requested."))); |
|
1537 videoCodecLevel = 5; |
|
1538 newMimeType += _L8("5"); |
|
1539 } |
|
1540 else if ( aMimeType.MatchF( _L8("*profile-level-id=6*") ) != KErrNotFound ) |
|
1541 { |
|
1542 // simple profile level 6 |
|
1543 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 6 requested."))); |
|
1544 videoCodecLevel = 6; |
|
1545 newMimeType += _L8("6"); |
|
1546 } |
|
1547 else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound ) |
|
1548 { |
|
1549 // no other profile-level ids supported |
|
1550 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported profile-level requested."))); |
|
1551 User::Leave(KErrNotSupported); |
|
1552 } |
|
1553 else |
|
1554 { |
|
1555 // Default is level 1 |
|
1556 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, no profile requested - defaulting to 1."))); |
|
1557 videoCodecLevel = 1; |
|
1558 newMimeType += _L8("1"); |
|
1559 } |
|
1560 |
|
1561 // recreate the codec data object |
|
1562 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4 recreating codecdata."))); |
|
1563 delete iVideoCodecData; |
|
1564 iVideoCodecData = NULL; |
|
1565 iVideoCodecData = new (ELeave) CCMRVideoCodecDataMPEG4(videoCodecLevel); |
|
1566 } |
|
1567 else |
|
1568 { |
|
1569 numerator = KCMRMPEG4AspectRatioNum; |
|
1570 denominator = KCMRMPEG4AspectRatioDenom; |
|
1571 |
|
1572 string = KCMRMimeTypeH264AVC; |
|
1573 string += _L8( "*" ); |
|
1574 |
|
1575 if ( aMimeType.MatchF( string ) != KErrNotFound ) |
|
1576 { |
|
1577 // H.264/AVC |
|
1578 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC requested"))); |
|
1579 newMimeType = KCMRMimeTypeH264AVCProfileId; //copy the contents |
|
1580 if ( aMimeType.MatchF( _L8("*profile-level-id=42800A*") ) != KErrNotFound ) |
|
1581 { |
|
1582 // baseline profile level 1 |
|
1583 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1 requested."))); |
|
1584 videoCodecLevel = KCMRH264AVCCodecLevel10; |
|
1585 newMimeType += _L8("42800A"); |
|
1586 } |
|
1587 else if ( aMimeType.MatchF( _L8("*profile-level-id=42900B*") ) != KErrNotFound ) |
|
1588 { |
|
1589 // baseline profile level 1b |
|
1590 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1b requested."))); |
|
1591 videoCodecLevel = KCMRH264AVCCodecLevel10b; |
|
1592 newMimeType += _L8("42900B"); |
|
1593 } |
|
1594 else if ( aMimeType.MatchF( _L8("*profile-level-id=42800B*") ) != KErrNotFound ) |
|
1595 { |
|
1596 // baseline profile level 1.1 |
|
1597 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1.1 requested."))); |
|
1598 videoCodecLevel = KCMRH264AVCCodecLevel11; |
|
1599 newMimeType += _L8("42800B"); |
|
1600 } |
|
1601 else if ( aMimeType.MatchF( _L8("*profile-level-id=42800C*") ) != KErrNotFound ) |
|
1602 { |
|
1603 // baseline profile level 1.2 |
|
1604 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1.2 requested."))); |
|
1605 videoCodecLevel = KCMRH264AVCCodecLevel12; |
|
1606 newMimeType += _L8("42800C"); |
|
1607 } |
|
1608 else if ( aMimeType.MatchF( _L8("*profile-level-id=42800D*") ) != KErrNotFound ) |
|
1609 { |
|
1610 // baseline profile level 1.3 |
|
1611 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1.3 requested."))); |
|
1612 videoCodecLevel = KCMRH264AVCCodecLevel13; |
|
1613 newMimeType += _L8("42800D"); |
|
1614 } |
|
1615 else if ( aMimeType.MatchF( _L8("*profile-level-id=428014*") ) != KErrNotFound ) |
|
1616 { |
|
1617 // baseline profile level 2 |
|
1618 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 2 requested."))); |
|
1619 videoCodecLevel = KCMRH264AVCCodecLevel20; |
|
1620 newMimeType += _L8("428014"); |
|
1621 } |
|
1622 else if ( aMimeType.MatchF( _L8("*profile-level-id=428015*") ) != KErrNotFound ) |
|
1623 { |
|
1624 // baseline profile level 2.1 |
|
1625 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 2.1 requested."))); |
|
1626 videoCodecLevel = KCMRH264AVCCodecLevel21; |
|
1627 newMimeType += _L8("428015"); |
|
1628 } |
|
1629 else if ( aMimeType.MatchF( _L8("*profile-level-id=428016*") ) != KErrNotFound ) |
|
1630 { |
|
1631 // baseline profile level 2.2 |
|
1632 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 2.2 requested."))); |
|
1633 videoCodecLevel = KCMRH264AVCCodecLevel22; |
|
1634 newMimeType += _L8("428016"); |
|
1635 } |
|
1636 else if ( aMimeType.MatchF( _L8("*profile-level-id=42801E*") ) != KErrNotFound ) |
|
1637 { |
|
1638 // baseline profile level 3 |
|
1639 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 3 requested."))); |
|
1640 videoCodecLevel = KCMRH264AVCCodecLevel30; |
|
1641 newMimeType += _L8("42801E"); |
|
1642 } |
|
1643 else if ( aMimeType.MatchF( _L8("*profile-level-id=42801F*") ) != KErrNotFound ) |
|
1644 { |
|
1645 // baseline profile level 3.1 |
|
1646 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 3.1 requested."))); |
|
1647 videoCodecLevel = KCMRH264AVCCodecLevel31; |
|
1648 newMimeType += _L8("42801F"); |
|
1649 } |
|
1650 else if ( aMimeType.MatchF( _L8("*profile-level-id=428020*") ) != KErrNotFound ) |
|
1651 { |
|
1652 // baseline profile level 3.2 |
|
1653 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 3.2 requested."))); |
|
1654 videoCodecLevel = KCMRH264AVCCodecLevel32; |
|
1655 newMimeType += _L8("428020"); |
|
1656 } |
|
1657 else if ( aMimeType.MatchF( _L8("*profile-level-id=428028*") ) != KErrNotFound ) |
|
1658 { |
|
1659 // baseline profile level 4 |
|
1660 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 4 requested."))); |
|
1661 videoCodecLevel = KCMRH264AVCCodecLevel40; |
|
1662 newMimeType += _L8("428028"); |
|
1663 } |
|
1664 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400A*") ) != KErrNotFound ) |
|
1665 { |
|
1666 // main profile level 1 |
|
1667 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1 requested."))); |
|
1668 videoCodecLevel = KCMRH264AVCCodecLevel10; |
|
1669 newMimeType += _L8("4D400A"); |
|
1670 } |
|
1671 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D500B*") ) != KErrNotFound ) |
|
1672 { |
|
1673 // main profile level 1b |
|
1674 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1b requested."))); |
|
1675 videoCodecLevel = KCMRH264AVCCodecLevel10b; |
|
1676 newMimeType += _L8("4D500B"); |
|
1677 } |
|
1678 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400B*") ) != KErrNotFound ) |
|
1679 { |
|
1680 // main profile level 1.1 |
|
1681 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1.1 requested."))); |
|
1682 videoCodecLevel = KCMRH264AVCCodecLevel11; |
|
1683 newMimeType += _L8("4D400B"); |
|
1684 } |
|
1685 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400C*") ) != KErrNotFound ) |
|
1686 { |
|
1687 // main profile level 1.2 |
|
1688 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1.2 requested."))); |
|
1689 videoCodecLevel = KCMRH264AVCCodecLevel12; |
|
1690 newMimeType += _L8("4D400C"); |
|
1691 } |
|
1692 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400D*") ) != KErrNotFound ) |
|
1693 { |
|
1694 // main profile level 1.3 |
|
1695 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1.3 requested."))); |
|
1696 videoCodecLevel = KCMRH264AVCCodecLevel13; |
|
1697 newMimeType += _L8("4D400D"); |
|
1698 } |
|
1699 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4014*") ) != KErrNotFound ) |
|
1700 { |
|
1701 // main profile level 2 |
|
1702 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 2 requested."))); |
|
1703 videoCodecLevel = KCMRH264AVCCodecLevel20; |
|
1704 newMimeType += _L8("4D4014"); |
|
1705 } |
|
1706 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4015*") ) != KErrNotFound ) |
|
1707 { |
|
1708 // main profile level 2.1 |
|
1709 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 2.1 requested."))); |
|
1710 videoCodecLevel = KCMRH264AVCCodecLevel21; |
|
1711 newMimeType += _L8("4D4015"); |
|
1712 } |
|
1713 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4016*") ) != KErrNotFound ) |
|
1714 { |
|
1715 // main profile level 2.2 |
|
1716 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 2.2 requested."))); |
|
1717 videoCodecLevel = KCMRH264AVCCodecLevel22; |
|
1718 newMimeType += _L8("4D4016"); |
|
1719 } |
|
1720 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D401E*") ) != KErrNotFound ) |
|
1721 { |
|
1722 // main profile level 3 |
|
1723 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 3 requested."))); |
|
1724 videoCodecLevel = KCMRH264AVCCodecLevel30; |
|
1725 newMimeType += _L8("4D401E"); |
|
1726 } |
|
1727 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D401F*") ) != KErrNotFound ) |
|
1728 { |
|
1729 // main profile level 3.1 |
|
1730 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 3.1 requested."))); |
|
1731 videoCodecLevel = KCMRH264AVCCodecLevel31; |
|
1732 newMimeType += _L8("4D401F"); |
|
1733 } |
|
1734 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4020*") ) != KErrNotFound ) |
|
1735 { |
|
1736 // main profile level 3.2 |
|
1737 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 3.2 requested."))); |
|
1738 videoCodecLevel = KCMRH264AVCCodecLevel32; |
|
1739 newMimeType += _L8("4D4020"); |
|
1740 } |
|
1741 else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4028*") ) != KErrNotFound ) |
|
1742 { |
|
1743 // main profile level 4 |
|
1744 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 4 requested."))); |
|
1745 videoCodecLevel = KCMRH264AVCCodecLevel40; |
|
1746 newMimeType += _L8("4D4028"); |
|
1747 } |
|
1748 else if ( aMimeType.MatchF( _L8("*profile-level-id=64400A*") ) != KErrNotFound ) |
|
1749 { |
|
1750 // high profile level 1 |
|
1751 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1 requested."))); |
|
1752 videoCodecLevel = KCMRH264AVCCodecLevel10; |
|
1753 newMimeType += _L8("64400A"); |
|
1754 } |
|
1755 else if ( aMimeType.MatchF( _L8("*profile-level-id=644009*") ) != KErrNotFound ) |
|
1756 { |
|
1757 // high profile level 1b |
|
1758 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1b requested."))); |
|
1759 videoCodecLevel = KCMRH264AVCCodecLevel10b; |
|
1760 newMimeType += _L8("644009"); |
|
1761 } |
|
1762 else if ( aMimeType.MatchF( _L8("*profile-level-id=64400B*") ) != KErrNotFound ) |
|
1763 { |
|
1764 // high profile level 1.1 |
|
1765 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1.1 requested."))); |
|
1766 videoCodecLevel = KCMRH264AVCCodecLevel11; |
|
1767 newMimeType += _L8("64400B"); |
|
1768 } |
|
1769 else if ( aMimeType.MatchF( _L8("*profile-level-id=64400C*") ) != KErrNotFound ) |
|
1770 { |
|
1771 // high profile level 1.2 |
|
1772 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1.2 requested."))); |
|
1773 videoCodecLevel = KCMRH264AVCCodecLevel12; |
|
1774 newMimeType += _L8("64400C"); |
|
1775 } |
|
1776 else if ( aMimeType.MatchF( _L8("*profile-level-id=64400D*") ) != KErrNotFound ) |
|
1777 { |
|
1778 // high profile level 1.3 |
|
1779 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1.3 requested."))); |
|
1780 videoCodecLevel = KCMRH264AVCCodecLevel13; |
|
1781 newMimeType += _L8("64400D"); |
|
1782 } |
|
1783 else if ( aMimeType.MatchF( _L8("*profile-level-id=644014*") ) != KErrNotFound ) |
|
1784 { |
|
1785 // high profile level 2 |
|
1786 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 2 requested."))); |
|
1787 videoCodecLevel = KCMRH264AVCCodecLevel20; |
|
1788 newMimeType += _L8("644014"); |
|
1789 } |
|
1790 else if ( aMimeType.MatchF( _L8("*profile-level-id=644015*") ) != KErrNotFound ) |
|
1791 { |
|
1792 // high profile level 2.1 |
|
1793 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 2.1 requested."))); |
|
1794 videoCodecLevel = KCMRH264AVCCodecLevel21; |
|
1795 newMimeType += _L8("644015"); |
|
1796 } |
|
1797 else if ( aMimeType.MatchF( _L8("*profile-level-id=644016*") ) != KErrNotFound ) |
|
1798 { |
|
1799 // high profile level 2.2 |
|
1800 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 2.2 requested."))); |
|
1801 videoCodecLevel = KCMRH264AVCCodecLevel22; |
|
1802 newMimeType += _L8("644016"); |
|
1803 } |
|
1804 else if ( aMimeType.MatchF( _L8("*profile-level-id=64401E*") ) != KErrNotFound ) |
|
1805 { |
|
1806 // high profile level 3 |
|
1807 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 3 requested."))); |
|
1808 videoCodecLevel = KCMRH264AVCCodecLevel30; |
|
1809 newMimeType += _L8("64401E"); |
|
1810 } |
|
1811 else if ( aMimeType.MatchF( _L8("*profile-level-id=64401F*") ) != KErrNotFound ) |
|
1812 { |
|
1813 // high profile level 3.1 |
|
1814 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 3.1 requested."))); |
|
1815 videoCodecLevel = KCMRH264AVCCodecLevel31; |
|
1816 newMimeType += _L8("64401F"); |
|
1817 } |
|
1818 else if ( aMimeType.MatchF( _L8("*profile-level-id=644020*") ) != KErrNotFound ) |
|
1819 { |
|
1820 // high profile level 3.2 |
|
1821 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 3.2 requested."))); |
|
1822 videoCodecLevel = KCMRH264AVCCodecLevel32; |
|
1823 newMimeType += _L8("644020"); |
|
1824 } |
|
1825 else if ( aMimeType.MatchF( _L8("*profile-level-id=644028*") ) != KErrNotFound ) |
|
1826 { |
|
1827 // high profile level 4 |
|
1828 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 4 requested."))); |
|
1829 videoCodecLevel = KCMRH264AVCCodecLevel40; |
|
1830 newMimeType += _L8("644028"); |
|
1831 } |
|
1832 else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound ) |
|
1833 { |
|
1834 // no other profile-level ids supported |
|
1835 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported profile-level requested."))); |
|
1836 User::Leave(KErrNotSupported); |
|
1837 } |
|
1838 else |
|
1839 { |
|
1840 // Default is level 1 |
|
1841 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, no profile requested - defaulting to 1."))); |
|
1842 videoCodecLevel = KCMRH264AVCCodecLevel10; |
|
1843 newMimeType += _L8("42800A"); |
|
1844 } |
|
1845 |
|
1846 // recreate the codec data object |
|
1847 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC recreating codecdata."))); |
|
1848 delete iVideoCodecData; |
|
1849 iVideoCodecData = NULL; |
|
1850 iVideoCodecData = new (ELeave) CCMRVideoCodecDataH264AVC(videoCodecLevel); |
|
1851 } |
|
1852 else |
|
1853 { |
|
1854 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() Unknown mimetype requested."))); |
|
1855 // unknown mimetype |
|
1856 } |
|
1857 } |
|
1858 } |
|
1859 } |
|
1860 |
|
1861 // successfully interpreted the input mime type |
|
1862 if ( newMimeType != iMimeType ) |
|
1863 { |
|
1864 iMimeType = newMimeType; //copy the contents |
|
1865 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() new supported video codec requested - updating available encoders."))); |
|
1866 iAvailableVideoEncoders.Reset(); |
|
1867 if ( iPreferredEncoderUID != KNullUid ) |
|
1868 {// We have preferred encoder UID from client - override encoder search and use it instead. |
|
1869 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using API user encoder: %d "), iPreferredEncoderUID.iUid)); |
|
1870 iAvailableVideoEncoders.AppendL(iPreferredEncoderUID); |
|
1871 } |
|
1872 else if ( iConfig && |
|
1873 ( iConfig->IsICMConfigDataAvailable() ) && |
|
1874 ( iConfig->VideoQualitySettings().iVideoEncoderUID != KNullUid ) ) |
|
1875 {// Video quality set has set UID value - override encoder search and use it instead. |
|
1876 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using ICM config encoder: %d "), iPreferredEncoderUID.iUid)); |
|
1877 iAvailableVideoEncoders.AppendL(iPreferredEncoderUID); |
|
1878 } |
|
1879 else |
|
1880 { |
|
1881 iDevVideoRec->FindEncodersL(iMimeType, 0 /* aPreProc */, iAvailableVideoEncoders, EFalse ); |
|
1882 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() search found %d encoder(s)"), iAvailableVideoEncoders.Count() )); |
|
1883 } |
|
1884 iConfig->SetVideoCodec(iMimeType); |
|
1885 iConfig->SetVideoPixelAspectRatio(numerator, denominator); |
|
1886 |
|
1887 UpdateSupportedVideoFrameSizesRates(); |
|
1888 |
|
1889 // user has to call this->PrepareL() now that a setting has been changed !!! |
|
1890 // allow to start recording only when the state is "EReadyToRecord" |
|
1891 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() codec set, prepare needed before recording."))); |
|
1892 SetState(EStateOpen); |
|
1893 DoSendEventToClient( KCMRPrepareNeeded, iErrorCode ); // use iErrorCode in case we had stored error; it may be KErrNone too |
|
1894 iErrorCode = KErrNone; |
|
1895 } |
|
1896 |
|
1897 PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() out"))); |
|
1898 } |
|
1899 |
|
1900 // ----------------------------------------------------------------------------- |
|
1901 // CCMRVideoRecorder::GetVideoCodec |
|
1902 // Get the used video codec. |
|
1903 // (other items were commented in a header). |
|
1904 // ----------------------------------------------------------------------------- |
|
1905 // |
|
1906 void CCMRVideoRecorder::GetVideoCodecL( TDes8& aVideoMimeType ) const |
|
1907 { |
|
1908 aVideoMimeType = iMimeType; |
|
1909 } |
|
1910 |
|
1911 |
|
1912 // --------------------------------------------------------- |
|
1913 // CCMRVideoRecorder::SetTargetBitRateL |
|
1914 // Sets new target bitrate |
|
1915 // (other items were commented in a header). |
|
1916 // --------------------------------------------------------- |
|
1917 // |
|
1918 void CCMRVideoRecorder::SetTargetBitRateL(TInt aBitRate) |
|
1919 { |
|
1920 PRINT((_L("CCMRVideoRecorder::SetTargetBitRate, aBitrate = % d"),aBitRate)); |
|
1921 |
|
1922 if ( aBitRate == KMMFVariableVideoBitRate ) |
|
1923 { |
|
1924 // Variable rate requested; normalize the bit-rate (temporarily only in this function) |
|
1925 // but set a mode |
|
1926 aBitRate = iVideoCodecData->MaxBitRate(); |
|
1927 iBitRateMode = EBitRateVariable; |
|
1928 } |
|
1929 else |
|
1930 { |
|
1931 iBitRateMode = EBitRateConstant; |
|
1932 } |
|
1933 |
|
1934 // check that values are reasonable; check max bitrate only when the level is expected to be used for MMS |
|
1935 if ( (aBitRate < KCMRMinAcceptedBitRate) || ((iVideoCodecData->LevelForMMS()) && (aBitRate > iVideoCodecData->MaxBitRate())) ) |
|
1936 { |
|
1937 PRINT((_L("CCMRVideoRecorder::SetTargetBitRateL() illegal bitrate"))); |
|
1938 User::Leave(KErrArgument); |
|
1939 } |
|
1940 |
|
1941 // call base class implementation |
|
1942 CCMRRecorderBase::SetTargetBitRateL(aBitRate); |
|
1943 |
|
1944 // inform the max bitrate to the sink |
|
1945 User::LeaveIfError( iOutput->SetMaxVideoBitRate( aBitRate ) ); |
|
1946 |
|
1947 //inform the estimated average bitrate to sink; use a HW-specific scaler to estimate the average |
|
1948 TReal videoBitrateScaler = 0; |
|
1949 if ( iConfig ) |
|
1950 { |
|
1951 videoBitrateScaler = iConfig->PluginSettings().iCMRAvgVideoBitRateScaler; |
|
1952 } |
|
1953 |
|
1954 // make sure we never get scaler value 0 (ends up Div0 error) |
|
1955 if ( videoBitrateScaler == 0 ) |
|
1956 { |
|
1957 videoBitrateScaler = KCMRAvgVideoBitRateScaler; |
|
1958 } |
|
1959 |
|
1960 TInt br = static_cast<TInt>(aBitRate*videoBitrateScaler); |
|
1961 User::LeaveIfError( iOutput->SetAverageVideoBitRate( br ) ); |
|
1962 |
|
1963 if ( StateRequiresDynamicSetting() ) |
|
1964 { |
|
1965 // we have prepared => new value must be given via dynamic methods |
|
1966 FillRateControlOptions( iRateControlOptions ); |
|
1967 iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported |
|
1968 } |
|
1969 else |
|
1970 { |
|
1971 // we are not recording or prepared => value will be given forward in prepare |
|
1972 } |
|
1973 } |
|
1974 |
|
1975 |
|
1976 // --------------------------------------------------------- |
|
1977 // CCMRVideoRecorder::TargetBitRateL |
|
1978 // Gets current target bitrate |
|
1979 // (other items were commented in a header). |
|
1980 // --------------------------------------------------------- |
|
1981 // |
|
1982 void CCMRVideoRecorder::TargetBitRateL(TInt& aBitRate) |
|
1983 { |
|
1984 PRINT((_L("CCMRVideoRecorder::TargetBitRate"))); |
|
1985 |
|
1986 |
|
1987 if ( iBitRateMode == EBitRateConstant ) |
|
1988 { |
|
1989 aBitRate = iTargetBitRate; |
|
1990 } |
|
1991 else |
|
1992 { |
|
1993 aBitRate = KMMFVariableVideoBitRate; |
|
1994 } |
|
1995 } |
|
1996 |
|
1997 |
|
1998 // --------------------------------------------------------- |
|
1999 // CCMRVideoRecorder::SetFrameSizeL |
|
2000 // Sets new input & output frame size |
|
2001 // (other items were commented in a header). |
|
2002 // --------------------------------------------------------- |
|
2003 // |
|
2004 void CCMRVideoRecorder::SetFrameSizeL(const TSize& aSize) |
|
2005 { |
|
2006 |
|
2007 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL(), In, size: %dx%d"), aSize.iWidth, aSize.iHeight )); |
|
2008 |
|
2009 // allow settings only when in "open" or "readytorecord" states |
|
2010 if ( ( State() != EStateOpen ) && ( State() != EStateReadyToRecord ) ) |
|
2011 { |
|
2012 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() wrong state"))); |
|
2013 User::Leave(KErrNotReady); |
|
2014 } |
|
2015 |
|
2016 // check that size is acceptable |
|
2017 if ( !iVideoCodecData->MaxFrameSize( aSize ) ) |
|
2018 { |
|
2019 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() illegal frame size"))); |
|
2020 User::Leave(KErrArgument);//could be also KErrNotSupported |
|
2021 } |
|
2022 |
|
2023 TSize size; |
|
2024 TInt i = 0; |
|
2025 TInt j = 0; |
|
2026 TInt k = 0; |
|
2027 |
|
2028 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() looking match for frame size: %d x %d from camera"), aSize.iWidth, aSize.iHeight )); |
|
2029 |
|
2030 // Some explanation of the logic here. Camera API must support the same rates for all formats, since there |
|
2031 // is just a single variable in the info class to check the number of rates. |
|
2032 // But the indices may differ and that's why we need enumerations |
|
2033 if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV420Planar ) |
|
2034 { |
|
2035 // check YUV420 planar |
|
2036 for ( i = 0; i < iCameraInfo.iNumVideoFrameSizesSupported; i++ ) |
|
2037 { |
|
2038 iSource->EnumerateVideoFrameSizes(size, i, CCamera::EFormatYUV420Planar); |
|
2039 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV420Planar %d x %d found from camera"), size.iWidth, size.iHeight )); |
|
2040 |
|
2041 if ( size == aSize ) |
|
2042 { |
|
2043 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV420Planar %d x %d Matched."), size.iWidth, size.iHeight )); |
|
2044 iSizeIndex420 = i; |
|
2045 break; |
|
2046 } |
|
2047 } |
|
2048 } |
|
2049 else |
|
2050 { |
|
2051 i = iCameraInfo.iNumVideoFrameSizesSupported; |
|
2052 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera doesn't support EFormatYUV420Planar"))); |
|
2053 } |
|
2054 |
|
2055 if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV422 ) |
|
2056 { |
|
2057 // check YUV422 interleaved |
|
2058 for ( j = 0; j < iCameraInfo.iNumVideoFrameSizesSupported; j++ ) |
|
2059 { |
|
2060 iSource->EnumerateVideoFrameSizes(size, j, CCamera::EFormatYUV422 ); |
|
2061 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV422 %d x %d found from camera"), size.iWidth, size.iHeight )); |
|
2062 |
|
2063 if ( size == aSize ) |
|
2064 { |
|
2065 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV422 %d x %d Matched."), size.iWidth, size.iHeight )); |
|
2066 iSizeIndex422 = j; |
|
2067 break; |
|
2068 } |
|
2069 } |
|
2070 } |
|
2071 else |
|
2072 { |
|
2073 j = iCameraInfo.iNumVideoFrameSizesSupported; |
|
2074 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera doesn't support EFormatYUV422"))); |
|
2075 } |
|
2076 |
|
2077 // Search if we have direct capture encoder available -> no need to care about camera supported sizes. |
|
2078 if ( iAvailableVideoFrameSizesRates.Count() ) |
|
2079 { |
|
2080 // check direct capture encoder size array |
|
2081 for ( k = 0; k < iAvailableVideoFrameSizesRates.Count(); k++ ) |
|
2082 { |
|
2083 // All target resolutions that are below higher resolution found from encoders are accepted. |
|
2084 if ( (iAvailableVideoFrameSizesRates[k].iPictureSize.iWidth >= aSize.iWidth) && |
|
2085 (iAvailableVideoFrameSizesRates[k].iPictureSize.iHeight >= aSize.iHeight) ) |
|
2086 { |
|
2087 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() DirectCapture encoder %d x %d Matched."), aSize.iWidth, aSize.iHeight )); |
|
2088 iSizeIndexDCEncoder = k; |
|
2089 break; |
|
2090 } |
|
2091 } |
|
2092 } |
|
2093 else |
|
2094 { |
|
2095 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() no directcapture encoder available for given size."))); |
|
2096 } |
|
2097 |
|
2098 if ( (i == iCameraInfo.iNumVideoFrameSizesSupported) && |
|
2099 (j == iCameraInfo.iNumVideoFrameSizesSupported) && |
|
2100 (k == iAvailableVideoFrameSizesRates.Count()) ) |
|
2101 { |
|
2102 // Requested size not supported by camera API or the directcapture encoder |
|
2103 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL(), Camera and/or direct capture encoder does not support this resolution"))); |
|
2104 User::Leave(KErrNotSupported); |
|
2105 } |
|
2106 |
|
2107 iFrameSize = aSize; |
|
2108 iOutput->SetVideoFrameSize(aSize); |
|
2109 |
|
2110 // user has to call this->PrepareL() now that a setting has been changed !!! |
|
2111 // allow to start recording only when the state is "EReadyToRecord" |
|
2112 SetState(EStateOpen); |
|
2113 DoSendEventToClient( KCMRPrepareNeeded, iErrorCode ); // use iErrorCode in case we had stored error; it may be KErrNone too |
|
2114 iErrorCode = KErrNone; |
|
2115 |
|
2116 // update MaxFrameRate to new frame size |
|
2117 iMaxFrameRate4GivenSize = iVideoCodecData->MaxFrameRate( iFrameSize ); |
|
2118 |
|
2119 // framerate is tied with framesize; if it was set before update it accordingly |
|
2120 // this may be overridden by user e.g. with a higher rate; this sets the rates <= previous encoding rate |
|
2121 if ( (iRateIndex420 >= 0) || (iRateIndex422 >= 0) || (iRateIndexDCEncoder >= 0) ) |
|
2122 { |
|
2123 // must use iEncodingFrameRate, since other rates may raise encoding rate higher than wanted; this allows camera frame rate to be higher |
|
2124 TInt success = KErrNone; |
|
2125 do |
|
2126 { |
|
2127 TRAP( success, SetFrameRateL( iEncodingFrameRate )); |
|
2128 if ( success == KErrNone ) |
|
2129 { |
|
2130 break; |
|
2131 } |
|
2132 // if picture size was increased, we may need to decrease framerate |
|
2133 iEncodingFrameRate--; |
|
2134 } while ( iEncodingFrameRate > 0 ); |
|
2135 if ( success != KErrNone ) |
|
2136 { |
|
2137 // This framesize - framerate combination not possible |
|
2138 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() illegal frame size - rate combination"))); |
|
2139 User::Leave(success); |
|
2140 } |
|
2141 } |
|
2142 |
|
2143 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL(), Out"))); |
|
2144 } |
|
2145 |
|
2146 |
|
2147 // --------------------------------------------------------- |
|
2148 // CCMRVideoRecorder::FrameSizeL |
|
2149 // Gets current frame size |
|
2150 // (other items were commented in a header). |
|
2151 // --------------------------------------------------------- |
|
2152 // |
|
2153 void CCMRVideoRecorder::FrameSizeL(TSize& aSize) const |
|
2154 { |
|
2155 PRINT((_L("CCMRVideoRecorder::FrameSizeL()"))); |
|
2156 aSize = iFrameSize; |
|
2157 } |
|
2158 |
|
2159 |
|
2160 // --------------------------------------------------------- |
|
2161 // CCMRVideoRecorder::SetFrameRateL |
|
2162 // Sets new target frame rate |
|
2163 // (other items were commented in a header). |
|
2164 // --------------------------------------------------------- |
|
2165 // |
|
2166 void CCMRVideoRecorder::SetFrameRateL(TReal32 aFrameRate) |
|
2167 { |
|
2168 PRINT((_L("CCMRVideoRecorder::SetFrameRate(), requested rate %f"), aFrameRate)); |
|
2169 |
|
2170 // Size has to be set before setting frame rate !!! |
|
2171 if ( (State() == EStateNone) || ((iSizeIndex420 < 0) && (iSizeIndex422 < 0) && (iSizeIndexDCEncoder < 0)) ) |
|
2172 { |
|
2173 PRINT((_L("CCMRVideoRecorder::SetFrameRateL() wrong state"))); |
|
2174 User::Leave(KErrNotReady); |
|
2175 } |
|
2176 |
|
2177 // check that values are reasonable |
|
2178 if ( (aFrameRate <= 0) || (aFrameRate > iVideoCodecData->MaxFrameRate(iFrameSize)) ) |
|
2179 { |
|
2180 PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() illegal frame rate"))); |
|
2181 User::Leave(KErrArgument); |
|
2182 } |
|
2183 |
|
2184 // encoding frame rate is always the requested one |
|
2185 if ( aFrameRate <= iMaxFrameRate4GivenSize ) // actually iMaxFrameRate4GivenSize is valid only after prepare |
|
2186 { |
|
2187 // requested rate looks ok |
|
2188 iEncodingFrameRate = aFrameRate; |
|
2189 } |
|
2190 else if ( iEncodingFrameRate < iMaxFrameRate4GivenSize ) |
|
2191 { |
|
2192 // too high rate requested, but the current rate is still lower than max possible, so we can set the rate higher anyway |
|
2193 iEncodingFrameRate = static_cast<TReal32>(iMaxFrameRate4GivenSize); |
|
2194 PRINT((_L("CCMRVideoRecorder::SetFrameRate(), requested rate is too high for the used encoder, but set it to this rate: %f"), iMaxFrameRate4GivenSize)); |
|
2195 } |
|
2196 else |
|
2197 { |
|
2198 // The change has no effect; the used encoder is already set to max possible rate and can't be configured for the requested rate |
|
2199 // for now camera api capability is not checked; e.g. if H.263 level is 20 => framerate could be 30fps for QCIF but if max encoder |
|
2200 // impl. rate is 10fps, we don't leave, but just ignore |
|
2201 PRINT((_L("CCMRVideoRecorder::SetFrameRate(), requested rate is too high for the used encoder, max rate %f"), iMaxFrameRate4GivenSize)); |
|
2202 return; |
|
2203 } |
|
2204 |
|
2205 if ( StateRequiresDynamicSetting() ) |
|
2206 { |
|
2207 // we are running, change only encoding rate now |
|
2208 |
|
2209 // store the requested rate also, to be taken into use in the next prepare |
|
2210 if ( !iNightMode ) |
|
2211 { |
|
2212 iRequestedFrameRate = aFrameRate; |
|
2213 } |
|
2214 |
|
2215 if ( iEncodingFrameRate > iSourceFrameRate ) |
|
2216 { |
|
2217 // can't be higher than capture rate, limit it |
|
2218 iEncodingFrameRate = iSourceFrameRate; |
|
2219 } |
|
2220 |
|
2221 // set the rate control params |
|
2222 FillRateControlOptions( iRateControlOptions ); |
|
2223 iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported |
|
2224 } |
|
2225 else |
|
2226 { |
|
2227 // we are in initialization phase, change also camera rate |
|
2228 |
|
2229 TReal32 rate; |
|
2230 TInt i; |
|
2231 |
|
2232 iRateIndex420 = -1; //reset just in case, needed to determine if the loop below was successful |
|
2233 iRateIndex422 = -1; //reset just in case, needed to determine if the loop below was successful |
|
2234 iRateIndexDCEncoder = -1; |
|
2235 |
|
2236 // Some explanation of the logic here. Camera API must support the same rates for all formats, since there |
|
2237 // is just a single variable in the info class to check the number of rates. |
|
2238 // But the indices may differ and that's why we need enumerations |
|
2239 // Since we prefer YUV422, it can override the member variables. |
|
2240 |
|
2241 if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV420Planar ) |
|
2242 { |
|
2243 // check YUV420 planar |
|
2244 |
|
2245 // search for an exact match from camera's supported rates |
|
2246 for ( i = 0; i < iCameraInfo.iNumVideoFrameRatesSupported; i++ ) |
|
2247 { |
|
2248 |
|
2249 iSource->EnumerateVideoFrameRates(rate, i, CCamera::EFormatYUV420Planar, iSizeIndex420, |
|
2250 CCamera::EExposureAuto); |
|
2251 |
|
2252 if ( rate == aFrameRate ) |
|
2253 { |
|
2254 iRateIndex420 = i; |
|
2255 iSourceFrameRate = aFrameRate; |
|
2256 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
2257 PRINT((_L("CCMRVideoRecorder::SetFrameRate, asked framerate found"))); |
|
2258 break; |
|
2259 } |
|
2260 else if ( rate > aFrameRate ) |
|
2261 { |
|
2262 // this is higher but could be used (encoder can match the rates) |
|
2263 // Check the other rates too if a better is found |
|
2264 iRateIndex420 = i; |
|
2265 iSourceFrameRate = rate; |
|
2266 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
2267 PRINT((_L("CCMRVideoRecorder::SetFrameRate, a higher source framerate found"))); |
|
2268 } |
|
2269 } |
|
2270 } |
|
2271 |
|
2272 if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV422 ) |
|
2273 { |
|
2274 // check YUV422 interleaved |
|
2275 |
|
2276 // search for an exact match from camera's supported rates |
|
2277 for ( i = 0; i < iCameraInfo.iNumVideoFrameRatesSupported; i++ ) |
|
2278 { |
|
2279 iSource->EnumerateVideoFrameRates(rate, i, CCamera::EFormatYUV422, iSizeIndex422, |
|
2280 CCamera::EExposureAuto); |
|
2281 |
|
2282 if ( rate == aFrameRate ) |
|
2283 { |
|
2284 iRateIndex422 = i; |
|
2285 iSourceFrameRate = aFrameRate; |
|
2286 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
2287 PRINT((_L("CCMRVideoRecorder::SetFrameRate, asked framerate found"))); |
|
2288 break; |
|
2289 } |
|
2290 else if ( rate > aFrameRate ) |
|
2291 { |
|
2292 // this is higher but could be used (encoder can match the rates) |
|
2293 // Check the other rates too if a better is found |
|
2294 iRateIndex422 = i; |
|
2295 iSourceFrameRate = rate; |
|
2296 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
2297 PRINT((_L("CCMRVideoRecorder::SetFrameRate, a higher source framerate found"))); |
|
2298 } |
|
2299 } |
|
2300 } |
|
2301 |
|
2302 if ( iAvailableVideoFrameSizesRates.Count() && (iSizeIndexDCEncoder >= 0) && (iSizeIndexDCEncoder < iAvailableVideoFrameSizesRates.Count()) ) |
|
2303 { |
|
2304 // check Direct capture encoder supported rates. |
|
2305 |
|
2306 // search for an exact match from encoders supported rates |
|
2307 for ( i = 0; i < iAvailableVideoFrameSizesRates.Count(); i++ ) |
|
2308 { |
|
2309 if ( (iAvailableVideoFrameSizesRates[i].iPictureRate == aFrameRate) && |
|
2310 (iAvailableVideoFrameSizesRates[i].iPictureSize == iAvailableVideoFrameSizesRates[iSizeIndexDCEncoder].iPictureSize) ) |
|
2311 { |
|
2312 iRateIndexDCEncoder = i; |
|
2313 iSizeIndexDCEncoder = i; |
|
2314 iSourceFrameRate = aFrameRate; |
|
2315 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
2316 PRINT((_L("CCMRVideoRecorder::SetFrameRate, asked framerate found"))); |
|
2317 break; |
|
2318 } |
|
2319 else if ( (iAvailableVideoFrameSizesRates[i].iPictureRate >= aFrameRate) && |
|
2320 (iAvailableVideoFrameSizesRates[i].iPictureSize.iWidth >= iAvailableVideoFrameSizesRates[iSizeIndexDCEncoder].iPictureSize.iWidth ) && |
|
2321 (iAvailableVideoFrameSizesRates[i].iPictureSize.iHeight >= iAvailableVideoFrameSizesRates[iSizeIndexDCEncoder].iPictureSize.iHeight ) ) |
|
2322 { |
|
2323 // this is higher but could be used (encoder can match the rates) |
|
2324 // Check the other rates too if a better is found |
|
2325 iRateIndexDCEncoder = i; |
|
2326 iSizeIndexDCEncoder = i; |
|
2327 iSourceFrameRate = aFrameRate; |
|
2328 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
2329 PRINT((_L("CCMRVideoRecorder::SetFrameRate, a higher source framerate found: %dx%d at %f"), iAvailableVideoFrameSizesRates[i].iPictureSize.iWidth, |
|
2330 iAvailableVideoFrameSizesRates[i].iPictureSize.iHeight, |
|
2331 iAvailableVideoFrameSizesRates[i].iPictureRate )); |
|
2332 } |
|
2333 } |
|
2334 } |
|
2335 |
|
2336 |
|
2337 if ( (iRateIndex420 < 0) && (iRateIndex422 < 0) && (iRateIndexDCEncoder < 0) ) |
|
2338 { |
|
2339 // there is no suitable frame rate available, not even a higher one, return error |
|
2340 PRINT((_L("CCMRVideoRecorder::SetFrameRate, no suitable framerate found from Camera API and/or direct capture encoder."))); |
|
2341 User::Leave(KErrNotSupported); |
|
2342 } |
|
2343 |
|
2344 // set to the actual rate to prevent trying set the rate again from PrepareL |
|
2345 iRequestedFrameRate = iSourceFrameRate; |
|
2346 |
|
2347 // user has to call this->PrepareL() now that a setting has been changed !!! |
|
2348 // allow to start recording only when the state is "EReadyToRecord" |
|
2349 if ( State() != EStateOpen ) |
|
2350 { |
|
2351 SetState(EStateOpen); |
|
2352 DoSendEventToClient( KCMRPrepareNeeded, iErrorCode ); // use iErrorCode in case we had stored error; it may be KErrNone too |
|
2353 iErrorCode = KErrNone; |
|
2354 } |
|
2355 } |
|
2356 } |
|
2357 |
|
2358 |
|
2359 // --------------------------------------------------------- |
|
2360 // CCMRVideoRecorder::FrameRateL |
|
2361 // Get the used encoding frame rate |
|
2362 // (other items were commented in a header). |
|
2363 // --------------------------------------------------------- |
|
2364 // |
|
2365 void CCMRVideoRecorder::FrameRateL(TReal32& aFrameRate) const |
|
2366 { |
|
2367 PRINT((_L("CCMRVideoRecorder::FrameRateL()"))); |
|
2368 aFrameRate = iEncodingFrameRate; |
|
2369 } |
|
2370 |
|
2371 |
|
2372 // --------------------------------------------------------- |
|
2373 // CCMRVideoRecorder::SetVideoCodingOptionsL |
|
2374 // Set misc video coding options |
|
2375 // (other items were commented in a header). |
|
2376 // --------------------------------------------------------- |
|
2377 // |
|
2378 void CCMRVideoRecorder::SetVideoCodingOptionsL(const TCCMRVideoCodingOptions& aOptions) |
|
2379 { |
|
2380 if ( ( State() != EStateOpen ) && ( State() != EStateReadyToRecord ) ) |
|
2381 { |
|
2382 PRINT((_L("CCMRVideoRecorder::SetVideoCodingOptionsL() wrong state"))); |
|
2383 User::Leave( KErrNotReady ); |
|
2384 } |
|
2385 if ( iMinRandomAccessPeriodInSeconds != KCMRUseDefault ) |
|
2386 { |
|
2387 iMinRandomAccessPeriodInSeconds = aOptions.iMinRandomAccessPeriodInSeconds; |
|
2388 } |
|
2389 |
|
2390 iVideoCodecData->SetVideoCodingOptionsL(aOptions); |
|
2391 } |
|
2392 |
|
2393 |
|
2394 // --------------------------------------------------------- |
|
2395 // CCMRVideoRecorder::SetVideoRateControlOptionsL |
|
2396 // Set video rate control options |
|
2397 // (other items were commented in a header). |
|
2398 // --------------------------------------------------------- |
|
2399 // |
|
2400 void CCMRVideoRecorder::SetVideoRateControlOptionsL(const TRateControlOptions& aOptions) |
|
2401 { |
|
2402 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() in"))); |
|
2403 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() TBitrateControlType iControl: %d"), aOptions.iControl)); |
|
2404 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iBitrate: %d"), aOptions.iBitrate)); |
|
2405 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iPictureQuality: %d"), aOptions.iPictureQuality)); |
|
2406 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iPictureRate: %f"), aOptions.iPictureRate)); |
|
2407 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iQualityTemporalTradeoff: %f"), aOptions.iQualityTemporalTradeoff)); |
|
2408 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iLatencyQualityTradeoff: %f"), aOptions.iLatencyQualityTradeoff)); |
|
2409 |
|
2410 if ( !StateRequiresDynamicSetting() ) |
|
2411 { |
|
2412 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() illegal state for dynamic settings"))); |
|
2413 User::Leave(KErrNotReady); |
|
2414 } |
|
2415 |
|
2416 // Handle new bitrate value: |
|
2417 if ( (aOptions.iBitrate < KCMRMinAcceptedBitRate) || ((iVideoCodecData->LevelForMMS()) && (aOptions.iBitrate > iVideoCodecData->MaxBitRate())) ) |
|
2418 {// check that values are reasonable; check max bitrate only when the level is expected to be used for MMS |
|
2419 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() illegal bitrate"))); |
|
2420 User::Leave(KErrArgument); |
|
2421 } |
|
2422 CCMRRecorderBase::SetTargetBitRateL(aOptions.iBitrate); |
|
2423 // inform the max bitrate to the sink |
|
2424 User::LeaveIfError( iOutput->SetMaxVideoBitRate( aOptions.iBitrate ) ); |
|
2425 //inform the estimated average bitrate to sink; use a HW-specific scaler to estimate the average |
|
2426 TReal videoBitrateScaler = 0; |
|
2427 if ( iConfig ) |
|
2428 { |
|
2429 videoBitrateScaler = iConfig->PluginSettings().iCMRAvgVideoBitRateScaler; |
|
2430 } |
|
2431 if ( videoBitrateScaler == 0 ) |
|
2432 {// make sure we never get scaler value 0 (ends up Div0 error) |
|
2433 videoBitrateScaler = KCMRAvgVideoBitRateScaler; |
|
2434 } |
|
2435 TInt br = static_cast<TInt>(aOptions.iBitrate*videoBitrateScaler); |
|
2436 User::LeaveIfError( iOutput->SetAverageVideoBitRate( br ) ); |
|
2437 |
|
2438 |
|
2439 //Handle new framerate value: |
|
2440 if ( (aOptions.iPictureRate <= 0) || (aOptions.iPictureRate > iVideoCodecData->MaxFrameRate(iFrameSize)) ) |
|
2441 {// check that values are reasonable |
|
2442 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() illegal frame rate, %f"), aOptions.iPictureRate)); |
|
2443 User::Leave(KErrArgument); |
|
2444 } |
|
2445 if ( aOptions.iPictureRate <= iMaxFrameRate4GivenSize ) // actually iMaxFrameRate4GivenSize is valid only after prepare |
|
2446 {// encoding frame rate is always the requested one |
|
2447 iEncodingFrameRate = aOptions.iPictureRate; // requested rate looks ok |
|
2448 } |
|
2449 else if ( iEncodingFrameRate < iMaxFrameRate4GivenSize ) |
|
2450 {// too high rate requested, but the current rate is still lower than max possible, so we can set the rate higher anyway |
|
2451 iEncodingFrameRate = static_cast<TReal32>(iMaxFrameRate4GivenSize); |
|
2452 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL(), requested rate is too high for the used encoder, but set it to this rate: %f"), iMaxFrameRate4GivenSize)); |
|
2453 } |
|
2454 if ( !iNightMode ) |
|
2455 {// store the requested rate also, to be taken into use in the next prepare |
|
2456 iRequestedFrameRate = aOptions.iPictureRate; |
|
2457 } |
|
2458 if ( iEncodingFrameRate > iSourceFrameRate ) |
|
2459 {// can't be higher than capture rate, limit it |
|
2460 iEncodingFrameRate = iSourceFrameRate; |
|
2461 } |
|
2462 |
|
2463 iRateControlOptions = aOptions; |
|
2464 iRateControlOptions.iPictureRate = iEncodingFrameRate; |
|
2465 if ( iDevVideoRec ) |
|
2466 { |
|
2467 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() settings stored and sending them to Devvideo."))); |
|
2468 iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported |
|
2469 } |
|
2470 else |
|
2471 { |
|
2472 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() no DevVideoRec! Leaving KErrNotReady -18"))); |
|
2473 User::Leave(KErrNotReady); |
|
2474 } |
|
2475 PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() out"))); |
|
2476 } |
|
2477 |
|
2478 // --------------------------------------------------------- |
|
2479 // CCMRVideoRecorder::GetVideoRateControlOptionsL |
|
2480 // Get video rate control options |
|
2481 // (other items were commented in a header). |
|
2482 // --------------------------------------------------------- |
|
2483 // |
|
2484 void CCMRVideoRecorder::GetVideoRateControlOptionsL(TRateControlOptions& aOptions) |
|
2485 { |
|
2486 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() in"))); |
|
2487 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() TBitrateControlType iControl: %d"), iRateControlOptions.iControl)); |
|
2488 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iBitrate: %d"), iRateControlOptions.iBitrate)); |
|
2489 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iPictureQuality: %d"), iRateControlOptions.iPictureQuality)); |
|
2490 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iPictureRate: %f"), iRateControlOptions.iPictureRate)); |
|
2491 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iQualityTemporalTradeoff: %f"), iRateControlOptions.iQualityTemporalTradeoff)); |
|
2492 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iLatencyQualityTradeoff: %f"), iRateControlOptions.iLatencyQualityTradeoff)); |
|
2493 |
|
2494 if ( !StateRequiresDynamicSetting() ) |
|
2495 { |
|
2496 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() illegal state for dynamic settings"))); |
|
2497 User::Leave(KErrNotReady); |
|
2498 } |
|
2499 aOptions = iRateControlOptions; |
|
2500 PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() out"))); |
|
2501 } |
|
2502 |
|
2503 |
|
2504 // --------------------------------------------------------- |
|
2505 // CCMRVideoRecorder::SetPreferredVideoEncoderL |
|
2506 // Set video encoder using its UID. Usage optional. |
|
2507 // (other items were commented in a header). |
|
2508 // --------------------------------------------------------- |
|
2509 // |
|
2510 void CCMRVideoRecorder::SetPreferredVideoEncoderL(TUid& aEncoder) |
|
2511 { |
|
2512 PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncoderL() in"))); |
|
2513 iPreferredEncoderUID = aEncoder; |
|
2514 |
|
2515 if ( iPreferredEncoderUID != KNullUid ) |
|
2516 {// We have preferred encoder UID from client - override encoder search and use it instead. |
|
2517 PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncoderL() skipping encoder search. Using API user encoder: %d "), iPreferredEncoderUID.iUid)); |
|
2518 iAvailableVideoEncoders.Reset(); |
|
2519 iAvailableVideoEncoders.AppendL(iPreferredEncoderUID); |
|
2520 UpdateSupportedVideoFrameSizesRates(); |
|
2521 } |
|
2522 |
|
2523 PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncoderL() out"))); |
|
2524 } |
|
2525 |
|
2526 // --------------------------------------------------------- |
|
2527 // CCMRVideoRecorder::SetPreferredVideoEncapsulationL |
|
2528 // Set video encoder output format encapsulation. Usage optional. |
|
2529 // (other items were commented in a header). |
|
2530 // --------------------------------------------------------- |
|
2531 // |
|
2532 void CCMRVideoRecorder::SetPreferredVideoEncapsulationL(TVideoDataUnitEncapsulation aCapsulation) |
|
2533 { |
|
2534 PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncapsulationL() in"))); |
|
2535 iPreferredEncapsulation = aCapsulation; |
|
2536 iPreferredEncapsulationSet = ETrue; |
|
2537 PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncapsulationL() out"))); |
|
2538 } |
|
2539 |
|
2540 // --------------------------------------------------------- |
|
2541 // CCMRVideoRecorder::SetSegmentTargetSize |
|
2542 // Set video segment target size |
|
2543 // (other items were commented in a header). |
|
2544 // --------------------------------------------------------- |
|
2545 // |
|
2546 void CCMRVideoRecorder::SetSegmentTargetSizeL(TUint aLayer, TUint aSizeBytes, TUint aSizeMacroblocks) |
|
2547 { |
|
2548 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() in"))); |
|
2549 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() aLayer: %d"), aLayer)); |
|
2550 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() aSizeBytes: %d"), aSizeBytes)); |
|
2551 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() aSizeMacroblocks: %d"), aSizeMacroblocks)); |
|
2552 |
|
2553 if ( !StateRequiresDynamicSetting() ) |
|
2554 { |
|
2555 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() illegal state for dynamic settings"))); |
|
2556 User::Leave(KErrNotReady); |
|
2557 } |
|
2558 |
|
2559 if ( iDevVideoRec ) |
|
2560 { |
|
2561 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() sending SetSegmentTargetSize to Devvideo."))); |
|
2562 iDevVideoRec->SetSegmentTargetSize(aLayer, aSizeBytes, aSizeMacroblocks); // only base layer (layer 0) supported |
|
2563 } |
|
2564 else |
|
2565 { |
|
2566 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() no DevVideoRec! Leaving KErrNotReady -18"))); |
|
2567 User::Leave(KErrNotReady); |
|
2568 } |
|
2569 PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() out"))); |
|
2570 } |
|
2571 |
|
2572 // --------------------------------------------------------- |
|
2573 // CCMRVideoRecorder::AdjustTimeStampsL |
|
2574 // Adjust time stamps of video |
|
2575 // (other items were commented in a header). |
|
2576 // --------------------------------------------------------- |
|
2577 // |
|
2578 void CCMRVideoRecorder::AdjustTimeStampsL(const TInt aAdjustmentMs) |
|
2579 { |
|
2580 if ( State() != EStateRecording ) |
|
2581 { |
|
2582 PRINT((_L("CCMRVideoRecorder::AdjustTimeStampsL() wrong state"))); |
|
2583 User::Leave( KErrNotReady ); |
|
2584 } |
|
2585 |
|
2586 iAdjustmentTimeUs = TInt64( aAdjustmentMs * 1000 ); |
|
2587 |
|
2588 PRINT((_L("CCMRVideoRecorder::AdjustTimeStampsL() by %d us"),I64INT(iAdjustmentTimeUs))); |
|
2589 } |
|
2590 |
|
2591 |
|
2592 // --------------------------------------------------------- |
|
2593 // CCMRVideoRecorder::MvsoReserveComplete |
|
2594 // Called by camera API when camera API has been reserved |
|
2595 // for exclusive use |
|
2596 // (other items were commented in a header). |
|
2597 // --------------------------------------------------------- |
|
2598 // |
|
2599 void CCMRVideoRecorder::MvsoReserveComplete(TInt aError) |
|
2600 { |
|
2601 PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() in"))); |
|
2602 |
|
2603 // Should not be called, if we use direct capture mode |
|
2604 if (iDirectCapture) |
|
2605 { |
|
2606 VRASSERT(0); |
|
2607 } |
|
2608 |
|
2609 // need to set this already here if returns unsuccesfully, to enable error handling when encoder init completes |
|
2610 iSourceInitComplete = ETrue; |
|
2611 |
|
2612 if ( iEncoderInitComplete && (iErrorCode != KErrNone) ) |
|
2613 { |
|
2614 // there was an error in the encoder initialisation, but the reporting was |
|
2615 // waiting for the completion of the source initialisation => report it now |
|
2616 PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() but error in video encoder: %d"), iErrorCode)); |
|
2617 DoSendEventToClient( KCMREncoderInitError, iErrorCode ); |
|
2618 iErrorCode = KErrNone; |
|
2619 return; |
|
2620 } |
|
2621 |
|
2622 if ( aError != KErrNone ) |
|
2623 { |
|
2624 if ( iEncoderInitComplete ) |
|
2625 { |
|
2626 PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() with error: %d"), aError)); |
|
2627 DoSendEventToClient( KCMRCameraReserveError, aError ); |
|
2628 } |
|
2629 else |
|
2630 { |
|
2631 // report only when encoder is completed too |
|
2632 PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() with error: %d, but must wait for encoder init completion"), aError)); |
|
2633 iErrorCode = aError; |
|
2634 } |
|
2635 return; |
|
2636 } |
|
2637 |
|
2638 TInt error; |
|
2639 |
|
2640 TRAP(error, iSource->PrepareCaptureL(iVideoFormat, iSizeIndex, iRateIndex, |
|
2641 iNumCameraBuffers, KCMRNumFramesInCameraBuffer)); |
|
2642 |
|
2643 PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() camera prepared, error %d"),error)); |
|
2644 if ( error != KErrNone ) |
|
2645 { |
|
2646 if ( iEncoderInitComplete ) |
|
2647 { |
|
2648 DoSendEventToClient( KCMRCameraPrepareError, error ); |
|
2649 } |
|
2650 else |
|
2651 { |
|
2652 // report only when encoder is completed too |
|
2653 iErrorCode = error; |
|
2654 } |
|
2655 return; |
|
2656 } |
|
2657 |
|
2658 |
|
2659 if ( iEncoderInitComplete ) |
|
2660 { |
|
2661 SetState(EStateReadyToRecord); |
|
2662 |
|
2663 // everything ok, inform observer that we are prepared. |
|
2664 DoSendEventToClient( KCMRPrepareComplete, KErrNone ); |
|
2665 } |
|
2666 |
|
2667 PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() out"))); |
|
2668 } |
|
2669 |
|
2670 |
|
2671 // --------------------------------------------------------- |
|
2672 // CCMRVideoRecorder::MvsoFrameBufferReady |
|
2673 // Called by camera API when a frame (or several frames) |
|
2674 // has been captured |
|
2675 // (other items were commented in a header). |
|
2676 // --------------------------------------------------------- |
|
2677 // |
|
2678 void CCMRVideoRecorder::MvsoFrameBufferReady(MFrameBuffer* aFrameBuffer, TInt aError) |
|
2679 { |
|
2680 // Should not be called, if we use direct capture mode |
|
2681 if (iDirectCapture) |
|
2682 { |
|
2683 VRASSERT(0); |
|
2684 } |
|
2685 |
|
2686 if ( aError != KErrNone || aFrameBuffer == NULL ) |
|
2687 { |
|
2688 // some errors, inform observer and return |
|
2689 DoSendEventToClient( KCMRCameraCaptureError, aError ); |
|
2690 if ( aFrameBuffer ) |
|
2691 { |
|
2692 // in case of errors, aFrameBuffer may be NULL |
|
2693 aFrameBuffer->Release(); |
|
2694 } |
|
2695 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady with error %d"), aError)); |
|
2696 return; |
|
2697 } |
|
2698 |
|
2699 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady in %x, frame & time & systemdrift\t%d\t%d\t%d"),aFrameBuffer, |
|
2700 aFrameBuffer->iIndexOfFirstFrameInBuffer, |
|
2701 I64INT(aFrameBuffer->iElapsedTime.Int64()), |
|
2702 I64INT(iSystemClockDelta.Int64()) |
|
2703 )); |
|
2704 |
|
2705 #ifdef VIDEO_FILE_OUTPUT |
|
2706 |
|
2707 // Write the frame to a file for testing purposes |
|
2708 TInt error = KErrNone; |
|
2709 TRAPD(error2, error = iOutputFile.Write( *(aFrameBuffer->DataL(0)) )); |
|
2710 |
|
2711 // release frame |
|
2712 aFrameBuffer->Release(); |
|
2713 |
|
2714 if (error != KErrNone || error2 != KErrNone) |
|
2715 { |
|
2716 DoSendEventToClient( KCMRRunTimeError, error ); |
|
2717 } |
|
2718 |
|
2719 |
|
2720 #else |
|
2721 // the real deal |
|
2722 |
|
2723 if ( (State() != EStateRecording) || (iErrorCode != KErrNone) ) |
|
2724 { |
|
2725 // we are paused or stopping or there was an error => return the framebuffer immediately |
|
2726 // if system clock has been changed during pause take that account in future frame timestamp calculations. |
|
2727 if ( (((aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) < iLatestAbsoluteTimeStamp.Int64()) || |
|
2728 ((aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) > (iLatestAbsoluteTimeStamp.Int64() + 2*iSourceFrameInterval))) && |
|
2729 (aFrameBuffer->iIndexOfFirstFrameInBuffer == iPreviousCameraFrameIndex + 1) ) |
|
2730 { |
|
2731 // something has changed system clock during pause, add cumulatively to drift delta. |
|
2732 iSystemClockDelta = (iLatestAbsoluteTimeStamp.Int64() + iSourceFrameInterval) - |
|
2733 (aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) |
|
2734 + iSystemClockDelta.Int64(); |
|
2735 |
|
2736 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() System time change: aFrameBuffer->iElapsedTime = %d, iSystemClockDelta = %d, iLatestAbsoluteTimeStamp = %d, iSourceFrameInterval = %d"), |
|
2737 I64INT(aFrameBuffer->iElapsedTime.Int64()), |
|
2738 I64INT(iSystemClockDelta.Int64()), |
|
2739 I64INT(iLatestAbsoluteTimeStamp.Int64()), |
|
2740 iSourceFrameInterval)); |
|
2741 } |
|
2742 |
|
2743 iLatestAbsoluteTimeStamp = aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64(); |
|
2744 iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer; |
|
2745 aFrameBuffer->Release(); |
|
2746 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() not recording, skip this one"))); |
|
2747 return; |
|
2748 } |
|
2749 |
|
2750 |
|
2751 #if ( defined (__WINS__) || defined (__WINSCW__) ) |
|
2752 if ( iEncoderInputQueueLength > 0 ) |
|
2753 { |
|
2754 // Too many pictures already in the encoder's input queue - skip this one. In Wins the criteria is more strict since performance is lower |
|
2755 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() - encoder already has one frame under processing, skip this one"))); |
|
2756 iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer; |
|
2757 aFrameBuffer->Release(); |
|
2758 return; |
|
2759 } |
|
2760 #else |
|
2761 if ( iEncoderInputQueueLength >= KCMRMaxPreEncoderBufferPictures ) |
|
2762 { |
|
2763 // Too many pictures already in the encoder's input queue - skip this one |
|
2764 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() - Encoder input/output queue(s) already full, must skip a captured frame"))); |
|
2765 iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer; |
|
2766 aFrameBuffer->Release(); |
|
2767 return; |
|
2768 } |
|
2769 #endif |
|
2770 |
|
2771 // Regulate timestamp to avoid too small or too large variations |
|
2772 |
|
2773 // use frame index instead of associated buffer timestamp, since timestamps may be |
|
2774 // less accurate and may cause rounding problems when converted to e.g. H.263 TRs |
|
2775 TInt64 frameTimeStamp; |
|
2776 frameTimeStamp = TInt64((aFrameBuffer->iIndexOfFirstFrameInBuffer - iDriftFrameSkipCount + iAddedFrameDurationCount) * 1E6/iSourceFrameRate + 0.5); // use accurate division here since rounded value in multiplication multiplies also the rounding error |
|
2777 |
|
2778 // However, relying purely on frameindex causes drifting if the used source framerate value here is not exactly |
|
2779 // the camera input rate. Hence we need to do some adjustments. |
|
2780 // The frameindex may also be exclude skipped frames, but that should considered a bug in camera drivers, although the Camera API spec is not fully unambiguous about this |
|
2781 TInt64 expectedNewTimeStamp; |
|
2782 if ( iNumberOfCapturedFrames > 0 ) |
|
2783 { |
|
2784 expectedNewTimeStamp = iLatestAbsoluteTimeStamp.Int64() + iSourceFrameInterval; |
|
2785 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), expectedNewTimeStamp (abs)\t%d\t"),I64INT(expectedNewTimeStamp))); |
|
2786 } |
|
2787 else |
|
2788 { |
|
2789 //first frame |
|
2790 expectedNewTimeStamp = 0; |
|
2791 iDriftFrameSkipCount = 0; |
|
2792 iAddedFrameDurationCount = 0; |
|
2793 iPreviousCameraFrameIndex = 0; |
|
2794 } |
|
2795 |
|
2796 TInt frameDropCount = aFrameBuffer->iIndexOfFirstFrameInBuffer - iPreviousCameraFrameIndex - 1; |
|
2797 iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer; |
|
2798 // |
|
2799 // Handle case where camera has dropped frames. |
|
2800 // |
|
2801 if ( frameDropCount > 0 ) |
|
2802 {// Camera dropped frame |
|
2803 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), Camera dropped %d frame(s), drift from expected: \t%d\t"), |
|
2804 frameDropCount, |
|
2805 I64INT((frameTimeStamp - expectedNewTimeStamp )))); |
|
2806 frameTimeStamp = expectedNewTimeStamp + (frameDropCount*iSourceFrameInterval); |
|
2807 } |
|
2808 // |
|
2809 // Handle case where camera frame timestamp is more than previous encoded timestamp + specified camera frame duration. |
|
2810 // |
|
2811 else if ( aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() > expectedNewTimeStamp ) |
|
2812 { |
|
2813 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted timestamp since it was greater than expected timestamp and we have delayed timestamps earlier\t%d\t"),I64INT((expectedNewTimeStamp - frameTimeStamp)))); |
|
2814 // we have adjusted timestamps more to positive direction (delayed timestamps), try to compensate it now |
|
2815 // if camera frames have drifted more than 1 frame duration increase frame time stamp with one frame duration (as if frame dropped). |
|
2816 if ((aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() - expectedNewTimeStamp) > iSourceFrameInterval ) |
|
2817 { |
|
2818 iAddedFrameDurationCount++; |
|
2819 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), Camera timestamp has drifted more than 1 frame duration - adding 1 frame duration to timestamp from now on!\t%d\t"), iAddedFrameDurationCount )); |
|
2820 expectedNewTimeStamp = iLatestAbsoluteTimeStamp.Int64() + 2*iSourceFrameInterval; |
|
2821 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), new expectedNewTimeStamp (abs)\t%d\t"),I64INT(expectedNewTimeStamp))); |
|
2822 } |
|
2823 frameTimeStamp = expectedNewTimeStamp; |
|
2824 } |
|
2825 // |
|
2826 // Handles case where camera frame timestamp is less than previous encoded frame timestamp |
|
2827 // * happens when Camera is producing higher FPS that target FPS causing frame timestamp to drift below calculated cumulative recording time. |
|
2828 // |
|
2829 else if ( aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() < iLatestAbsoluteTimeStamp.Int64() ) |
|
2830 { |
|
2831 // frame with the timestamp of this frame was already encoded |
|
2832 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), drift between expected and frame buffer timestamp more than 1 frame duration, dropping frame!"))); |
|
2833 iDriftFrameSkipCount++; |
|
2834 aFrameBuffer->Release(); |
|
2835 return; |
|
2836 } |
|
2837 // |
|
2838 // Handle case where (camera frame index * framerate) is less than camera frame timestamp - specified camera frame duration |
|
2839 // * happens when Camera is skipping frames without extra increase in frame index count. |
|
2840 // |
|
2841 else if ( frameTimeStamp < ( (aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) - iSourceFrameInterval ) ) |
|
2842 { |
|
2843 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted timestamp since frame counter was too small compared to elapsed time: difference\t%d\t"),I64INT(aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() - frameTimeStamp))); |
|
2844 // frame numbers & elapsed time do not match, probably camera is skipping frames but doesn't know it / doesn't inform it to us |
|
2845 frameTimeStamp = Max( aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64(), expectedNewTimeStamp ); |
|
2846 } |
|
2847 // |
|
2848 // Handle case where (camera frame index * framerate) is less than calculated estimated timestamp value for currect frame |
|
2849 // (based on previous encoded frame timestamp + specified camera frame duration) |
|
2850 // |
|
2851 else if ( frameTimeStamp < expectedNewTimeStamp ) |
|
2852 { |
|
2853 // timestamp should not be too close to the previous timestamp (video codecs set max for framerate <=> min for ts diff) |
|
2854 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted timestamp since it was smaller than expected timestamp, difference\t%d\t"),I64INT(expectedNewTimeStamp - frameTimeStamp))); |
|
2855 frameTimeStamp = expectedNewTimeStamp; |
|
2856 } |
|
2857 else |
|
2858 { |
|
2859 // leave it as it is |
|
2860 } |
|
2861 |
|
2862 // for now we've been playing with absolute times, excluding all pauses & adjustments. Save this value as reference for determining timestamp for the next frame |
|
2863 iLatestAbsoluteTimeStamp = frameTimeStamp; |
|
2864 |
|
2865 if ( iAdjustmentTimeUs != 0 ) |
|
2866 { |
|
2867 // at the moment, initial and pause values are in opposite direction (+/-) |
|
2868 // for initial adjustment: |
|
2869 // if audio is ahead (iAdjustmentTimeUs > 0) => video should fast forward (video timestamps should be increased), |
|
2870 // if audio is behind (iAdjustmentTimeUs < 0) => video should "pause" for a while (video timestamps should be decreased) |
|
2871 // note that we modify here the iPausedTime which is subtracted from aFrameBuffer->iElapsedTime, so these |
|
2872 // changes affect kind of reverse way |
|
2873 |
|
2874 if ( ( frameTimeStamp - (iTotalPausedTime.Int64() - iAdjustmentTimeUs) ) >= (iLatestUsedTimeStamp.Int64() + iSourceFrameInterval) ) |
|
2875 { |
|
2876 // iAdjustmentTimeUs > 0 or < 0 but not too much < 0 so that the resulting timestamp won't be < (latest time stamp + sourceframeinterval) |
|
2877 iTotalPausedTime = iTotalPausedTime.Int64() - iAdjustmentTimeUs; |
|
2878 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted paused time by %d us"), I64INT(iAdjustmentTimeUs))); |
|
2879 iAdjustmentTimeUs = 0; |
|
2880 } |
|
2881 else |
|
2882 { |
|
2883 // iAdjustmentTimeUs < 0 here, we should "pause" video (skip frames) until we reach the required time |
|
2884 // Skipping is needed to avoid the timestamps to skip back over already captured frames. |
|
2885 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), skipped a frame due to time adjustment request %d; buffer->elapsedTime %d; latest time stamp %d"), I64INT(iAdjustmentTimeUs), I64INT(aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()), I64INT(iLatestUsedTimeStamp.Int64()) )); |
|
2886 aFrameBuffer->Release(); |
|
2887 return; |
|
2888 } |
|
2889 } |
|
2890 |
|
2891 // subtract the time we were paused |
|
2892 // (MSL assumes devvideorecord/hw device does this but we do it here) |
|
2893 TTimeIntervalMicroSeconds iPrevUsedTimeStamp = iLatestUsedTimeStamp; |
|
2894 iLatestUsedTimeStamp = frameTimeStamp - iTotalPausedTime.Int64(); |
|
2895 |
|
2896 // Increment timestamp in case we dropped frames during pause |
|
2897 while(( iLatestUsedTimeStamp < iPrevUsedTimeStamp ) && ( iNumberOfCapturedFrames > 0 )) |
|
2898 { |
|
2899 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() incrementing timestamp by one frame"))); |
|
2900 iLatestUsedTimeStamp = TTimeIntervalMicroSeconds( iLatestUsedTimeStamp.Int64() + iSourceFrameInterval ); |
|
2901 } |
|
2902 |
|
2903 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), iTotalPausedTime \t%d"), I64INT(iTotalPausedTime.Int64()) )); |
|
2904 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), iLatestUsedTimeStamp (relative) & drift from elapsed time\t%d"), I64INT(iLatestUsedTimeStamp.Int64()) )); |
|
2905 |
|
2906 EncodeFrame(aFrameBuffer); |
|
2907 |
|
2908 PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady, out"))); |
|
2909 } |
|
2910 |
|
2911 |
|
2912 // --------------------------------------------------------- |
|
2913 // CCMRVideoRecorder::EncodeFrame |
|
2914 // Encodes the given video frame. |
|
2915 // (other items were commented in a header). |
|
2916 // --------------------------------------------------------- |
|
2917 // |
|
2918 void CCMRVideoRecorder::EncodeFrame(MFrameBuffer* aFrameBuffer) |
|
2919 { |
|
2920 PRINT((_L("CCMRVideoRecorder::EncodeFrame, in"))); |
|
2921 |
|
2922 // Take a TVideoPicture into use |
|
2923 TVideoPicture* outputPicture = NULL; |
|
2924 if ( iCodingFifo->IsEmpty() ) |
|
2925 { |
|
2926 // allocate a new |
|
2927 outputPicture = new TVideoPicture; |
|
2928 if ( outputPicture == NULL ) |
|
2929 { |
|
2930 // out of memory, stop operation |
|
2931 DoSendEventToClient( KCMRRunTimeError, KErrNoMemory ); |
|
2932 aFrameBuffer->Release(); |
|
2933 return; |
|
2934 } |
|
2935 } |
|
2936 else |
|
2937 { |
|
2938 // take an old one from the queue |
|
2939 outputPicture = reinterpret_cast<TVideoPicture*>(iCodingFifo->Get()); |
|
2940 } |
|
2941 |
|
2942 iNumberOfCapturedFrames++; |
|
2943 |
|
2944 #ifdef _DEBUG |
|
2945 TTime current; |
|
2946 current.UniversalTime(); |
|
2947 TInt elapsedMs = I64INT((current.MicroSecondsFrom(iLastCapture).Int64())) / 1000; |
|
2948 iCumulativeCaptureTime += elapsedMs; |
|
2949 iAverageCaptureTime = TReal(iCumulativeCaptureTime) / TReal(iNumberOfCapturedFrames); |
|
2950 |
|
2951 PRINT((_L("CCMRVideoRecorder::EncodeFrame() recording time %d, ms since last: %d, average capture time: %4.2f"), |
|
2952 (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) / 1000, |
|
2953 elapsedMs, |
|
2954 iAverageCaptureTime)); |
|
2955 |
|
2956 iLastCapture = current; |
|
2957 iEncodingStartTime.UniversalTime(); |
|
2958 #endif |
|
2959 |
|
2960 // wrap captured frame to encoder input buffer |
|
2961 outputPicture->iData.iDataFormat = EYuvRawData; |
|
2962 outputPicture->iData.iDataSize.iWidth = iFrameSize.iWidth; |
|
2963 outputPicture->iData.iDataSize.iHeight = iFrameSize.iHeight; |
|
2964 TRAPD(err, (outputPicture->iData.iRawData = (TPtr8*)aFrameBuffer->DataL(0))); |
|
2965 if ( err != KErrNone ) |
|
2966 { |
|
2967 // error, stop operation |
|
2968 DoSendEventToClient( KCMRRunTimeError, err ); |
|
2969 aFrameBuffer->Release(); |
|
2970 delete outputPicture; |
|
2971 return; |
|
2972 } |
|
2973 |
|
2974 outputPicture->iTimestamp = iLatestUsedTimeStamp; |
|
2975 outputPicture->iOptions = TVideoPicture::ETimestamp; |
|
2976 outputPicture->iUser = this; |
|
2977 |
|
2978 #ifdef _DEBUG__ |
|
2979 TTime current; |
|
2980 current.UniversalTime(); |
|
2981 |
|
2982 |
|
2983 PRINT((_L("CCMRVideoRecorder::EncodeFrame()\t%d"), |
|
2984 (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) )); |
|
2985 #endif |
|
2986 |
|
2987 |
|
2988 // Put the captured buffer to iSourceFifo |
|
2989 TRAP( err, iSourceFifo->PutL( reinterpret_cast<TAny*>(aFrameBuffer) )); |
|
2990 if ( err != KErrNone ) |
|
2991 { |
|
2992 // out of memory, stop operation |
|
2993 DoSendEventToClient( KCMRRunTimeError, err ); |
|
2994 aFrameBuffer->Release(); |
|
2995 delete outputPicture; |
|
2996 return; |
|
2997 } |
|
2998 |
|
2999 |
|
3000 // give the frame to devVideoRec for encoding |
|
3001 iEncoderInputQueueLength++; |
|
3002 TRAP( err, iDevVideoRec->WritePictureL( outputPicture ) ); |
|
3003 if ( err != KErrNone ) |
|
3004 { |
|
3005 // error, stop operation, aFrameBuffer will be released from fifo when stopped |
|
3006 DoSendEventToClient( KCMRRunTimeError, err ); |
|
3007 return; |
|
3008 } |
|
3009 |
|
3010 PRINT((_L("CCMRVideoRecorder::EncodeFrame, picture %x written to devvr"),outputPicture)); |
|
3011 |
|
3012 #endif // #else if !VIDEO_FILE_OUTPUT |
|
3013 } |
|
3014 |
|
3015 |
|
3016 // --------------------------------------------------------- |
|
3017 // CCMRVideoRecorder::MdvroInitializeComplete |
|
3018 // Called by DevVideoRecord when its initalization is complete |
|
3019 // (other items were commented in a header). |
|
3020 // --------------------------------------------------------- |
|
3021 // |
|
3022 void CCMRVideoRecorder::MdvroInitializeComplete(TInt aError) |
|
3023 { |
|
3024 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete(), error[%d]"), aError)); |
|
3025 |
|
3026 if ( iDirectCapture ) |
|
3027 { |
|
3028 // Since direct capture is used, it should be true. Actual init CAPI status is |
|
3029 // included to aError now. |
|
3030 iSourceInitComplete = ETrue; |
|
3031 } |
|
3032 |
|
3033 iEncoderInitComplete = ETrue; |
|
3034 |
|
3035 if ( iSourceInitComplete && (iErrorCode != KErrNone) ) |
|
3036 { |
|
3037 // there was an error in the source initialisation, but the reporting was |
|
3038 // waiting for the completion of the encoder initialisation => report it now |
|
3039 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() but camera reservation had error: %d"), iErrorCode)); |
|
3040 DoSendEventToClient( KCMRCameraReserveError, iErrorCode ); |
|
3041 iErrorCode = KErrNone; |
|
3042 return; |
|
3043 } |
|
3044 |
|
3045 if ( aError != KErrNone ) |
|
3046 { |
|
3047 if ( aError == KErrHardwareNotAvailable && iVideoCodecHWAccelerated ) |
|
3048 { |
|
3049 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, retrying with ARM codec"))); |
|
3050 // hw accel codec and init failed due to resource problems => retry with non-hw-accelerated |
|
3051 iEncoderInitComplete = EFalse; |
|
3052 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, delete devvideo"))); |
|
3053 if (iDevVideoRec) |
|
3054 { |
|
3055 delete iDevVideoRec; |
|
3056 iDevVideoRec = NULL; |
|
3057 } |
|
3058 TRAPD(err, iDevVideoRec = CMMFDevVideoRecord::NewL( *this )); |
|
3059 if ( err == KErrNone ) |
|
3060 { |
|
3061 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, new devvideo created"))); |
|
3062 TRAP(err,SetupEncoderL()); |
|
3063 if ( err == KErrNone ) |
|
3064 { |
|
3065 // ok, continue waiting for the callback |
|
3066 return; |
|
3067 } |
|
3068 else |
|
3069 { |
|
3070 // store the last error, to be used in the operations below |
|
3071 aError = err; |
|
3072 } |
|
3073 } |
|
3074 else |
|
3075 { |
|
3076 // store the last error, to be used in the operations below |
|
3077 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, new devvideo creation failed."))); |
|
3078 aError = err; |
|
3079 } |
|
3080 } |
|
3081 |
|
3082 if ( iSourceInitComplete ) |
|
3083 { |
|
3084 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() with error: %d"), aError)); |
|
3085 DoSendEventToClient( KCMREncoderInitError, aError ); |
|
3086 } |
|
3087 else |
|
3088 { |
|
3089 // report only when source is completed too |
|
3090 PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() with error: %d, but must wait for camera reserve completion"), aError)); |
|
3091 iErrorCode = aError; |
|
3092 } |
|
3093 return; |
|
3094 } |
|
3095 |
|
3096 if ( aError == KErrNone ) |
|
3097 { |
|
3098 // If Encoder initialized Ok, give other run-time settings |
|
3099 // 1. Give dynamic settings to encoder after initializing |
|
3100 if ( !iVideoCodecHWAccelerated && ( iDevVideoRec->NumComplexityLevels(iEncoderHWDeviceId) > 0 ) ) |
|
3101 { |
|
3102 iVideoComplexity = iConfig->PluginSettings().iVideoComplexitySetting; |
|
3103 iDevVideoRec->SetComplexityLevel( iEncoderHWDeviceId, iVideoComplexity ); |
|
3104 } |
|
3105 // HW codec-specific configuration is HW dependent, and hence outside the scope of Series 60 |
|
3106 |
|
3107 // 2. Rate control options |
|
3108 if ( iEncodingFrameRate > iMaxFrameRate4GivenSize ) |
|
3109 { |
|
3110 iEncodingFrameRate = static_cast<TReal32>(iMaxFrameRate4GivenSize); |
|
3111 } |
|
3112 |
|
3113 FillRateControlOptions( iRateControlOptions ); |
|
3114 iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported |
|
3115 TRAPD(err,iVideoCodecData->SetPostInitParamsL(iDevVideoRec)); |
|
3116 if ( err ) {} |
|
3117 // ignore the error, having some post init setting is not crucial |
|
3118 |
|
3119 } |
|
3120 |
|
3121 if ( iSourceInitComplete ) |
|
3122 { |
|
3123 SetState(EStateReadyToRecord); |
|
3124 |
|
3125 // everything ok, inform observer that we are prepared. |
|
3126 DoSendEventToClient( KCMRPrepareComplete, KErrNone ); |
|
3127 } |
|
3128 } |
|
3129 |
|
3130 |
|
3131 // --------------------------------------------------------- |
|
3132 // CCMRVideoRecorder::MdvroReturnPicture |
|
3133 // Called by DevVideoRecord when it does not need the given |
|
3134 // input frame anymore |
|
3135 // (other items were commented in a header). |
|
3136 // --------------------------------------------------------- |
|
3137 // |
|
3138 void CCMRVideoRecorder::MdvroReturnPicture(TVideoPicture* aPicture) |
|
3139 { |
|
3140 #ifdef _DEBUG |
|
3141 TTime current; |
|
3142 current.UniversalTime(); |
|
3143 |
|
3144 |
|
3145 PRINT((_L("CCMRVideoRecorder::MdvroReturnPicture() time now\t%d"), |
|
3146 (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) )); |
|
3147 #endif |
|
3148 |
|
3149 // take oldest frame from fifo |
|
3150 VRASSERT( !iSourceFifo->IsEmpty() );// if empty, for some reason the buffer was already returned!! |
|
3151 |
|
3152 MFrameBuffer* buffer = reinterpret_cast<MFrameBuffer*>(iSourceFifo->Get()); |
|
3153 |
|
3154 // check that its the oldest stored captured picture |
|
3155 TPtr8* tmp = NULL; |
|
3156 TRAPD(error, (tmp = static_cast<TPtr8*>(buffer->DataL(0)))); |
|
3157 if ( tmp != aPicture->iData.iRawData ) |
|
3158 { |
|
3159 // pictures are returned in different order than they were sent |
|
3160 RPointerArray<MFrameBuffer> buffers; |
|
3161 buffers.Append(buffer); |
|
3162 |
|
3163 TUint i; |
|
3164 for ( i = 1; i < iNumCameraBuffers; i++ ) |
|
3165 { |
|
3166 buffers.Append(reinterpret_cast<MFrameBuffer*>(iSourceFifo->Get())); |
|
3167 |
|
3168 TRAP(error, (tmp = static_cast<TPtr8*>(buffers[i]->DataL(0)))); |
|
3169 if ( tmp == aPicture->iData.iRawData ) |
|
3170 { |
|
3171 // Found it! Put the retrieved buffers back to the queue |
|
3172 TInt err = KErrNone; |
|
3173 TUint j; |
|
3174 for ( j = 0; j < i; j++ ) |
|
3175 { |
|
3176 TRAP( err, iSourceFifo->PutL( reinterpret_cast<TAny*>(buffers[j]) )); |
|
3177 // This can't really fail since we just got the buffers from the fifo and in that case PutL doesn't allocate anything => can't leave |
|
3178 VRASSERT( err == KErrNone ); |
|
3179 buffers[j] = NULL; |
|
3180 } |
|
3181 break; |
|
3182 } |
|
3183 } |
|
3184 VRASSERT( i < iNumCameraBuffers ); |
|
3185 buffer = buffers[i]; |
|
3186 buffers.Close(); |
|
3187 } |
|
3188 |
|
3189 // release captured buffer |
|
3190 PRINT((_L("CCMRVideoRecorder::MdvroReturnPicture() releasing %x"), buffer )); |
|
3191 buffer->Release(); |
|
3192 buffer = NULL; |
|
3193 |
|
3194 iEncoderInputQueueLength--; |
|
3195 |
|
3196 |
|
3197 // save the picture holder to fifo |
|
3198 TRAPD( err, iCodingFifo->PutL( reinterpret_cast<TAny*>(aPicture) )); |
|
3199 if ( err != KErrNone ) |
|
3200 { |
|
3201 // OOM, inform error and stop operation |
|
3202 DoSendEventToClient( KCMRRunTimeError, err ); |
|
3203 delete aPicture; |
|
3204 return; |
|
3205 } |
|
3206 PRINT((_L("CCMRVideoRecorder::MdvroReturnPicture() stored %x"), aPicture )); |
|
3207 } |
|
3208 |
|
3209 |
|
3210 // --------------------------------------------------------- |
|
3211 // CCMRVideoRecorder::MdvroSupplementalInfoSent |
|
3212 // Called by DevVideoRecord when supplemental info (e.g., |
|
3213 // VOL header) has been sent to the encoder |
|
3214 // (other items were commented in a header). |
|
3215 // --------------------------------------------------------- |
|
3216 // |
|
3217 void CCMRVideoRecorder::MdvroSupplementalInfoSent() |
|
3218 { |
|
3219 PRINT((_L("CCMRVideoRecorder::MdvroSupplementalInfoSent()"))); |
|
3220 User::Panic(_L("CCMRVIDEORECORDER"), KErrGeneral); |
|
3221 } |
|
3222 |
|
3223 |
|
3224 // --------------------------------------------------------- |
|
3225 // CCMRVideoRecorder::MdvroNewBuffers |
|
3226 // Called by DevVideoRecord when new bitstream buffers are |
|
3227 // available for retrieval |
|
3228 // (other items were commented in a header). |
|
3229 // --------------------------------------------------------- |
|
3230 // |
|
3231 void CCMRVideoRecorder::MdvroNewBuffers() |
|
3232 { |
|
3233 PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - START - iRequestStatus: 0x%08x"), iRequestStatus )); |
|
3234 PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers(), NumDataBuffers[%d]"), iDevVideoRec->NumDataBuffers() )); |
|
3235 iNumberOfEncodedFrames++; |
|
3236 |
|
3237 TVideoOutputBuffer* buffer = NULL; |
|
3238 for (;;) |
|
3239 { |
|
3240 TRAPD( err, ( buffer = iDevVideoRec->NextBufferL())); |
|
3241 |
|
3242 if ( err != KErrNone ) |
|
3243 { |
|
3244 return; |
|
3245 } |
|
3246 if ( buffer == NULL ) |
|
3247 { |
|
3248 break; |
|
3249 } |
|
3250 /* TInt bufferSize = buffer->iData.Length(); |
|
3251 TInt bufferTimeStamp = I64INT(buffer->iCaptureTimestamp.Int64()); |
|
3252 OstTraceExt2( TRACE_PERFORMANCE, CCMRVIDEORECORDER_MDVRONEWBUFFERS, "CCMRVideoRecorder::MdvroNewBuffers %d %d", bufferSize, bufferTimeStamp ); |
|
3253 */ |
|
3254 // enter restricted area |
|
3255 iMutexObj.Wait(); |
|
3256 // store |
|
3257 PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers(), storing buffer: 0x%x, timestamp: high: %u low: %u"), buffer, I64HIGH(buffer->iCaptureTimestamp.Int64()),I64LOW(buffer->iCaptureTimestamp.Int64()))); |
|
3258 iVideoOutputBufferInputQue.AddLast(*buffer); |
|
3259 iNumberOfVideoOutputBuffers++; |
|
3260 |
|
3261 // leave restricted area |
|
3262 iMutexObj.Signal(); |
|
3263 } |
|
3264 |
|
3265 // enter restricted area |
|
3266 iMutexObj.Wait(); |
|
3267 if ( iRequestStatus ) |
|
3268 { |
|
3269 PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - completing output request..." ))); |
|
3270 iOutputThreadHandle.RequestComplete( iRequestStatus, KErrNone ); |
|
3271 } |
|
3272 else |
|
3273 { |
|
3274 // else a new request has not been issued yet |
|
3275 PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - skipping RequestComplete" ))); |
|
3276 } |
|
3277 // leave restricted area |
|
3278 iMutexObj.Signal(); |
|
3279 |
|
3280 PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - END - iRequestStatus: 0x%08x"), iRequestStatus )); |
|
3281 } |
|
3282 |
|
3283 |
|
3284 // --------------------------------------------------------- |
|
3285 // CCMRVideoRecorder::MdvroFatalError |
|
3286 // Called by devVideoRecord when a fatal error has occurred |
|
3287 // (other items were commented in a header). |
|
3288 // --------------------------------------------------------- |
|
3289 // |
|
3290 void CCMRVideoRecorder::MdvroFatalError(TInt aError) |
|
3291 { |
|
3292 PRINT((_L("CCMRVideoRecorder::MdvroFatalError(), error[%d]"), aError)); |
|
3293 |
|
3294 // Since now don't touch DevVideo that expects only destruction from the client, otherwise panics.. |
|
3295 iFatalError = ETrue; |
|
3296 |
|
3297 // Cancel returning buffers to DevVideo |
|
3298 iBufferReturnAO->Cancel(); |
|
3299 |
|
3300 if ( iDevVideoRec ) |
|
3301 { |
|
3302 delete iDevVideoRec; |
|
3303 iDevVideoRec = NULL; |
|
3304 } |
|
3305 |
|
3306 if ( State() == EStateStopping ) |
|
3307 { |
|
3308 // error occurred while stopping => carry out the rest of stopping & inform client |
|
3309 SetState( EStateReadyToRecord ); |
|
3310 DoSendEventToClient( KCMRRecordingComplete, aError ); |
|
3311 } |
|
3312 else |
|
3313 { |
|
3314 // inform client |
|
3315 DoSendEventToClient( KCMRRunTimeError, aError ); |
|
3316 iErrorCode = aError; |
|
3317 } |
|
3318 } |
|
3319 |
|
3320 |
|
3321 // --------------------------------------------------------- |
|
3322 // CCMRVideoRecorder::MdvroStreamEnd |
|
3323 // Called by devVideoRecord when all pictures have been processed |
|
3324 // (after InputEnd is called) |
|
3325 // (other items were commented in a header). |
|
3326 // --------------------------------------------------------- |
|
3327 // |
|
3328 void CCMRVideoRecorder::MdvroStreamEnd() |
|
3329 { |
|
3330 PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd() in"))); |
|
3331 |
|
3332 // MdvroStreamEnd was called by devVideo without InputEnd |
|
3333 VRASSERT( iInputEnd ); |
|
3334 |
|
3335 // get all available buffers from devvideo |
|
3336 PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd(), getting all encoded frames from DevVideo."))); |
|
3337 TVideoOutputBuffer* buffer = NULL; |
|
3338 for (;;) |
|
3339 { |
|
3340 TRAPD( err, ( buffer = iDevVideoRec->NextBufferL())); |
|
3341 if ( err != KErrNone || buffer == NULL) |
|
3342 { |
|
3343 break; |
|
3344 } |
|
3345 // enter restricted area |
|
3346 iMutexObj.Wait(); |
|
3347 // store |
|
3348 PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd(), storing buffer: 0x%x, timestamp:%d"), buffer, I64INT(buffer->iCaptureTimestamp.Int64()))); |
|
3349 iVideoOutputBufferInputQue.AddLast(*buffer); |
|
3350 iNumberOfVideoOutputBuffers++; |
|
3351 |
|
3352 // leave restricted area |
|
3353 iMutexObj.Signal(); |
|
3354 } |
|
3355 |
|
3356 PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd(), flushing written frames back to DevVideo."))); |
|
3357 iBufferReturnAO->Flush(); |
|
3358 |
|
3359 // stop |
|
3360 if ( iDevVideoRec ) |
|
3361 { |
|
3362 PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd() iDevVideoRec->Stop called"))); |
|
3363 iDevVideoRec->Stop(); |
|
3364 } |
|
3365 |
|
3366 iStreamEnd = ETrue; |
|
3367 |
|
3368 // set state & inform MR => it can return from stop |
|
3369 SetState( EStateReadyToRecord ); |
|
3370 |
|
3371 // everything ok, inform observer that we are ready for a new recording (iStopping does it too, though). |
|
3372 DoSendEventToClient( KCMRRecordingComplete, KErrNone ); |
|
3373 |
|
3374 PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd() out"))); |
|
3375 } |
|
3376 |
|
3377 |
|
3378 // ----------------------------------------------------------------------------- |
|
3379 // CCMRVideoRecorder::RequestNewData |
|
3380 // Output active object is ready to accept new data |
|
3381 // (other items were commented in a header). |
|
3382 // ----------------------------------------------------------------------------- |
|
3383 // |
|
3384 void CCMRVideoRecorder::RequestNewData(TRequestStatus& aStatus) |
|
3385 { |
|
3386 PRINT((_L("CCMRVideoRecorder::RequestNewData() - START - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus )); |
|
3387 |
|
3388 // enter restricted area |
|
3389 iMutexObj.Wait(); |
|
3390 |
|
3391 iRequestStatus = &aStatus; |
|
3392 aStatus = KRequestPending; |
|
3393 |
|
3394 // leave restricted area |
|
3395 iMutexObj.Signal(); |
|
3396 |
|
3397 PRINT((_L("CCMRVideoRecorder::RequestNewData() - END - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus )); |
|
3398 } |
|
3399 |
|
3400 |
|
3401 // ----------------------------------------------------------------------------- |
|
3402 // CCMRVideoRecorder::RequestNewDataCancel |
|
3403 // |
|
3404 // |
|
3405 // ----------------------------------------------------------------------------- |
|
3406 // |
|
3407 void CCMRVideoRecorder::RequestNewDataCancel(TRequestStatus& aStatus) |
|
3408 { |
|
3409 PRINT((_L("CCMRVideoRecorder::RequestNewDataCancel() - START - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus )); |
|
3410 |
|
3411 // enter restricted area |
|
3412 iMutexObj.Wait(); |
|
3413 |
|
3414 if ( &aStatus == iRequestStatus ) |
|
3415 { |
|
3416 iOutputThreadHandle.RequestComplete( iRequestStatus, KErrCancel ); |
|
3417 } |
|
3418 |
|
3419 // leave restricted area |
|
3420 iMutexObj.Signal(); |
|
3421 |
|
3422 PRINT((_L("CCMRVideoRecorder::RequestNewDataCancel() - END - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus )); |
|
3423 } |
|
3424 |
|
3425 |
|
3426 // ----------------------------------------------------------------------------- |
|
3427 // CCMRVideoRecorder::GetNextBuffer |
|
3428 // Output active object takes the next output buffer |
|
3429 // (other items were commented in a header). |
|
3430 // ----------------------------------------------------------------------------- |
|
3431 // |
|
3432 CCMRMediaBuffer* CCMRVideoRecorder::GetNextBuffer() |
|
3433 { |
|
3434 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() in") )); |
|
3435 if ( iDevVideoRec == NULL || iFatalError ) |
|
3436 { |
|
3437 // probably we have not been opened yet |
|
3438 PRINT((_L("CCMRVideoRecorder::GetNextBuffer(), We have not been opened yet, or there's an error from devVideo"))); |
|
3439 return NULL; |
|
3440 } |
|
3441 |
|
3442 if ( iDecSpecInfo ) |
|
3443 { |
|
3444 // we have MPEG-4 decoder configuration information, it must be processed first |
|
3445 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() iDecSpecInfo") )); |
|
3446 iRemoveHeader = ETrue; |
|
3447 const TUint8* data = iDecSpecInfo->Ptr(); |
|
3448 iDecSpecInfoLength = iDecSpecInfo->Length(); |
|
3449 |
|
3450 CCMRMediaBuffer::TBufferType decSpecType = CCMRMediaBuffer::EVideoMPEG4DecSpecInfo; |
|
3451 if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264NAL ) |
|
3452 {// H.264 AVC NAL / GenericPayload encapsulation |
|
3453 decSpecType = CCMRMediaBuffer::EVideoH264NALDecSpecInfo; |
|
3454 } |
|
3455 else if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264Bytestream ) |
|
3456 { |
|
3457 decSpecType = CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo; |
|
3458 } |
|
3459 |
|
3460 // wrap the relevant data to CCMRMediaBuffer; iOutputSinkBuffer can't be != NULL here since it is created in ConstructL |
|
3461 iOutputSinkBuffer->Set( TPtrC8(data,iDecSpecInfoLength), |
|
3462 decSpecType, |
|
3463 iDecSpecInfoLength, |
|
3464 EFalse, |
|
3465 TTimeIntervalMicroSeconds(0) ); |
|
3466 |
|
3467 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() decoder specific info to sink sent"))); |
|
3468 return iOutputSinkBuffer; |
|
3469 } |
|
3470 |
|
3471 // enter restricted area |
|
3472 iMutexObj.Wait(); |
|
3473 if (iNumberOfVideoOutputBuffers > 0) |
|
3474 { |
|
3475 iOutputVideoBuffer = iVideoOutputBufferInputQue.First(); |
|
3476 |
|
3477 // Remove the picture from the list |
|
3478 iOutputVideoBuffer->iLink.Deque(); |
|
3479 iNumberOfVideoOutputBuffers--; |
|
3480 // leave restricted area |
|
3481 iMutexObj.Signal(); |
|
3482 } |
|
3483 else |
|
3484 { |
|
3485 // leave restricted area |
|
3486 PRINT((_L("CCMRVideoRecorder::GetNextBuffer()returning null, leave restricted area, iNumberOfVideoOutputBuffers == 0 %x"), this)); |
|
3487 iMutexObj.Signal(); |
|
3488 return NULL; |
|
3489 } |
|
3490 |
|
3491 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() got [0x%x] from devvr"), iOutputVideoBuffer )); |
|
3492 |
|
3493 if ( iOutputVideoBuffer != NULL ) |
|
3494 { |
|
3495 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() processing iOutputVideoBuffer") )); |
|
3496 TBool outputMediaBufferSet = EFalse; |
|
3497 if ( iRemoveHeader ) |
|
3498 { |
|
3499 // check if we need to remove VOS+VO+VOL header from the bitstream, since it is stored in metadata, and |
|
3500 // having it in 2 places may cause interoperability problems |
|
3501 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() remove extra header info") )); |
|
3502 iRemoveHeader = EFalse; |
|
3503 if ( iVideoBufferType == CCMRMediaBuffer::EVideoMPEG4 ) |
|
3504 {// MPEG-4 |
|
3505 RemoveSeqHeader( reinterpret_cast<TDesC8*>(&iOutputVideoBuffer->iData) ); |
|
3506 } |
|
3507 else if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264NAL ) |
|
3508 {// H.264 AVC NAL / EDuGenericPayload / NAL encapsulation |
|
3509 // Removes SPS & PPS from first frame from encoder to avoid situation where its both in |
|
3510 // .mp4 file metadata and in bitstream of video track. |
|
3511 // Make sure buffer contains only one frame and rewrite encapsulation to make sure its ok. |
|
3512 RemoveNalDecSpecInfoHeader( reinterpret_cast<TDesC8*>(&iOutputVideoBuffer->iData) ); |
|
3513 outputMediaBufferSet = ETrue; |
|
3514 } |
|
3515 else if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264Bytestream ) |
|
3516 {// H.264 AVC NAL / EDuElementarystream / Bytestream |
|
3517 // Removes SPS & PPS from first frame from encoder to avoid situation where its both in |
|
3518 // .mp4 file metadata and in bitstream of video track. |
|
3519 RemoveByteStreamDecSpecInfoHeader( reinterpret_cast<TDesC8*>(&iOutputVideoBuffer->iData) ); |
|
3520 outputMediaBufferSet = ETrue; |
|
3521 } |
|
3522 } |
|
3523 |
|
3524 if ( !outputMediaBufferSet ) |
|
3525 { |
|
3526 // wrap the relevant data to CCMRMediaBuffer |
|
3527 iOutputSinkBuffer->Set( iOutputVideoBuffer->iData, |
|
3528 iVideoBufferType, |
|
3529 iOutputVideoBuffer->iData.Length(), |
|
3530 iOutputVideoBuffer->iRandomAccessPoint, |
|
3531 iOutputVideoBuffer->iCaptureTimestamp ); |
|
3532 } |
|
3533 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() iOutputSinkBuffer set") )); |
|
3534 |
|
3535 #ifdef _DEBUG__ |
|
3536 TTime current; |
|
3537 current.UniversalTime(); |
|
3538 TInt elapsedMs = (I64INT(current.MicroSecondsFrom(iEncodingStartTime).Int64())) / 1000; |
|
3539 iCumulativeEncodingTime += elapsedMs; |
|
3540 iAverageEncodingTime = TReal(iCumulativeEncodingTime) / TReal(iNumberOfEncodedFrames); |
|
3541 |
|
3542 |
|
3543 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() %d, time consumed: %d, average encoding time: %4.2f"), |
|
3544 (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) / 1000, |
|
3545 (I64INT(current.MicroSecondsFrom(iEncodingStartTime).Int64())) / 1000, |
|
3546 iAverageEncodingTime)); |
|
3547 #endif |
|
3548 |
|
3549 #ifdef VIDEO_BS_FILE_OUTPUT |
|
3550 // Write the frame to a file for testing purposes; have to ignore possible errors |
|
3551 iOutputFile.Write(videoBuffer->iData); |
|
3552 #endif |
|
3553 |
|
3554 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() a buffer to sink sent with timestamp high: %u low: %u"),I64HIGH(iOutputVideoBuffer->iCaptureTimestamp.Int64()),I64LOW(iOutputVideoBuffer->iCaptureTimestamp.Int64()))); |
|
3555 return iOutputSinkBuffer; |
|
3556 } |
|
3557 else |
|
3558 { |
|
3559 PRINT((_L("CCMRVideoRecorder::GetNextBuffer() returning NULL - no new buffers in queue") )); |
|
3560 // no more new buffers in queue |
|
3561 return NULL; |
|
3562 } |
|
3563 } |
|
3564 |
|
3565 |
|
3566 // ----------------------------------------------------------------------------- |
|
3567 // CCMRVideoRecorder::NumBuffersWaiting |
|
3568 // Return the number of buffers in the source |
|
3569 // (other items were commented in a header). |
|
3570 // ----------------------------------------------------------------------------- |
|
3571 // |
|
3572 TInt CCMRVideoRecorder::NumBuffersWaiting() |
|
3573 { |
|
3574 if (iFatalError) |
|
3575 { |
|
3576 // NumDataBuffers() cannot be called since fatalError was reported |
|
3577 return 0; |
|
3578 } |
|
3579 |
|
3580 if ( iDecSpecInfo ) |
|
3581 { |
|
3582 // decspecinfo is not counted in iNumberOfVideoOutputBuffers |
|
3583 return (iNumberOfVideoOutputBuffers+1); |
|
3584 } |
|
3585 else |
|
3586 { |
|
3587 return iNumberOfVideoOutputBuffers; |
|
3588 } |
|
3589 } |
|
3590 |
|
3591 |
|
3592 // ----------------------------------------------------------------------------- |
|
3593 // CCMRVideoRecorder::LatestTimeStampL |
|
3594 // Return the latest time stamp from the input stream |
|
3595 // (other items were commented in a header). |
|
3596 // ----------------------------------------------------------------------------- |
|
3597 // |
|
3598 void CCMRVideoRecorder::LatestTimeStampL(TTimeIntervalMicroSeconds& aTimeStamp) const |
|
3599 { |
|
3600 aTimeStamp = iLatestUsedTimeStamp; |
|
3601 } |
|
3602 |
|
3603 // ----------------------------------------------------------------------------- |
|
3604 // CCMRVideoRecorder::DurationL |
|
3605 // Get duration of the recording (in practice the same as the latest time stamp) |
|
3606 // (other items were commented in a header). |
|
3607 // ----------------------------------------------------------------------------- |
|
3608 // |
|
3609 void CCMRVideoRecorder::DurationL(TTimeIntervalMicroSeconds& aDuration) const |
|
3610 { |
|
3611 LatestTimeStampL( aDuration ); |
|
3612 } |
|
3613 |
|
3614 // ----------------------------------------------------------------------------- |
|
3615 // CCMRVideoRecorder::ReturnBuffer |
|
3616 // Output active object returns an emptied buffer |
|
3617 // (other items were commented in a header). |
|
3618 // ----------------------------------------------------------------------------- |
|
3619 // |
|
3620 void CCMRVideoRecorder::ReturnBuffer(CCMRMediaBuffer* aBuffer) |
|
3621 { |
|
3622 PRINT((_L("CCMRVideoRecorder::ReturnBuffer() buffers 0x%x, 0x%x"),aBuffer, iOutputSinkBuffer)); |
|
3623 VRASSERT( iOutputSinkBuffer == aBuffer ); |
|
3624 |
|
3625 if ( iFatalError ) |
|
3626 { |
|
3627 PRINT((_L("CCMRVideoRecorder::ReturnBuffer(), don't return anything, since there's an error from devVideo"))); |
|
3628 iOutputVideoBuffer = NULL; |
|
3629 return; |
|
3630 } |
|
3631 |
|
3632 iOutputSinkBuffer = aBuffer; |
|
3633 if ( iDecSpecInfo ) |
|
3634 { |
|
3635 delete iDecSpecInfo; |
|
3636 iDecSpecInfo = NULL; |
|
3637 // iOutputVideoBuffer is not used with decspecinfo |
|
3638 } |
|
3639 else |
|
3640 { |
|
3641 // normal case; iOutputVideoBuffer != NULL if functions are called in correct order |
|
3642 PRINT((_L("CCMRVideoRecorder::ReturnBuffer() iOutputVideoBuffer 0x%x"), iOutputVideoBuffer)); |
|
3643 VRASSERT( iOutputVideoBuffer != NULL ); |
|
3644 // store the buffer for sending from this thread |
|
3645 iBufferReturnAO->EnqueueReturnBuffer(iOutputVideoBuffer); |
|
3646 |
|
3647 iOutputVideoBuffer = NULL; |
|
3648 } |
|
3649 } |
|
3650 |
|
3651 |
|
3652 |
|
3653 // ----------------------------------------------------------------------------- |
|
3654 // CCMRVideoRecorder::FillRateControlOptions |
|
3655 // Fill DevVideoRecord rate control options structure |
|
3656 // (other items were commented in a header). |
|
3657 // ----------------------------------------------------------------------------- |
|
3658 // |
|
3659 void CCMRVideoRecorder::FillRateControlOptions( TRateControlOptions& aRC ) |
|
3660 { |
|
3661 TRAPD(error,CCMRRecorderBase::TargetBitRateL((TInt&)(aRC.iBitrate))); |
|
3662 |
|
3663 // error can be ignored, it will never be != KErrNone at this stage |
|
3664 if (error != KErrNone) |
|
3665 { |
|
3666 VRASSERT( error == KErrNone ); |
|
3667 } |
|
3668 |
|
3669 if ( iBitRateMode == EBitRateConstant ) |
|
3670 { |
|
3671 aRC.iControl = EBrControlStream; |
|
3672 } |
|
3673 else |
|
3674 { |
|
3675 // Variable bitrate; rc.iBitrate is probably not needed but it gives now the upper limit |
|
3676 aRC.iControl = EBrControlNone; |
|
3677 } |
|
3678 |
|
3679 aRC.iPictureRate = iEncodingFrameRate; |
|
3680 // these are filled already in constructor: |
|
3681 //aRC.iPictureQuality |
|
3682 //aRC.iLatencyQualityTradeoff |
|
3683 //aRC.iQualityTemporalTradeoff |
|
3684 PRINT((_L("CCMRVideoRecorder::FillRateControlOptions() - framerate %f, bitrate %d"), aRC.iPictureRate, aRC.iBitrate)); |
|
3685 } |
|
3686 |
|
3687 |
|
3688 // ----------------------------------------------------------------------------- |
|
3689 // CCMRVideoRecorder::CheckExposure |
|
3690 // Check exposure from camera and adjust framerates if needed |
|
3691 // (other items were commented in a header). |
|
3692 // ----------------------------------------------------------------------------- |
|
3693 // |
|
3694 void CCMRVideoRecorder::CheckExposure() |
|
3695 { |
|
3696 if ( iSource->GetExposure() == CCamera::EExposureNight ) |
|
3697 { |
|
3698 iNightMode = ETrue; |
|
3699 iSourceFrameRate = iConfig->PluginSettings().iVideoNightFrameRate; |
|
3700 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
3701 |
|
3702 // new framerate should be set to the encoder too |
|
3703 TRAPD(error, SetFrameRateL( iSourceFrameRate )); |
|
3704 |
|
3705 // error can be ignored, it will never be != KErrNone here |
|
3706 if (error != KErrNone) |
|
3707 { |
|
3708 VRASSERT( error == KErrNone ); |
|
3709 } |
|
3710 } |
|
3711 else |
|
3712 { |
|
3713 // other modes don't affect to framerates, except if we switch back from night mode to normal |
|
3714 if ( iNightMode ) |
|
3715 { |
|
3716 iSourceFrameRate = iRequestedFrameRate; |
|
3717 iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate); |
|
3718 |
|
3719 // new framerate should be set to the encoder too |
|
3720 TRAPD(error,SetFrameRateL( iSourceFrameRate )); |
|
3721 |
|
3722 // error can be ignored, it will never be != KErrNone here |
|
3723 if (error != KErrNone) |
|
3724 { |
|
3725 VRASSERT( error == KErrNone ); |
|
3726 } |
|
3727 |
|
3728 iNightMode = EFalse; |
|
3729 } |
|
3730 } |
|
3731 |
|
3732 } |
|
3733 |
|
3734 |
|
3735 // ----------------------------------------------------------------------------- |
|
3736 // CCMRVideoRecorder::UpdateSupportedFrameSizesRates |
|
3737 // Update supported video frames and sizes table from ECAM and MDF encoders. |
|
3738 // (other items were commented in a header). |
|
3739 // ----------------------------------------------------------------------------- |
|
3740 // |
|
3741 void CCMRVideoRecorder::UpdateSupportedVideoFrameSizesRates() |
|
3742 { |
|
3743 PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() in"))); |
|
3744 iAvailableVideoFrameSizesRates.Reset(); |
|
3745 |
|
3746 if ( iAvailableVideoEncoders.Count() ) |
|
3747 { |
|
3748 for ( TInt i = 0 ; i < iAvailableVideoEncoders.Count(); i++ ) |
|
3749 { |
|
3750 // encoder info for retrieving capabilities |
|
3751 CVideoEncoderInfo* encoderInfo = NULL; |
|
3752 PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() - getting info from a plugin index[%d] with Uid 0x%x"), i, iAvailableVideoEncoders[i].iUid )); |
|
3753 TRAPD(error, (encoderInfo = ReadEncoderInfoL(iAvailableVideoEncoders[i])) ); |
|
3754 |
|
3755 if ( (encoderInfo != NULL) && (error == KErrNone)) |
|
3756 { |
|
3757 // Check directCapture support for current codec |
|
3758 if ( encoderInfo->SupportsDirectCapture() ) |
|
3759 { |
|
3760 // check max framerate for given picture size |
|
3761 RArray<TPictureRateAndSize> rateAndSize = encoderInfo->MaxPictureRates(); |
|
3762 for ( TUint j = 0; j < rateAndSize.Count(); j++ ) |
|
3763 { |
|
3764 TPictureRateAndSize newSizeRate = rateAndSize[j]; |
|
3765 TInt addError = iAvailableVideoFrameSizesRates.InsertInOrder(newSizeRate, TLinearOrder<TPictureRateAndSize>(TLinearOrderFuncVideoSizeRate) ); |
|
3766 if (addError == KErrNone) |
|
3767 { |
|
3768 PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() - Added size: %d x %d, rate: %f"), |
|
3769 rateAndSize[j].iPictureSize.iWidth, |
|
3770 rateAndSize[j].iPictureSize.iHeight, |
|
3771 rateAndSize[j].iPictureRate)); |
|
3772 } |
|
3773 } |
|
3774 } |
|
3775 delete encoderInfo; |
|
3776 } |
|
3777 } |
|
3778 } |
|
3779 PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() out"))); |
|
3780 } |
|
3781 |
|
3782 // ----------------------------------------------------------------------------- |
|
3783 // CCMRVideoRecorder::DoSendEventToClient |
|
3784 // Send event to client |
|
3785 // (other items were commented in a header). |
|
3786 // ----------------------------------------------------------------------------- |
|
3787 // |
|
3788 TInt CCMRVideoRecorder::DoSendEventToClient(TUid aEventType, TInt aErrorCode) |
|
3789 { |
|
3790 PRINT((_L("CCMRVideoRecorder::DoSendEventToClient(), aEventType %d"),aEventType.iUid)); |
|
3791 TMMFEvent event(aEventType, aErrorCode); |
|
3792 return iEventHandler.SendEventToClient(event); |
|
3793 } |
|
3794 |
|
3795 |
|
3796 // ----------------------------------------------------------------------------- |
|
3797 // CCMRVideoRecorder::ReturnBufferToDevVR |
|
3798 // CCMRReturnAO uses this function to return buffer to DevVideoRecord |
|
3799 // (other items were commented in a header). |
|
3800 // ----------------------------------------------------------------------------- |
|
3801 // |
|
3802 void CCMRVideoRecorder::ReturnBufferToDevVR(TVideoOutputBuffer* aBuffer) |
|
3803 { |
|
3804 PRINT((_L("CCMRVideoRecorder::ReturnBufferToDevVR() in buffer: 0x%x, timestamp: high: %u low: %u"), aBuffer, I64HIGH(aBuffer->iCaptureTimestamp.Int64()),I64LOW(aBuffer->iCaptureTimestamp.Int64()))); |
|
3805 if (iDevVideoRec) |
|
3806 { |
|
3807 iDevVideoRec->ReturnBuffer(aBuffer); |
|
3808 } |
|
3809 PRINT((_L("CCMRVideoRecorder::ReturnBufferToDevVR() out"))); |
|
3810 } |
|
3811 |
|
3812 |
|
3813 // ----------------------------------------------------------------------------- |
|
3814 // CCMRVideoRecorder::RemoveSeqHeader( TDesC8* aVideoBuffer ) |
|
3815 // RemoveSeqHeader remove MPEG4 decoder configuration info (VOS+VO+VOL header) |
|
3816 // from the 1st video packet (it is saved in metadata, and duplication not allowed) |
|
3817 // Returns: TInt number of bytes removed |
|
3818 // ----------------------------------------------------------------------------- |
|
3819 // |
|
3820 TInt CCMRVideoRecorder::RemoveSeqHeader( TDesC8* aVideoBuffer ) |
|
3821 { |
|
3822 // MPEG-4 VOP header == the 1st element in the buffer to not remove |
|
3823 const TUint8 KHeader[4] = {0x00, 0x00, 0x01, 0xb6}; |
|
3824 const TUint KSampleLength = 4; |
|
3825 |
|
3826 TPtr8* buffer = reinterpret_cast<TPtr8*>(aVideoBuffer); |
|
3827 // Bitstream start point |
|
3828 const TUint8* data = buffer->Ptr(); |
|
3829 TUint headerLength; |
|
3830 TBool iFound = EFalse; |
|
3831 |
|
3832 // Search for VOP start code |
|
3833 for ( headerLength = 0; headerLength < (buffer->Length() - (KSampleLength - 1)); headerLength++ ) |
|
3834 { |
|
3835 if ( (data[headerLength] == KHeader[0]) |
|
3836 && (data[headerLength+1] == KHeader[1]) |
|
3837 && (data[headerLength+2] == KHeader[2]) |
|
3838 && (data[headerLength+3] == KHeader[3]) ) |
|
3839 { |
|
3840 // VOP start code is found => video data starts from here |
|
3841 iFound = ETrue; |
|
3842 break; |
|
3843 } |
|
3844 } |
|
3845 |
|
3846 if ( (headerLength > 0) && iFound ) |
|
3847 { |
|
3848 // adjust ptr & length depending which is longer VOP header location or earlier iDecSpecInfoLength length |
|
3849 if ( iDecSpecInfoLength && (iDecSpecInfoLength <= headerLength ) ) |
|
3850 { |
|
3851 buffer->Delete(0,iDecSpecInfoLength); |
|
3852 } |
|
3853 else |
|
3854 { |
|
3855 buffer->Delete(0,headerLength); |
|
3856 } |
|
3857 } |
|
3858 return headerLength; |
|
3859 } |
|
3860 |
|
3861 // ----------------------------------------------------------------------------- |
|
3862 // CCMRVideoRecorder::RemoveNalDecSpecInfoHeader( TDesC8* aVideoBuffer ) |
|
3863 // Removes decoder configuration info (SPS & PPS) from first NAL encapsulated H.264/AVC video buffer |
|
3864 // from encoder to avoid situation where its both in .mp4 file metadata and in bitstream of video track. |
|
3865 // Makes sure buffer contains only one frame and rewrite encapsulation to make sure its ok. |
|
3866 // ----------------------------------------------------------------------------- |
|
3867 // |
|
3868 TInt CCMRVideoRecorder::RemoveNalDecSpecInfoHeader( TDesC8* aVideoBuffer ) |
|
3869 { |
|
3870 // H.264 AVC NAL / EDuGenericPayload / NAL encapsulation |
|
3871 |
|
3872 // Get reference to the buffer |
|
3873 TPtr8* ptr = reinterpret_cast<TPtr8*>(aVideoBuffer); |
|
3874 // Bitstream start point |
|
3875 TPtr8& buffer(*ptr); |
|
3876 TInt frameStart = 0; |
|
3877 TInt frameSize = 0; |
|
3878 TInt offset = 0; |
|
3879 TInt bufType = 0; |
|
3880 TInt i=0; |
|
3881 TInt totalNALLength = 0; |
|
3882 TInt firstCopiedNAL = 0; |
|
3883 TInt nalCount = 0; |
|
3884 RArray<TInt> nalSizes; |
|
3885 RArray<TInt> nalStarts; |
|
3886 |
|
3887 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() in, length: %d "), buffer.Length() )); |
|
3888 |
|
3889 // There should be enough data for the NAL header + frame |
|
3890 if ( buffer.Length() > 12 ) |
|
3891 { |
|
3892 // Offset to the end and get NAL unit count |
|
3893 offset = buffer.Length()-4; //last 4 bytes are the NAL unit count |
|
3894 nalCount = TInt(buffer[offset]) + |
|
3895 (TInt(buffer[offset + 1]) << 8) + |
|
3896 (TInt(buffer[offset + 2]) << 16) + |
|
3897 (TInt(buffer[offset + 3]) << 24); |
|
3898 |
|
3899 for(i=0; i<nalCount; i++) |
|
3900 {//go through all NAL units in buffer |
|
3901 // Offset to the start of NAL Unit infos |
|
3902 offset = buffer.Length()-4-(8*nalCount); // 4 is the NAL unit count at end of buffer, 8 bytes used per NAL Unit for FrameStartOffset and FrameSize. |
|
3903 |
|
3904 // Get frame start offset |
|
3905 offset += 8*i; |
|
3906 frameStart = TInt(buffer[offset]) + |
|
3907 (TInt(buffer[offset + 1]) << 8) + |
|
3908 (TInt(buffer[offset + 2]) << 16) + |
|
3909 (TInt(buffer[offset + 3]) << 24); |
|
3910 |
|
3911 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() NAL unit %d frame start: %d "), i, frameStart )); |
|
3912 |
|
3913 // Get frame size |
|
3914 offset += 4; |
|
3915 frameSize = TInt(buffer[offset]) + |
|
3916 (TInt(buffer[offset + 1]) << 8) + |
|
3917 (TInt(buffer[offset + 2]) << 16) + |
|
3918 (TInt(buffer[offset + 3]) << 24); |
|
3919 |
|
3920 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() NAL unit %d frame size: %d "), i, frameSize )); |
|
3921 bufType = buffer[frameStart] & 0x1F; |
|
3922 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() NAL unit %d type: %d "), i, bufType )); |
|
3923 if ( bufType != 7 && //SPS |
|
3924 bufType != 8 )//PPS |
|
3925 { |
|
3926 // we found first NAL unit that isn't SPS or PPS |
|
3927 nalSizes.Append(frameSize); |
|
3928 if (firstCopiedNAL==0) |
|
3929 { |
|
3930 firstCopiedNAL = frameStart; |
|
3931 } |
|
3932 nalStarts.Append(frameStart-firstCopiedNAL); |
|
3933 totalNALLength = frameStart+frameSize-firstCopiedNAL; |
|
3934 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() new total length: %d, padding: %d "), totalNALLength, totalNALLength%4 )); |
|
3935 totalNALLength += totalNALLength%4; |
|
3936 } |
|
3937 } |
|
3938 |
|
3939 // The buffer should have enough space for the new NAL header |
|
3940 |
|
3941 // We need to write a new NAL header just after the frame end |
|
3942 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() writing new header."))); |
|
3943 offset = firstCopiedNAL + totalNALLength; |
|
3944 |
|
3945 if ( (offset + nalSizes.Count()*8 + 4) > buffer.Length() ) |
|
3946 { |
|
3947 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() Fatal error, cannot create header, non-align 32bit encoder output buffer."))); |
|
3948 VRASSERT(0); |
|
3949 } |
|
3950 |
|
3951 for (TInt j=0; j<nalSizes.Count(); j++) |
|
3952 { |
|
3953 PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() new header, unit: %d, start: %d, size: %d."), j, nalStarts[j], nalSizes[j] )); |
|
3954 // Write NAL unit start position |
|
3955 buffer[offset + 0] = TUint8(nalStarts[j] & 0xff); |
|
3956 buffer[offset + 1] = TUint8((nalStarts[j] >> 8) & 0xff); |
|
3957 buffer[offset + 2] = TUint8((nalStarts[j] >> 16) & 0xff); |
|
3958 buffer[offset + 3] = TUint8((nalStarts[j] >> 24) & 0xff); |
|
3959 |
|
3960 // Write NAL unit size |
|
3961 offset +=4; |
|
3962 buffer[offset + 0] = TUint8(nalSizes[j] & 0xff); |
|
3963 buffer[offset + 1] = TUint8((nalSizes[j] >> 8) & 0xff); |
|
3964 buffer[offset + 2] = TUint8((nalSizes[j] >> 16) & 0xff); |
|
3965 buffer[offset + 3] = TUint8((nalSizes[j] >> 24) & 0xff); |
|
3966 |
|
3967 offset +=4; |
|
3968 } |
|
3969 |
|
3970 // Write the number of NAL units |
|
3971 buffer[offset + 0] = TUint8(nalSizes.Count() & 0xff);; |
|
3972 buffer[offset + 1] = TUint8((nalSizes.Count() >> 8) & 0xff);; |
|
3973 buffer[offset + 2] = TUint8((nalSizes.Count() >> 16) & 0xff); |
|
3974 buffer[offset + 3] = TUint8((nalSizes.Count() >> 24) & 0xff); |
|
3975 } |
|
3976 |
|
3977 // Get a pointer to the position where the frame starts |
|
3978 TPtrC8 tmp( (buffer.Ptr() + firstCopiedNAL), (totalNALLength + (nalSizes.Count()*8) + 4) ); |
|
3979 |
|
3980 // Set output media buffer |
|
3981 iOutputSinkBuffer->Set( tmp, CCMRMediaBuffer::EVideoH264NAL, |
|
3982 tmp.Length(), iOutputVideoBuffer->iRandomAccessPoint, |
|
3983 iOutputVideoBuffer->iCaptureTimestamp ); |
|
3984 |
|
3985 nalSizes.Close(); |
|
3986 nalStarts.Close(); |
|
3987 return firstCopiedNAL; |
|
3988 } |
|
3989 |
|
3990 // ----------------------------------------------------------------------------- |
|
3991 // CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader( TDesC8* aVideoBuffer ) |
|
3992 // Removes decoder configuration info (SPS & PPS) from first bytestream encapsulated H.264/AVC video buffer |
|
3993 // from encoder to avoid situation where its both in .mp4 file metadata and in bitstream of video track. |
|
3994 // ----------------------------------------------------------------------------- |
|
3995 // |
|
3996 TInt CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader( TDesC8* aVideoBuffer ) |
|
3997 {// H.264 AVC NAL / EDuElementarystream / Bytestream |
|
3998 TInt skippedBytes = -1; |
|
3999 TInt bufType = 0; |
|
4000 |
|
4001 // Get reference to the buffer |
|
4002 TPtr8* buffer = reinterpret_cast<TPtr8*>(aVideoBuffer); |
|
4003 // Bitstream start point |
|
4004 const TUint8* data = buffer->Ptr(); |
|
4005 |
|
4006 PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() in, length: %d "), buffer->Length() )); |
|
4007 |
|
4008 // check buffer for bytestream header and possible decSpecInfo (SPS & PPS) |
|
4009 for (TInt i=0; i+4< buffer->Length(); i++) |
|
4010 { |
|
4011 // check for bytestream encapsulation [00 00 00 01] |
|
4012 if ( data[i] == 0 && |
|
4013 data[i+1] == 0 && |
|
4014 data[i+2] == 0 && |
|
4015 data[i+3] == 1 ) |
|
4016 { |
|
4017 PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() 0001 header at: %d "), i )); |
|
4018 // search buffer that isn't SPS or PPS |
|
4019 bufType = data[i+4] & 0x1F; |
|
4020 PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() buffer type: %d "), bufType )); |
|
4021 if ( (bufType == 7 || //SPS |
|
4022 bufType == 8) && //PPS |
|
4023 skippedBytes == -1 ) |
|
4024 {// we need to skip SPS and PPS so activate next if clause |
|
4025 skippedBytes = 0; |
|
4026 } |
|
4027 if ( bufType != 7 && //SPS |
|
4028 bufType != 8 && //PPS |
|
4029 skippedBytes == 0) |
|
4030 {// found first non SPS / PPS buffer content -> stop stripping here |
|
4031 skippedBytes = i; |
|
4032 PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() skipping: %d bytes"), skippedBytes )); |
|
4033 } |
|
4034 } |
|
4035 } |
|
4036 /* |
|
4037 if (skippedBytes) |
|
4038 { |
|
4039 for (TInt j=0; j<skippedBytes;j++) |
|
4040 { |
|
4041 PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() skipping %d: %x "), j, data[j] )); |
|
4042 } |
|
4043 } |
|
4044 */ |
|
4045 // Get a pointer to the position where the frame starts |
|
4046 TPtrC8 tmp(buffer->Ptr() + skippedBytes, buffer->Length() - skippedBytes); |
|
4047 |
|
4048 // Set output media buffer |
|
4049 iOutputSinkBuffer->Set( tmp, CCMRMediaBuffer::EVideoH264Bytestream, |
|
4050 tmp.Length(), iOutputVideoBuffer->iRandomAccessPoint, |
|
4051 iOutputVideoBuffer->iCaptureTimestamp ); |
|
4052 |
|
4053 return skippedBytes; |
|
4054 } |
|
4055 |
|
4056 // --------------------------------------------------------- |
|
4057 // CCMRVideoRecorder::CCMRReturnAO::NewL |
|
4058 // Two-phased constructor. |
|
4059 // --------------------------------------------------------- |
|
4060 // |
|
4061 CCMRVideoRecorder::CCMRReturnAO* CCMRVideoRecorder::CCMRReturnAO::NewL(CCMRVideoRecorder* aHost) |
|
4062 { |
|
4063 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::NewL(), In"))) |
|
4064 |
|
4065 CCMRReturnAO* self = new (ELeave) CCMRReturnAO(aHost); |
|
4066 CleanupStack::PushL( self ); |
|
4067 self->ConstructL(); |
|
4068 CleanupStack::Pop(); |
|
4069 |
|
4070 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::NewL(), Out"))) |
|
4071 return self; |
|
4072 } |
|
4073 |
|
4074 // ----------------------------------------------------------------------------- |
|
4075 // CCMRVideoRecorder::CCMRReturnAO::CCMRReturnAO |
|
4076 // Default constructor for CCMRReturnAO |
|
4077 // (other items were commented in a header). |
|
4078 // ----------------------------------------------------------------------------- |
|
4079 // |
|
4080 CCMRVideoRecorder::CCMRReturnAO::CCMRReturnAO(CCMRVideoRecorder* aHost) : |
|
4081 CActive(EPriorityNormal), |
|
4082 iVideoOutputBufferReturnQue(_FOFF(TVideoOutputBuffer,iLink)), |
|
4083 iVideoOutputBufferReturnQueIter(iVideoOutputBufferReturnQue), |
|
4084 iHost(aHost) |
|
4085 { |
|
4086 CActiveScheduler::Add(this); |
|
4087 } |
|
4088 |
|
4089 // --------------------------------------------------------- |
|
4090 // CCMRVideoRecorder::CCMRReturnAO::ConstructL() |
|
4091 // Symbian 2nd phase constructor can leave. |
|
4092 // --------------------------------------------------------- |
|
4093 // |
|
4094 void CCMRVideoRecorder::CCMRReturnAO::ConstructL() |
|
4095 { |
|
4096 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::ConstructL() in"))); |
|
4097 User::LeaveIfError(iMutexObj.CreateLocal()); |
|
4098 iMutexCreated = ETrue; |
|
4099 User::LeaveIfError(iVideoThreadHandle.Open(RThread().Id())); |
|
4100 iThreadHandleOpened = ETrue; |
|
4101 |
|
4102 iStatus = KRequestPending; |
|
4103 SetActive(); |
|
4104 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::ConstructL() out"))); |
|
4105 } |
|
4106 |
|
4107 // ----------------------------------------------------------------------------- |
|
4108 // CCMRVideoRecorder::CCMRReturnAO::~CCMRReturnAO |
|
4109 // Destructor for CCMRReturnAO |
|
4110 // (other items were commented in a header). |
|
4111 // ----------------------------------------------------------------------------- |
|
4112 // |
|
4113 CCMRVideoRecorder::CCMRReturnAO::~CCMRReturnAO() |
|
4114 { |
|
4115 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::~CCMRReturnAO"))); |
|
4116 if ( iMutexCreated ) |
|
4117 { |
|
4118 iMutexObj.Close(); |
|
4119 } |
|
4120 if ( iThreadHandleOpened ) |
|
4121 { |
|
4122 iVideoThreadHandle.Close(); |
|
4123 } |
|
4124 } |
|
4125 |
|
4126 // ----------------------------------------------------------------------------- |
|
4127 // CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer |
|
4128 // Enqueue TVideoOutputBuffer from controller thread to be returned to |
|
4129 // DevVideoRecord from this thread |
|
4130 // (other items were commented in a header). |
|
4131 // ----------------------------------------------------------------------------- |
|
4132 // |
|
4133 void CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer(TVideoOutputBuffer* aBuffer) |
|
4134 { |
|
4135 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer() in aBuffer=0x%x "), aBuffer)); |
|
4136 // enter restricted area |
|
4137 iMutexObj.Wait(); |
|
4138 iVideoOutputBufferReturnQue.AddLast(*aBuffer); |
|
4139 if ( iStatus == KRequestPending ) |
|
4140 { |
|
4141 TRequestStatus* tmp = &iStatus; |
|
4142 iVideoThreadHandle.RequestComplete(tmp, KErrNone); |
|
4143 } |
|
4144 // leave restricted area |
|
4145 iMutexObj.Signal(); |
|
4146 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer() out"))); |
|
4147 } |
|
4148 |
|
4149 |
|
4150 // ----------------------------------------------------------------------------- |
|
4151 // CCMRVideoRecorder::CCMRReturnAO::Flush |
|
4152 // Flush content of return queueu to DevVideo |
|
4153 // (other items were commented in a header). |
|
4154 // ----------------------------------------------------------------------------- |
|
4155 // |
|
4156 void CCMRVideoRecorder::CCMRReturnAO::Flush() |
|
4157 { |
|
4158 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::Flush() in."))); |
|
4159 iMutexObj.Wait(); |
|
4160 while (!iVideoOutputBufferReturnQue.IsEmpty()) |
|
4161 { |
|
4162 // take the oldest buffer |
|
4163 TVideoOutputBuffer* tmp = iVideoOutputBufferReturnQue.First(); |
|
4164 // Remove the picture from the list |
|
4165 tmp->iLink.Deque(); |
|
4166 // send it to DevVR using the CCMRVideoRecorder object |
|
4167 iHost->ReturnBufferToDevVR(tmp); |
|
4168 tmp = NULL; |
|
4169 } |
|
4170 // leave restricted area |
|
4171 iMutexObj.Signal(); |
|
4172 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::Flush() out"))); |
|
4173 } |
|
4174 |
|
4175 // ----------------------------------------------------------------------------- |
|
4176 // CCMRVideoRecorder::CCMRReturnAO::RunL |
|
4177 // Returns the queued buffers |
|
4178 // (other items were commented in a header). |
|
4179 // ----------------------------------------------------------------------------- |
|
4180 // |
|
4181 void CCMRVideoRecorder::CCMRReturnAO::RunL() |
|
4182 { |
|
4183 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunL() - iStatus: %d"), iStatus.Int() )); |
|
4184 SetActive(); |
|
4185 // enter restricted area |
|
4186 iMutexObj.Wait(); |
|
4187 iStatus = KRequestPending; |
|
4188 while (!iVideoOutputBufferReturnQue.IsEmpty()) |
|
4189 { |
|
4190 // take the oldest buffer |
|
4191 TVideoOutputBuffer* tmp = iVideoOutputBufferReturnQue.First(); |
|
4192 // Remove the picture from the list |
|
4193 tmp->iLink.Deque(); |
|
4194 // send it to DevVR using the CCMRVideoRecorder object |
|
4195 iHost->ReturnBufferToDevVR(tmp); |
|
4196 tmp = NULL; |
|
4197 } |
|
4198 // leave restricted area |
|
4199 iMutexObj.Signal(); |
|
4200 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunL() out"))); |
|
4201 } |
|
4202 |
|
4203 // ----------------------------------------------------------------------------- |
|
4204 // CCMRVideoRecorder::CCMRReturnAO::RunError |
|
4205 // Handles errors from RunL |
|
4206 // (other items were commented in a header). |
|
4207 // ----------------------------------------------------------------------------- |
|
4208 // |
|
4209 TInt CCMRVideoRecorder::CCMRReturnAO::RunError(TInt aError) |
|
4210 { |
|
4211 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunError"))); |
|
4212 // currently RunL can't leave, but keep this here to remind the possible need in the future |
|
4213 if (aError != KErrNone) |
|
4214 { |
|
4215 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunError() error %d"),aError)); |
|
4216 } |
|
4217 return KErrNone; |
|
4218 } |
|
4219 |
|
4220 // ----------------------------------------------------------------------------- |
|
4221 // CCMRVideoRecorder::CCMRReturnAO::DoCancel |
|
4222 // Cancels the active object |
|
4223 // (other items were commented in a header). |
|
4224 // ----------------------------------------------------------------------------- |
|
4225 // |
|
4226 void CCMRVideoRecorder::CCMRReturnAO::DoCancel() |
|
4227 { |
|
4228 // Cancel the request |
|
4229 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::DoCancel() in"))); |
|
4230 if ( iStatus == KRequestPending ) |
|
4231 { |
|
4232 TRequestStatus *stat = &iStatus; |
|
4233 User::RequestComplete(stat, KErrCancel); |
|
4234 } |
|
4235 PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::DoCancel() out"))); |
|
4236 } |
|
4237 |
|
4238 // End of file |