|
1 /* |
|
2 * Copyright (c) 2002-2006 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: 3GP file composer |
|
15 * |
|
16 */ |
|
17 |
|
18 // INCLUDE FILES |
|
19 #include <f32file.h> |
|
20 #include <mmf/server/mmffile.h> |
|
21 #include <sysutildomaincrkeys.h> // for critical disk level CentralRepository keys |
|
22 #include <3gplibrary/mp4lib.h> |
|
23 #include "CamC3GPDataSink.h" |
|
24 #include "CamC3GPDataSinkImp.h" |
|
25 #include "CCMRMediaSink.h" |
|
26 #include "CCMRSupportedCodecs.h" |
|
27 |
|
28 #include <stdlib.h> |
|
29 #include <stdio.h> |
|
30 #include <string.h> |
|
31 #include <sys/unistd.h> |
|
32 |
|
33 // MACROS |
|
34 // Debug print macro |
|
35 #ifdef _DEBUG |
|
36 #include <e32svr.h> |
|
37 #define PRINT(x) RDebug::Print x |
|
38 #else |
|
39 #define PRINT(x) |
|
40 #endif |
|
41 |
|
42 // CONSTANTS |
|
43 const TUint KVideoAverageBitRate = 48000; // Default average bitrate for video |
|
44 const TUint KVideoMaxBitRate = 64000; // Default maximum bitrate for video |
|
45 const TUint KVideoXResolution = 176; // Default width of video |
|
46 const TUint KVideoYResolution = 144; // Default height of video |
|
47 const TUint KVideoBufferSize = 8192; // Maximum video frame size |
|
48 const TUint KAudioMaxFrameSize = 32; // Maximum AMR audio frame size |
|
49 const TUint KAudioBufferNumber = 10; // Number of audio frames to be buffered |
|
50 const TUint KVideoTimeScale = 30000; // Video timescale in the output file; use 30000 since it corresponds roughly to ~30 fps. |
|
51 // 29970 would be exact for H.263, but it may not be exactly camera's baseframerate. And it may be harder for some players than 30000 |
|
52 // The most important is now that this value is in the same scale as used in MediaRecorder for Camera API framerate. |
|
53 // If that is 15, then this should be 30000. But some other, e.g. 14.985 fps is used there, then it is better to change this one too. |
|
54 const TUint KAudioTimeScale = 8000; // Audio timescale in the output file, safer to use the same value as sampling rate although makes the times more difficult to understand |
|
55 const TUint KAudioFrameDuration = 8*20; // AMR frame is 20 ms, but timescale is 8000 => duration is 160 / 8000 s |
|
56 const TUint8 KAMRAudioFramesPerSample = 10; // Number of AMR audio frames per sample in the output file |
|
57 const TUint8 KAACAudioFramesPerSample = 1; // Number of AAC audio frames per sample in the output file |
|
58 const TUint KAACDefaultSampleRate = 16000; // Default samplerate for AAC that is used as audio track timescale in case we get no audiobuffers, but audio codec is selected. |
|
59 const TUint16 KAudioModeSet = 0x81ff; // AMR modeset: all modes possible |
|
60 const TUint KDiskSafetyLimit = 400000; // Amount of free disk space to leave unused |
|
61 const TReal KMetaDataCoeff = 1.03; // Coefficient to estimate metadata amount |
|
62 const TInt KFreeDiskSpaceCounter = 10; // Interval when to find out real free disk space |
|
63 const TUint KFTYPSize = 24; // Size of FTYP box in bytes in 3GP files |
|
64 const TUint KCamCMaxClipDurationInSecs = 5400; // Maximun video clip duration in seconds |
|
65 const TInt KLimitForLargeFileBuffers = 100000; // Bitrate limit to toggle to larger output file buffers in composer. |
|
66 const TInt KDelayUseBitrates = 3000000; // Delay used in GetRemainingTime until function uses real file sizes instead of avarage bitrates. |
|
67 const TInt KCamC3GPDeleteFileQueueGranularity = 10; // Optimal value is the number of temporary files |
|
68 const TUint32 KCamC3GPMaximumFileSize = 4294967295UL; // max size for RFile |
|
69 |
|
70 _LIT(KTmpFileName, "\\system\\Temp\\CamcorderTMP"); // Temporary output file name |
|
71 |
|
72 // ============================ MEMBER FUNCTIONS =============================== |
|
73 |
|
74 |
|
75 // ----------------------------------------------------------------------------- |
|
76 // CCamC3GPDataSink::NewL |
|
77 // |
|
78 // Sink constructor. |
|
79 // ----------------------------------------------------------------------------- |
|
80 // |
|
81 EXPORT_C CCamC3GPDataSink* CCamC3GPDataSink::NewL(M3GPDataSinkObserver *aObserver) |
|
82 { |
|
83 CCamC3GPDataSinkImp* self = new (ELeave) CCamC3GPDataSinkImp(); |
|
84 CleanupStack::PushL(self); |
|
85 self->ConstructL(aObserver); |
|
86 CleanupStack::Pop(); |
|
87 return self; |
|
88 } |
|
89 |
|
90 |
|
91 // ----------------------------------------------------------------------------- |
|
92 // CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp |
|
93 // |
|
94 // Sink destructor. |
|
95 // ----------------------------------------------------------------------------- |
|
96 // |
|
97 CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp(void) |
|
98 { |
|
99 PRINT(_L("CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp enter")); |
|
100 delete [] iVideoBuffer; |
|
101 delete [] iAudioBuffer; |
|
102 |
|
103 if ( iFileName != KNullDesC ) |
|
104 { |
|
105 // we need to try to stop sink |
|
106 TInt error = KErrNone; |
|
107 TRAP(error, SinkStopL()); |
|
108 iFileName = KNullDesC; |
|
109 } |
|
110 |
|
111 if (iMP4Handle) |
|
112 { |
|
113 MP4ComposeClose(iMP4Handle); |
|
114 iMP4Handle = NULL; |
|
115 } |
|
116 |
|
117 if (iFS) |
|
118 { |
|
119 iFS->Delete(iTmpFileName); |
|
120 iFS->Close(); |
|
121 delete iFS; |
|
122 iFS = NULL; |
|
123 } |
|
124 |
|
125 iObserver = NULL; |
|
126 iMMFFile = NULL; // not owned |
|
127 iFile = NULL; // not owned |
|
128 |
|
129 // Delete the CIdle async file remover object |
|
130 delete iIdleDelete; |
|
131 iIdleDelete = 0; |
|
132 |
|
133 // Do async temp file deletion for rest of files |
|
134 if ( iDeleteFileQueue ) |
|
135 { |
|
136 // Reset and destroy the file name pointers from queue (if any left). |
|
137 iDeleteFileQueue->ResetAndDestroy(); |
|
138 } |
|
139 delete iDeleteFileQueue; |
|
140 iDeleteFileQueue = 0; |
|
141 PRINT(_L("CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp exit")); |
|
142 } |
|
143 |
|
144 |
|
145 // ----------------------------------------------------------------------------- |
|
146 // CCamC3GPDataSinkImp::ConstructL |
|
147 // |
|
148 // Symbian 2nd phase constructor. |
|
149 // ----------------------------------------------------------------------------- |
|
150 // |
|
151 void CCamC3GPDataSinkImp::ConstructL(M3GPDataSinkObserver *aObserver) |
|
152 { |
|
153 PRINT(_L("CCamC3GPDataSinkImp::ConstructL enter")); |
|
154 iObserver = aObserver; |
|
155 |
|
156 iVideoBuffer = new (ELeave) TUint8[KVideoBufferSize]; |
|
157 iVideoBufferSize = KVideoBufferSize; |
|
158 |
|
159 iAudioBuffer = new (ELeave) TUint8[KAudioMaxFrameSize * KAudioBufferNumber]; |
|
160 iAudioBufferSize = KAudioMaxFrameSize * KAudioBufferNumber; |
|
161 |
|
162 iMP4Handle = NULL; |
|
163 iMMFFile = NULL; |
|
164 |
|
165 iFileName = KNullDesC; |
|
166 |
|
167 iBytesReceived = 0; |
|
168 iBytesOfMetadata = 0; |
|
169 |
|
170 iVideoXResolution = 0; |
|
171 iVideoYResolution = 0; |
|
172 iVideoAverageBitRate = -1; |
|
173 iVideoMaxBitRate = -1; |
|
174 iAudioAverageBitRate = -1; |
|
175 |
|
176 iBufferSize = 0; |
|
177 iFileCodecType = MP4_TYPE_NONE; |
|
178 iVideoTimestamp = 0; |
|
179 iVideoBufferTimestamp = -1; |
|
180 iFirstVideoFrameTimestamp = 0; |
|
181 iVideoRandomAccessPoint = EFalse; |
|
182 iVideoBufferRandomAccessPoint = EFalse; |
|
183 iVideoFrameDuration = 0; |
|
184 iVideoBufferFrameSize = 0; |
|
185 iVideoFrameNumber = 0; |
|
186 iVideoIntraFrameNumber = 0; |
|
187 iVideoDecSpecInfoSize = 0; |
|
188 iAudioDecSpecInfoSize = 0; |
|
189 iAudioBufferFrameSize = 0; |
|
190 iAudioFrameNumber = 0; |
|
191 iAudioFramesInBuffer = 0; |
|
192 iFreeDiskSpace = 0; |
|
193 iFreeDiskSpaceCounter = 0; |
|
194 iAvailableSpaceAtStart = 0; |
|
195 iAvarageEndTime = -1; |
|
196 iAudioAACFrameDuration = 0; |
|
197 iAudioAACSamplerate = 0; |
|
198 iAVCOutputLevel = 10; |
|
199 iCriticalDiskVal = 0; |
|
200 |
|
201 iSizeLimit = KCamC3GPMaximumFileSize; // max size for RFile |
|
202 iFileSizeLimitReached = EFalse; |
|
203 iDiskFull = EFalse; |
|
204 iFS = NULL; |
|
205 |
|
206 iDeleteFileQueue = new( ELeave ) RPointerArray<MP4FileName>( KCamC3GPDeleteFileQueueGranularity ); |
|
207 |
|
208 // Idle priority Active object for async video temp file deletion |
|
209 iIdleDelete = CIdle::NewL( CActive::EPriorityIdle ); |
|
210 |
|
211 PRINT(_L("CCamC3GPDataSinkImp::ConstructL exit")); |
|
212 } |
|
213 |
|
214 // ----------------------------------------------------------------------------- |
|
215 // CCamC3GPDataSinkImp::OpenFileL |
|
216 // |
|
217 // Opens a 3GP file for writing. |
|
218 // ----------------------------------------------------------------------------- |
|
219 // |
|
220 void CCamC3GPDataSinkImp::OpenFileL(CMMFFile* aMMFFile, TFourCC aAudioCodecType, const TDesC8& aVideoCodecType, TCamCSinkFileFormat aFileFormat ) |
|
221 { |
|
222 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL CMMFFile enter"))); |
|
223 |
|
224 TFileName aFileName; |
|
225 iMMFFile = aMMFFile; |
|
226 aFileName = iMMFFile->FullName(); |
|
227 |
|
228 OpenFileL(aFileName, aAudioCodecType, aVideoCodecType, aFileFormat); |
|
229 } |
|
230 |
|
231 // ----------------------------------------------------------------------------- |
|
232 // CCamC3GPDataSinkImp::OpenFileL |
|
233 // |
|
234 // Opens a 3GP file for writing. |
|
235 // ----------------------------------------------------------------------------- |
|
236 // |
|
237 void CCamC3GPDataSinkImp::OpenFileL(TFileName aFileName, TFourCC aAudioCodecType, const TDesC8& aVideoCodecType, TCamCSinkFileFormat aFileFormat) |
|
238 { |
|
239 MP4Err error; |
|
240 |
|
241 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL TFileName enter"))); |
|
242 |
|
243 if (iMP4Handle) |
|
244 { |
|
245 User::Leave(KErrGeneral); |
|
246 } |
|
247 |
|
248 iVideoBufferTimestamp = -1; // reset duration information for new file |
|
249 iFirstVideoFrameTimestamp = 0; |
|
250 iAvailableSpaceAtStart = 0; |
|
251 iAvarageEndTime = -1; |
|
252 iVideoFrameNumber = 0; |
|
253 iVideoIntraFrameNumber = 0; |
|
254 iBytesReceived = 0; |
|
255 iAudioAACFrameDuration = 0; |
|
256 iAudioAACSamplerate = 0; |
|
257 iFileHandleExists = EFalse; |
|
258 |
|
259 iDiskFull = EFalse; |
|
260 iTmpFileName = KTmpFileName; |
|
261 iFileName = aFileName; |
|
262 TInt errorcode; |
|
263 |
|
264 if (!iFS) // Don't allocate new file server, if there is one already |
|
265 { |
|
266 iFS = new (ELeave) RFs; |
|
267 |
|
268 errorcode = iFS->Connect(); |
|
269 if ( errorcode != KErrNone) |
|
270 { |
|
271 delete(iFS); |
|
272 iFS = NULL; |
|
273 User::Leave( errorcode ); |
|
274 } |
|
275 } |
|
276 |
|
277 TParse fp; |
|
278 User::LeaveIfError(iFS->Parse(iFileName, fp)); |
|
279 TPtrC driveletter = fp.Drive(); |
|
280 TChar drl = driveletter[0]; |
|
281 User::LeaveIfError(iFS->CharToDrive(drl, iDriveNumber)); |
|
282 |
|
283 // Get critical level for this drive type |
|
284 TDriveInfo driveInfo; |
|
285 iFS->Drive(driveInfo, iDriveNumber); |
|
286 |
|
287 iCriticalDiskVal = 0; |
|
288 if ( driveInfo.iType == EMediaRam ) // RAM drives have different critical levent than others |
|
289 { |
|
290 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Asking disk critical level, memtype: EMediaRam"))); |
|
291 CRepository* repository = CRepository::NewLC( KCRUidDiskLevel ); |
|
292 User::LeaveIfError( repository->Get( KRamDiskCriticalLevel, iCriticalDiskVal ) ); |
|
293 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Got disk critical level: %d"),iCriticalDiskVal )); |
|
294 CleanupStack::PopAndDestroy( repository ); |
|
295 } |
|
296 else // Some other media type |
|
297 { |
|
298 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Asking disk critical level, memtype: other"))); |
|
299 CRepository* repository = CRepository::NewLC( KCRUidDiskLevel ); |
|
300 User::LeaveIfError( repository->Get( KDiskCriticalThreshold, iCriticalDiskVal ) ); |
|
301 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Got disk critical level: %d"),iCriticalDiskVal )); |
|
302 CleanupStack::PopAndDestroy( repository ); |
|
303 } |
|
304 |
|
305 errorcode = iFS->MkDirAll(fp.DriveAndPath()); |
|
306 if ( (errorcode != KErrAlreadyExists ) && ( errorcode != KErrNone ) ) |
|
307 { |
|
308 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Error creating output path: '%s', error: %d"), fp.DriveAndPath().Ptr(), errorcode )); |
|
309 User::Leave(errorcode); |
|
310 } |
|
311 |
|
312 errorcode = iFS->SetAtt( iFileName, KEntryAttNormal, KEntryAttReadOnly ); |
|
313 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Deleting File: '%s'"), iFileName.Ptr())); |
|
314 errorcode = iFS->Delete(iFileName); |
|
315 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Deleting File Error: %d"), errorcode)); |
|
316 |
|
317 if ( errorcode == KErrInUse && iMMFFile ) |
|
318 { |
|
319 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL using rfiles"))); |
|
320 iMMFFile->SinkPrimeL(); |
|
321 iFile = &(iMMFFile->FileL()); |
|
322 iFileHandleExists = ETrue; |
|
323 } |
|
324 else if ( ( errorcode != KErrNone ) && ( errorcode != KErrNotFound ) && ( errorcode != KErrPathNotFound ) ) |
|
325 { |
|
326 User::Leave(errorcode); |
|
327 } |
|
328 |
|
329 iTmpFileName.Insert(0, fp.Drive()); |
|
330 errorcode = iFS->SetAtt( iTmpFileName, KEntryAttNormal, KEntryAttReadOnly ); |
|
331 errorcode = iFS->Delete(iTmpFileName); |
|
332 if ( ( errorcode != KErrNone ) && ( errorcode != KErrNotFound ) && ( errorcode != KErrPathNotFound ) ) |
|
333 { |
|
334 if ( errorcode == KErrInUse ) |
|
335 { |
|
336 // use actual output filename incase other instance still running with temporary file. |
|
337 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL temporary output file in use (-14). Using actual output filename instead."))); |
|
338 iTmpFileName = aFileName; |
|
339 errorcode = iFS->SetAtt( iTmpFileName, KEntryAttNormal, KEntryAttReadOnly ); |
|
340 errorcode = iFS->Delete(iTmpFileName); |
|
341 if ( ( errorcode != KErrNone ) && ( errorcode != KErrNotFound ) && ( errorcode != KErrPathNotFound ) ) |
|
342 { |
|
343 User::Leave(errorcode); |
|
344 } |
|
345 } |
|
346 else |
|
347 { |
|
348 User::Leave(errorcode); |
|
349 } |
|
350 } |
|
351 |
|
352 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Temp files cleared"))); |
|
353 |
|
354 // Find used audio codec |
|
355 if ( ( aAudioCodecType == TFourCC(KCMRFourCCIdAMRNB) ) ) // AMR-NB |
|
356 { |
|
357 iFileCodecType |= MP4_TYPE_AMR_NB; |
|
358 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Audio codec: AMR-NB"))); |
|
359 } |
|
360 else if ( aAudioCodecType == TFourCC(KCMRFourCCIdMPEG4AAC) ) // AAC |
|
361 { |
|
362 iFileCodecType |= MP4_TYPE_MPEG4_AUDIO; |
|
363 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Audio codec: AAC"))); |
|
364 } |
|
365 else |
|
366 { |
|
367 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Audio codec: none"))); |
|
368 // if audio codec is null we don't generate audiotrack to composed file. |
|
369 } |
|
370 |
|
371 // Find used video codec |
|
372 mp4_u8 videoLevel = 10; |
|
373 |
|
374 if ( aVideoCodecType == KNullDesC8 ) // No video codec set. |
|
375 { |
|
376 // filecomposer will always create videotrack, whether we get video frames or not. |
|
377 iFileCodecType |= MP4_TYPE_H263_PROFILE_0; |
|
378 } |
|
379 else |
|
380 { |
|
381 TBuf8<256> matchstring; |
|
382 matchstring = KCMRMimeTypeH263; |
|
383 matchstring += _L8( "*" ); |
|
384 |
|
385 if ( ( aVideoCodecType.MatchF( matchstring ) != KErrNotFound ) ) // H.263 |
|
386 { |
|
387 matchstring = KCMRMimeTypeH263Profile3; |
|
388 matchstring += _L8( "*" ); |
|
389 |
|
390 if ( aVideoCodecType.MatchF( matchstring ) != KErrNotFound ) |
|
391 { |
|
392 iFileCodecType |= MP4_TYPE_H263_PROFILE_3; // H.263 profile 3 |
|
393 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 profile 3"))); |
|
394 } |
|
395 else |
|
396 { |
|
397 iFileCodecType |= MP4_TYPE_H263_PROFILE_0; // H.263 profile 0 |
|
398 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 profile 0"))); |
|
399 } |
|
400 // check if level is indicated too |
|
401 matchstring = _L8("*level=*"); |
|
402 if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound ) |
|
403 { |
|
404 // yes, there is, check what it is |
|
405 if ( aVideoCodecType.MatchF( _L8("*level=10*") ) != KErrNotFound ) |
|
406 { |
|
407 videoLevel = 10; |
|
408 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 10"))); |
|
409 } |
|
410 else if ( aVideoCodecType.MatchF( _L8("*level=20*") ) != KErrNotFound ) |
|
411 { |
|
412 videoLevel = 20; |
|
413 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 20"))); |
|
414 } |
|
415 else if ( aVideoCodecType.MatchF( _L8("*level=30*") ) != KErrNotFound ) |
|
416 { |
|
417 videoLevel = 30; |
|
418 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 30"))); |
|
419 } |
|
420 else if ( aVideoCodecType.MatchF( _L8("*level=40*") ) != KErrNotFound ) |
|
421 { |
|
422 videoLevel = 40; |
|
423 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 40"))); |
|
424 } |
|
425 else if ( aVideoCodecType.MatchF( _L8("*level=45*") ) != KErrNotFound ) |
|
426 { |
|
427 videoLevel = 45; |
|
428 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 45"))); |
|
429 } |
|
430 else if ( aVideoCodecType.MatchF( _L8("*level=50*") ) != KErrNotFound ) |
|
431 { |
|
432 videoLevel = 50; |
|
433 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 50"))); |
|
434 } |
|
435 else |
|
436 { |
|
437 // assume 10 |
|
438 videoLevel = 10; |
|
439 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 10"))); |
|
440 } |
|
441 } |
|
442 } |
|
443 else // MPEG-4 |
|
444 { |
|
445 matchstring = KCMRMimeTypeMPEG4V; |
|
446 matchstring += _L8( "*" ); |
|
447 |
|
448 if ( aVideoCodecType.MatchF(matchstring) != KErrNotFound ) |
|
449 { |
|
450 iFileCodecType |= MP4_TYPE_MPEG4_VIDEO; // MPEG-4 |
|
451 } |
|
452 else // H.264 AVC |
|
453 { |
|
454 matchstring = KCMRMimeTypeH264AVC; |
|
455 matchstring += _L8( "*" ); |
|
456 |
|
457 if ( aVideoCodecType.MatchF(matchstring) != KErrNotFound ) |
|
458 { |
|
459 iAVCOutputLevel = 10; |
|
460 // check if profile & level is indicated too |
|
461 matchstring = _L8("*profile-level-id=*"); |
|
462 if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound ) |
|
463 { |
|
464 // yes, there is, check what it is |
|
465 // Determine if other AVC profile is used: |
|
466 matchstring = _L8( "*profile-level-id=42*" ); // Main Profile |
|
467 if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound) |
|
468 { |
|
469 iFileCodecType |= MP4_TYPE_AVC_PROFILE_BASELINE; // H.264 AVC Baseline profile found |
|
470 } |
|
471 matchstring = _L8( "*profile-level-id=4D*" ); // Main Profile |
|
472 if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound) |
|
473 { |
|
474 iFileCodecType |= MP4_TYPE_AVC_PROFILE_MAIN; // H.264 AVC Main profile found |
|
475 } |
|
476 matchstring = _L8( "*profile-level-id=64*" ); // High Profile |
|
477 if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound) |
|
478 { |
|
479 iFileCodecType |= MP4_TYPE_AVC_PROFILE_HIGH; // H.264 AVC Baseline profile found |
|
480 } |
|
481 |
|
482 // Determine if other AVC level is used: |
|
483 if ( aVideoCodecType.MatchF( _L8("*00A*") ) != KErrNotFound ) |
|
484 { |
|
485 iAVCOutputLevel = 10; // Level 1 |
|
486 } |
|
487 else if ( (aVideoCodecType.MatchF( _L8("*profile-level-id=42900B*") ) != KErrNotFound) || |
|
488 (aVideoCodecType.MatchF( _L8("*profile-level-id=4D500B*") ) != KErrNotFound) || |
|
489 (aVideoCodecType.MatchF( _L8("*profile-level-id=644009*") ) != KErrNotFound) ) |
|
490 { |
|
491 iAVCOutputLevel = 101; // Level 1b |
|
492 } |
|
493 else if ( (aVideoCodecType.MatchF( _L8("*profile-level-id=42800B*") ) != KErrNotFound) || |
|
494 (aVideoCodecType.MatchF( _L8("*profile-level-id=4D400B*") ) != KErrNotFound) || |
|
495 (aVideoCodecType.MatchF( _L8("*profile-level-id=64400B*") ) != KErrNotFound) ) |
|
496 { |
|
497 iAVCOutputLevel = 11; // Level 1.1 |
|
498 } |
|
499 else if ( aVideoCodecType.MatchF( _L8("*00C*") ) != KErrNotFound ) |
|
500 { |
|
501 iAVCOutputLevel = 12; // Level 1.2 |
|
502 } |
|
503 else if ( aVideoCodecType.MatchF( _L8("*00D*") ) != KErrNotFound ) |
|
504 { |
|
505 iAVCOutputLevel = 13; // Level 1.3 |
|
506 } |
|
507 else if ( aVideoCodecType.MatchF( _L8("*014*") ) != KErrNotFound ) |
|
508 { |
|
509 iAVCOutputLevel = 20; // Level 2 |
|
510 } |
|
511 else if ( aVideoCodecType.MatchF( _L8("*015*") ) != KErrNotFound ) |
|
512 { |
|
513 iAVCOutputLevel = 21; // Level 2.1 |
|
514 } |
|
515 else if ( aVideoCodecType.MatchF( _L8("*016*") ) != KErrNotFound ) |
|
516 { |
|
517 iAVCOutputLevel = 22; // Level 2.2 |
|
518 } |
|
519 else if ( aVideoCodecType.MatchF( _L8("*01E*") ) != KErrNotFound ) |
|
520 { |
|
521 iAVCOutputLevel = 30; // Level 3 |
|
522 } |
|
523 else if ( aVideoCodecType.MatchF( _L8("*01F*") ) != KErrNotFound ) |
|
524 { |
|
525 iAVCOutputLevel = 31; // Level 3.1 |
|
526 } |
|
527 else if ( aVideoCodecType.MatchF( _L8("*020*") ) != KErrNotFound ) |
|
528 { |
|
529 iAVCOutputLevel = 32; // Level 3.2 |
|
530 } |
|
531 else if ( aVideoCodecType.MatchF( _L8("*028*") ) != KErrNotFound ) |
|
532 { |
|
533 iAVCOutputLevel = 4; // Level 4 |
|
534 } |
|
535 else |
|
536 { |
|
537 // assume level 1 |
|
538 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Warning unknown video codec type - defaulting level 1.0"))); |
|
539 iAVCOutputLevel = 10; |
|
540 } |
|
541 } |
|
542 } |
|
543 else |
|
544 { |
|
545 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Unsupported video codec type"))); |
|
546 User::Leave(KErrArgument); |
|
547 } |
|
548 } |
|
549 } |
|
550 } |
|
551 |
|
552 if ( iFileHandleExists ) |
|
553 { |
|
554 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL using rfile to open mp4handle"))); |
|
555 error = MP4ComposeOpenFileHandle(&iMP4Handle, iFile, (TDriveNumber)iDriveNumber, iFileCodecType); |
|
556 } |
|
557 else |
|
558 { |
|
559 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL using descriptors to open mp4handle"))); |
|
560 error = MP4ComposeOpen(&iMP4Handle, (MP4FileName)iTmpFileName.Ptr(), iFileCodecType); |
|
561 } |
|
562 |
|
563 if ( error == MP4_OUT_OF_MEMORY ) |
|
564 { |
|
565 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeOpen, error=%d"), error)); |
|
566 User::Leave(KErrNoMemory); |
|
567 } |
|
568 else if (error != MP4_OK) |
|
569 { |
|
570 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeOpen, error=%d"), error)); |
|
571 TInt64 currentdiskspace = DriveFreeSpaceL(); |
|
572 iFileName = KNullDesC; |
|
573 |
|
574 if ( currentdiskspace < ((TInt64)KDiskSafetyLimit+iCriticalDiskVal+CurrentMetadataSize()) ) |
|
575 { |
|
576 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL disk full, available: %d"), I64INT(currentdiskspace))); |
|
577 iDiskFull = ETrue; |
|
578 User::Leave(KErrDiskFull); |
|
579 } |
|
580 else |
|
581 { |
|
582 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Compose and Open failed, error=%d"), error)); |
|
583 iFileName = KNullDesC; |
|
584 User::Leave(KErrGeneral); |
|
585 } |
|
586 } |
|
587 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Compose and Open done"))); |
|
588 |
|
589 mp4_u32 composeFlags = 0; |
|
590 if ( aFileFormat == E3GPP2 ) |
|
591 { |
|
592 composeFlags |= ( MP4_FLAG_METADATALAST | MP4_FLAG_LONGCLIP | MP4_FLAG_GENERATE_3G2); |
|
593 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Fileformat: 3G2"))); |
|
594 } |
|
595 else if ( aFileFormat == EMPEG4 ) |
|
596 { |
|
597 composeFlags |= ( MP4_FLAG_METADATALAST | MP4_FLAG_LONGCLIP | MP4_FLAG_GENERATE_MP4); |
|
598 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Fileformat: MP4"))); |
|
599 } |
|
600 else // E3GPP |
|
601 { |
|
602 composeFlags |= ( MP4_FLAG_METADATALAST | MP4_FLAG_LONGCLIP ); |
|
603 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Fileformat: 3GP"))); |
|
604 } |
|
605 |
|
606 if ( ( iVideoMaxBitRate + iAudioAverageBitRate ) >= KLimitForLargeFileBuffers ) |
|
607 { |
|
608 composeFlags |= MP4_FLAG_LARGEFILEBUFFER; |
|
609 } |
|
610 |
|
611 error = MP4ComposeSetFlags(iMP4Handle, composeFlags ); |
|
612 if ( error == MP4_OUT_OF_MEMORY ) |
|
613 { |
|
614 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeSetFlags, error=%d"), error)); |
|
615 User::Leave(KErrNoMemory); |
|
616 } |
|
617 else if (error != MP4_OK) |
|
618 { |
|
619 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeSetFlags, error=%d"), error)); |
|
620 TInt64 currentdiskspace2 = DriveFreeSpaceL(); |
|
621 |
|
622 if ( currentdiskspace2 < ((TInt64)KDiskSafetyLimit+iCriticalDiskVal+CurrentMetadataSize()) ) |
|
623 { |
|
624 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL disk full, available: %d"), I64INT(currentdiskspace2))); |
|
625 iDiskFull = ETrue; |
|
626 User::Leave(KErrDiskFull); |
|
627 } |
|
628 else |
|
629 { |
|
630 User::Leave(KErrGeneral); |
|
631 } |
|
632 } |
|
633 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Compose flags set"))); |
|
634 |
|
635 if ((iFileCodecType & MP4_TYPE_H263_PROFILE_0) || |
|
636 (iFileCodecType & MP4_TYPE_H263_PROFILE_3) || |
|
637 (iFileCodecType & MP4_TYPE_MPEG4_VIDEO) || |
|
638 (iFileCodecType & MP4_TYPE_AVC_PROFILE_BASELINE) || |
|
639 (iFileCodecType & MP4_TYPE_AVC_PROFILE_MAIN) || |
|
640 (iFileCodecType & MP4_TYPE_AVC_PROFILE_HIGH)) |
|
641 { |
|
642 // Set default values for video parameters if they are not set |
|
643 if (iVideoAverageBitRate < 0) |
|
644 { |
|
645 iVideoAverageBitRate = KVideoAverageBitRate; |
|
646 } |
|
647 if (iVideoMaxBitRate < 0) |
|
648 { |
|
649 iVideoMaxBitRate = KVideoMaxBitRate; |
|
650 } |
|
651 if (iVideoXResolution == 0) |
|
652 { |
|
653 iVideoXResolution = KVideoXResolution; |
|
654 } |
|
655 if (iVideoYResolution == 0) |
|
656 { |
|
657 iVideoYResolution = KVideoYResolution; |
|
658 } |
|
659 |
|
660 error = MP4ComposeAddVideoDescription(iMP4Handle, |
|
661 (mp4_u32)KVideoTimeScale, |
|
662 (mp4_u16)iVideoXResolution, |
|
663 (mp4_u16)iVideoYResolution, |
|
664 (mp4_u32)iVideoMaxBitRate, |
|
665 (mp4_u32)iVideoAverageBitRate); |
|
666 |
|
667 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeAddVideoDescription, error=%d"), error)); |
|
668 if (error != MP4_OK) |
|
669 { |
|
670 User::Leave(KErrGeneral); |
|
671 } |
|
672 if ( (iFileCodecType & (MP4_TYPE_H263_PROFILE_0 | MP4_TYPE_H263_PROFILE_3)) |
|
673 && ( videoLevel != 10) ) |
|
674 { |
|
675 // H.263 level should be given to 3gp library like this |
|
676 error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle, |
|
677 (mp4_u8*)&videoLevel, |
|
678 (mp4_u32)1); |
|
679 if ( error != MP4_OK ) |
|
680 { |
|
681 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error)); |
|
682 User::Leave(KErrGeneral); |
|
683 } |
|
684 } |
|
685 } |
|
686 |
|
687 if (iFileCodecType & MP4_TYPE_AMR_NB) |
|
688 { |
|
689 error = MP4ComposeAddAudioDescription(iMP4Handle, |
|
690 (mp4_u32)KAudioTimeScale, |
|
691 (mp4_u8)KAMRAudioFramesPerSample, |
|
692 (mp4_u16)KAudioModeSet); |
|
693 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeAddAudioDescription, AMR-NB error=%d"), error)); |
|
694 if (error != MP4_OK) |
|
695 { |
|
696 User::Leave(KErrGeneral); |
|
697 } |
|
698 } |
|
699 |
|
700 if ( iFileCodecType & MP4_TYPE_MPEG4_AUDIO) |
|
701 { |
|
702 // To make sure we always write proper timescale to output file (even in case when we get no audio |
|
703 // buffers) the default samplerate is passed to 3GP library here. |
|
704 // When we get audio decoder specific information in WriteBuffer() the MP4ComposeAddAudioDescription() |
|
705 // will be called again with correct samplerate. |
|
706 error = MP4ComposeAddAudioDescription(iMP4Handle, |
|
707 (mp4_u32)KAACDefaultSampleRate, |
|
708 (mp4_u8)KAACAudioFramesPerSample, |
|
709 (mp4_u16)KAudioModeSet); |
|
710 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeAddAudioDescription, AAC error=%d"), error)); |
|
711 if (error != MP4_OK) |
|
712 { |
|
713 User::Leave(KErrGeneral); |
|
714 } |
|
715 } |
|
716 |
|
717 if ( iAvailableSpaceAtStart == 0 ) |
|
718 { |
|
719 TVolumeInfo volumeinfo; |
|
720 User::LeaveIfError(iFS->Volume(volumeinfo, iDriveNumber)); |
|
721 iAvailableSpaceAtStart = volumeinfo.iFree - (TInt64)(KDiskSafetyLimit+iCriticalDiskVal); |
|
722 } |
|
723 |
|
724 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Setting async file remover handler"))); |
|
725 error = MP4ComposeSetTempFileRemoverObserver(&iMP4Handle, this); |
|
726 if (error != MP4_OK) |
|
727 { |
|
728 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Setting async file remover handler FAILED"))); |
|
729 } |
|
730 |
|
731 PRINT((_L("CCamC3GPDataSinkImp::OpenFileL exit"))); |
|
732 } |
|
733 |
|
734 |
|
735 // ----------------------------------------------------------------------------- |
|
736 // CCamC3GPDataSinkImp::SetSizeLimit |
|
737 // |
|
738 // Set size limit of the 3GP file to be recorded in bytes. The limit must be |
|
739 // set before the recording starts. |
|
740 // ----------------------------------------------------------------------------- |
|
741 // |
|
742 void CCamC3GPDataSinkImp::SetSizeLimit(TUint aSize) |
|
743 { |
|
744 PRINT((_L("CCamC3GPDataSinkImp::SetSizeLimit enter, requested limit: %u"), aSize)); |
|
745 if (iBytesReceived) |
|
746 { |
|
747 PRINT(_L("CCamC3GPDataSinkImp::SetSizeLimit NOT set, recording")); |
|
748 return; |
|
749 } |
|
750 |
|
751 TInt64 rfileMaxSize = KCamC3GPMaximumFileSize; |
|
752 if ( aSize == 0 || aSize > rfileMaxSize ) |
|
753 { |
|
754 PRINT((_L("CCamC3GPDataSinkImp::SetSizeLimit 0 or over RFile max size, using internal max instead."))); |
|
755 iSizeLimit = rfileMaxSize; //max size for RFile |
|
756 } |
|
757 else |
|
758 { |
|
759 iSizeLimit = aSize; |
|
760 } |
|
761 PRINT((_L("CCamC3GPDataSinkImp::SetSizeLimit set to: high:%u low:%u"), I64HIGH(iSizeLimit), I64LOW(iSizeLimit))); |
|
762 } |
|
763 |
|
764 |
|
765 // ----------------------------------------------------------------------------- |
|
766 // CCamC3GPDataSinkImp::GetElapsedTime |
|
767 // |
|
768 // Return the amount of time recording has been on in microseconds. |
|
769 // ----------------------------------------------------------------------------- |
|
770 // |
|
771 TTimeIntervalMicroSeconds CCamC3GPDataSinkImp::GetElapsedTime() |
|
772 { |
|
773 PRINT(_L("CCamC3GPDataSinkImp::GetElapsedTime in")); |
|
774 TTimeIntervalMicroSeconds elapsed; |
|
775 if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) |
|
776 { |
|
777 elapsed = 0; |
|
778 } |
|
779 else |
|
780 { |
|
781 elapsed = iVideoBufferTimestamp.Int64() - iFirstVideoFrameTimestamp.Int64(); |
|
782 } |
|
783 PRINT((_L("CCamC3GPDataSinkImp::GetElapsedTime out, elapsed=%d"), I64INT(elapsed.Int64()) )); |
|
784 return elapsed; |
|
785 } |
|
786 |
|
787 |
|
788 // ----------------------------------------------------------------------------- |
|
789 // CCamC3GPDataSinkImp::GetRemainingTime |
|
790 // |
|
791 // Return the estimated remaining time for the recording in microseconds. |
|
792 // This method takes into account the file size and disk full restrictions. |
|
793 // ----------------------------------------------------------------------------- |
|
794 // |
|
795 TTimeIntervalMicroSeconds CCamC3GPDataSinkImp::GetRemainingTimeL() |
|
796 { |
|
797 TTimeIntervalMicroSeconds elapsed; |
|
798 TTimeIntervalMicroSeconds remaining; |
|
799 TTimeIntervalMicroSeconds endtime; |
|
800 TInt64 availableSpace; |
|
801 TInt64 usedSpace; |
|
802 TInt64 metaDataSize; |
|
803 TBool remainingFromSizeLimit = EFalse; |
|
804 |
|
805 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL in"))); |
|
806 |
|
807 if ( iAvailableSpaceAtStart == 0 ) |
|
808 { |
|
809 TVolumeInfo volumeinfo; |
|
810 User::LeaveIfError(iFS->Volume(volumeinfo, iDriveNumber)); |
|
811 iAvailableSpaceAtStart = volumeinfo.iFree - (TInt64)(KDiskSafetyLimit+iCriticalDiskVal); |
|
812 } |
|
813 |
|
814 if (iSizeLimit && ( iSizeLimit < iAvailableSpaceAtStart ) ) |
|
815 { |
|
816 // use sizelimit as available space. |
|
817 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL Limiting remainingtime by sizelimit: %d."), I64INT(iSizeLimit))); |
|
818 remainingFromSizeLimit = ETrue; |
|
819 } |
|
820 else |
|
821 { |
|
822 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL Limiting remainingtime by available space at start: %d "), I64INT(iAvailableSpaceAtStart) )); |
|
823 } |
|
824 |
|
825 if ( iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0) ) |
|
826 { |
|
827 elapsed = 0; |
|
828 } |
|
829 else |
|
830 { |
|
831 elapsed = iVideoBufferTimestamp.Int64() - iFirstVideoFrameTimestamp.Int64(); |
|
832 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL elapsed with first=%d current=%d elapsed=%d"), I64INT(iFirstVideoFrameTimestamp.Int64()), I64INT(iVideoBufferTimestamp.Int64()), I64INT(elapsed.Int64()) )); |
|
833 } |
|
834 |
|
835 if (elapsed < (TTimeIntervalMicroSeconds)((TInt64)KDelayUseBitrates) ) |
|
836 { |
|
837 // Use average audio/video bitrates to estimate remaining time |
|
838 TUint averageBitRate; |
|
839 TUint averageByteRate; |
|
840 |
|
841 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: BitRates Video: %d , Audio: %d"), iVideoAverageBitRate, iAudioAverageBitRate )); |
|
842 |
|
843 averageBitRate = (TUint)((iVideoAverageBitRate + iAudioAverageBitRate) * KMetaDataCoeff); |
|
844 averageByteRate = averageBitRate / 8; |
|
845 |
|
846 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: avaragebitrate: %d , avaragebyterate: %d"), averageBitRate, averageByteRate )); |
|
847 |
|
848 usedSpace = elapsed.Int64() * averageByteRate / 1000000; // 1000000 is for conversion between microseconds and seconds |
|
849 |
|
850 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: elapsed: %d, usedspace: %d"), I64INT(elapsed.Int64()), usedSpace )); |
|
851 |
|
852 metaDataSize = 2*CurrentMetadataSize(); |
|
853 if (remainingFromSizeLimit) |
|
854 { |
|
855 availableSpace = iSizeLimit - usedSpace - metaDataSize; |
|
856 } |
|
857 else |
|
858 { |
|
859 availableSpace = iAvailableSpaceAtStart - usedSpace - metaDataSize; |
|
860 } |
|
861 |
|
862 if (availableSpace <= 0 || averageByteRate == 0) |
|
863 { |
|
864 remaining = 0; |
|
865 } |
|
866 else |
|
867 { |
|
868 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: availablespace: %d, atStart: %d "), I64INT(elapsed.Int64()), I64INT(iAvailableSpaceAtStart) )); |
|
869 |
|
870 remaining = availableSpace * 1000000 / averageByteRate; // 1000000 is for conversion between microseconds and seconds |
|
871 |
|
872 if ( (remaining.Int64() + elapsed.Int64()) > (TInt64(KCamCMaxClipDurationInSecs)*1000000) ) |
|
873 { |
|
874 remaining = (TInt64(KCamCMaxClipDurationInSecs)*1000000) - elapsed.Int64(); |
|
875 } |
|
876 |
|
877 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: remaining: %d "), I64INT(remaining.Int64()) )); |
|
878 } |
|
879 |
|
880 // update also iAvarageEndTime to smooth jump at KDelayUseBitrates sec point. |
|
881 iAvarageEndTime = elapsed.Int64()+ remaining.Int64(); |
|
882 } |
|
883 else // use real filesize estimates. |
|
884 { |
|
885 // used space is mediadata + 2x metadata (metadata in temp-files written and additionaö reserved space for stop copying it to output file. |
|
886 usedSpace = CurrentFileSize()+ 2*CurrentMetadataSize(); |
|
887 if (remainingFromSizeLimit) |
|
888 { |
|
889 availableSpace = iSizeLimit - usedSpace; |
|
890 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL availableSpace from sizelimit: %d "), I64INT(iAvailableSpaceAtStart) )); |
|
891 } |
|
892 else |
|
893 { |
|
894 availableSpace = iAvailableSpaceAtStart - usedSpace; |
|
895 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL availableSpace from availablespaceAtStart: %d "), I64INT(iAvailableSpaceAtStart) )); |
|
896 } |
|
897 |
|
898 if (availableSpace <= 0) |
|
899 { |
|
900 remaining = 0; |
|
901 } |
|
902 else |
|
903 { |
|
904 // preserve integer precision by scaling the first dividend up in calculation |
|
905 if (remainingFromSizeLimit) |
|
906 { |
|
907 // divide the greater of iSizeLimit and elapsed with usedSpace first to prevent overflow |
|
908 if ( iSizeLimit > elapsed.Int64() ) |
|
909 { |
|
910 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iSizeLimit > elapsed: %d vs. %d"), I64INT(iSizeLimit), I64INT(elapsed.Int64()) )); |
|
911 endtime = (((iSizeLimit * 1000) / usedSpace ) * elapsed.Int64() ) / 1000; |
|
912 } |
|
913 else |
|
914 { |
|
915 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iSizeLimit < elapsed: %d vs. %d"), I64INT(iSizeLimit), I64INT(elapsed.Int64()) )); |
|
916 endtime = ( iSizeLimit * ( (elapsed.Int64() * 1000) / usedSpace )) / 1000; |
|
917 } |
|
918 } |
|
919 else |
|
920 { |
|
921 // divide the greater of iAvailableSpaceAtStart and elapsed with usedSpace first to prevent overflow |
|
922 if (iAvailableSpaceAtStart > elapsed.Int64() ) |
|
923 { |
|
924 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iAvailableSpaceAtStart > elapsed: %d vs. %d"), I64INT(iAvailableSpaceAtStart), I64INT(elapsed.Int64()) )); |
|
925 endtime = (( (iAvailableSpaceAtStart * 1000) / usedSpace ) * elapsed.Int64() ) / 1000; |
|
926 } |
|
927 else |
|
928 { |
|
929 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iAvailableSpaceAtStart < elapsed: %d vs. %d"), I64INT(iAvailableSpaceAtStart), I64INT(elapsed.Int64()) )); |
|
930 endtime = ( iAvailableSpaceAtStart * ( (elapsed.Int64() * 1000) / usedSpace )) / 1000; |
|
931 } |
|
932 } |
|
933 |
|
934 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL Endtime: %d"), I64INT(endtime.Int64()) )); |
|
935 if ( iAvarageEndTime.Int64() == -1 ) |
|
936 { |
|
937 iAvarageEndTime = endtime; |
|
938 } |
|
939 else |
|
940 { |
|
941 iAvarageEndTime = (( iAvarageEndTime.Int64() * 7 ) + endtime.Int64() ) / 8; |
|
942 } |
|
943 |
|
944 if ( iAvarageEndTime.Int64() > (TInt64(KCamCMaxClipDurationInSecs)*1000000) ) |
|
945 { |
|
946 iAvarageEndTime = (TInt64(KCamCMaxClipDurationInSecs)*1000000); |
|
947 } |
|
948 |
|
949 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL elapsed: %d , usedspace: %d"), I64INT(elapsed.Int64()), I64INT(usedSpace) )); |
|
950 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL available: %d, atStart: %d"), I64INT(availableSpace), iAvailableSpaceAtStart)); |
|
951 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL AvgEndtime: %d"), I64INT(iAvarageEndTime.Int64()) )); |
|
952 remaining = iAvarageEndTime.Int64() - elapsed.Int64(); |
|
953 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL remaining: %d"), I64INT(remaining.Int64()) )); |
|
954 } |
|
955 } |
|
956 |
|
957 // Check if remaining time has reached 0 and we need to stop right away |
|
958 if ( remaining <= TInt64(0) ) |
|
959 { |
|
960 if ( elapsed >= TInt64(0) ) // we are recording. |
|
961 { |
|
962 if ( remainingFromSizeLimit || (elapsed >= (TInt64(KCamCMaxClipDurationInSecs)*1000000)) ) |
|
963 { |
|
964 // Size limit has been set and we reach wanted size -> remaining time is 0 |
|
965 iFileSizeLimitReached = ETrue; |
|
966 iObserver->MfcoSizeLimitReachedL(); |
|
967 } |
|
968 else |
|
969 { |
|
970 // Diskfull |
|
971 iDiskFull = ETrue; |
|
972 iObserver->MfcoDiskFullL(); |
|
973 } |
|
974 } |
|
975 remaining = 0; |
|
976 } |
|
977 PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL out"))); |
|
978 return remaining; |
|
979 } |
|
980 |
|
981 |
|
982 // ----------------------------------------------------------------------------- |
|
983 // CCamC3GPDataSinkImp::SinkStopL |
|
984 // |
|
985 // Order the sink to finalize and close the current 3GP file. |
|
986 // ----------------------------------------------------------------------------- |
|
987 // |
|
988 void CCamC3GPDataSinkImp::SinkStopL() |
|
989 { |
|
990 MP4Err error; |
|
991 |
|
992 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL enter"))); |
|
993 |
|
994 if (!iMP4Handle) |
|
995 { |
|
996 return; |
|
997 } |
|
998 |
|
999 if (iVideoFrameDuration) // Write remaining video frame to disk |
|
1000 { |
|
1001 error = MP4ComposeWriteVideoFrame(iMP4Handle, |
|
1002 (mp4_u8 *)iVideoBuffer, |
|
1003 (mp4_u32)iVideoBufferFrameSize, |
|
1004 (mp4_u32)iVideoFrameDuration, |
|
1005 (mp4_bool)iVideoBufferRandomAccessPoint); |
|
1006 if (error != MP4_OK) |
|
1007 { |
|
1008 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL MP4ComposeWriteVideoFrame, error=%d"), error)); |
|
1009 User::Leave(KErrGeneral); |
|
1010 } |
|
1011 } |
|
1012 |
|
1013 |
|
1014 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL video frames written"))); |
|
1015 |
|
1016 |
|
1017 if (iAudioFramesInBuffer) // Write remaining audio frames to disk |
|
1018 { |
|
1019 error = MP4ComposeWriteAudioFrames(iMP4Handle, |
|
1020 (mp4_u8 *)iAudioBuffer, |
|
1021 (mp4_u32)iAudioBufferFrameSize, |
|
1022 (mp4_u32)iAudioFramesInBuffer, |
|
1023 (mp4_u32)iAudioFramesInBuffer * KAudioFrameDuration); |
|
1024 if (error != MP4_OK) |
|
1025 { |
|
1026 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL MP4ComposeWriteAudioFrames, error=%d"), error)); |
|
1027 User::Leave(KErrGeneral); |
|
1028 } |
|
1029 } |
|
1030 |
|
1031 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL audio frames written"))); |
|
1032 |
|
1033 |
|
1034 error = MP4ComposeClose(iMP4Handle); |
|
1035 iMP4Handle = NULL; |
|
1036 if (error != MP4_OK) |
|
1037 { |
|
1038 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL MP4ComposeClose, error=%d"), error)); |
|
1039 TInt64 currentdiskspace = DriveFreeSpaceL(); |
|
1040 |
|
1041 if ( currentdiskspace < ((TInt64)KDiskSafetyLimit+iCriticalDiskVal+CurrentMetadataSize()) ) |
|
1042 { |
|
1043 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL disk full, available: %d"), I64INT(currentdiskspace))); |
|
1044 iDiskFull = ETrue; |
|
1045 User::Leave(KErrDiskFull); |
|
1046 } |
|
1047 else |
|
1048 { |
|
1049 User::Leave(KErrGeneral); |
|
1050 } |
|
1051 } |
|
1052 |
|
1053 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL file composed and closed"))); |
|
1054 |
|
1055 if ( iFileHandleExists ) |
|
1056 { |
|
1057 iMMFFile->SinkStopL(); |
|
1058 iMMFFile = NULL; // not owned |
|
1059 } |
|
1060 else |
|
1061 { |
|
1062 if (!iBytesReceived) |
|
1063 { |
|
1064 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL No data written, iTmpFileName left: '%s'"), iTmpFileName.Ptr())); |
|
1065 } |
|
1066 else |
|
1067 { |
|
1068 iFS->SetEntry(iTmpFileName, TTime(0), NULL, KEntryAttHidden); |
|
1069 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL Renaming temp file to: '%s'"), iFileName.Ptr())); |
|
1070 User::LeaveIfError(iFS->Rename(iTmpFileName, iFileName)); |
|
1071 } |
|
1072 } |
|
1073 |
|
1074 iFileName = KNullDesC; |
|
1075 |
|
1076 iBytesOfMetadata = 0; |
|
1077 iBufferSize = 0; |
|
1078 iFileCodecType = MP4_TYPE_NONE; |
|
1079 iVideoTimestamp = 0; |
|
1080 iVideoBufferTimestamp = -1; |
|
1081 iVideoRandomAccessPoint = EFalse; |
|
1082 iVideoBufferRandomAccessPoint = EFalse; |
|
1083 iVideoFrameDuration = 0; |
|
1084 iVideoBufferFrameSize = 0; |
|
1085 iVideoDecSpecInfoSize = 0; |
|
1086 iAudioDecSpecInfoSize = 0; |
|
1087 iAudioBufferFrameSize = 0; |
|
1088 iAudioFrameNumber = 0; |
|
1089 iAudioFramesInBuffer = 0; |
|
1090 iFileSizeLimitReached = EFalse; |
|
1091 iDiskFull = EFalse; |
|
1092 iFreeDiskSpace = 0; |
|
1093 iFreeDiskSpaceCounter = 0; |
|
1094 iAudioAACFrameDuration = 0; |
|
1095 iAudioAACSamplerate = 0; |
|
1096 |
|
1097 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL() updating available diskspace - in"))); |
|
1098 TVolumeInfo volumeinfo; |
|
1099 if ( iFS && iFS->Volume(volumeinfo, iDriveNumber) == KErrNone ) |
|
1100 { |
|
1101 iAvailableSpaceAtStart = volumeinfo.iFree - (TInt64)(KDiskSafetyLimit+iCriticalDiskVal); |
|
1102 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL() updating available diskspace - done"))); |
|
1103 } |
|
1104 |
|
1105 PRINT((_L("CCamC3GPDataSinkImp::SinkStopL exit"))); |
|
1106 } |
|
1107 |
|
1108 |
|
1109 // ----------------------------------------------------------------------------- |
|
1110 // CCamC3GPDataSinkImp::WriteBuffer |
|
1111 // |
|
1112 // Write an audio/video buffer to the sink. The sink copies the given buffer |
|
1113 // and writes it to the file. |
|
1114 // ----------------------------------------------------------------------------- |
|
1115 // |
|
1116 void CCamC3GPDataSinkImp::WriteBufferL(CCMRMediaBuffer* aBuffer) |
|
1117 { |
|
1118 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL enter"))); |
|
1119 TInt64 videoduration = 0; |
|
1120 TUint8* tmpaudiobuffer = 0; |
|
1121 TInt64 currentfilesize; |
|
1122 MP4Err error = MP4_OK; |
|
1123 |
|
1124 |
|
1125 if (!iMP4Handle) |
|
1126 { |
|
1127 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL No MP4Handle, returning."))); |
|
1128 return; |
|
1129 } |
|
1130 |
|
1131 if (iFileSizeLimitReached || iDiskFull) |
|
1132 { |
|
1133 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL sizelimit reached or disk full returning"))); |
|
1134 return; |
|
1135 } |
|
1136 |
|
1137 iBufferType = aBuffer->Type(); |
|
1138 iBufferSize = aBuffer->BufferSize(); |
|
1139 |
|
1140 TTimeIntervalMicroSeconds elapsed; |
|
1141 if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) |
|
1142 { |
|
1143 elapsed = 0; |
|
1144 } |
|
1145 else |
|
1146 { |
|
1147 elapsed = iVideoBufferTimestamp.Int64() - iFirstVideoFrameTimestamp.Int64(); |
|
1148 } |
|
1149 |
|
1150 currentfilesize = CurrentFileSize() + CurrentMetadataSize(); |
|
1151 if ( ( iSizeLimit && ((currentfilesize + (TUint)iBufferSize) > iSizeLimit) ) || |
|
1152 (elapsed.Int64() >= (TInt64(KCamCMaxClipDurationInSecs)*1000000)) ) |
|
1153 { |
|
1154 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL sizelimit reached, filesize: %d"), I64INT(currentfilesize))); |
|
1155 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL sizelimit is set to: high:%u low:%u"), I64HIGH(iSizeLimit), I64LOW(iSizeLimit))); |
|
1156 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL elapsed time: high:%u low:%u"), I64HIGH(elapsed.Int64()), I64LOW(elapsed.Int64()))); |
|
1157 iFileSizeLimitReached = ETrue; |
|
1158 iObserver->MfcoSizeLimitReachedL(); |
|
1159 return; |
|
1160 } |
|
1161 |
|
1162 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL, filesize: %d, bufsize: %d") |
|
1163 , I64INT(currentfilesize), iBufferSize)); |
|
1164 |
|
1165 currentfilesize += CurrentMetadataSize(); // extra reserve for stop (copy metadata from temp files to end of output file. |
|
1166 if ( currentfilesize >= iAvailableSpaceAtStart ) |
|
1167 { |
|
1168 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL disk full, calc size: %d"), I64INT(currentfilesize))); |
|
1169 iDiskFull = ETrue; |
|
1170 iObserver->MfcoDiskFullL(); |
|
1171 return; |
|
1172 } |
|
1173 |
|
1174 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL, available: %d") |
|
1175 , I64INT(iAvailableSpaceAtStart-currentfilesize))); |
|
1176 |
|
1177 iBytesReceived += (TUint)iBufferSize; |
|
1178 switch (iBufferType) |
|
1179 { |
|
1180 case CCMRMediaBuffer::EAudioAMRNB: |
|
1181 { |
|
1182 iAudioFrameNumber++; |
|
1183 |
|
1184 if ( ( (TUint)iBufferSize + iAudioBufferFrameSize ) > iAudioBufferSize) // Incoming buffer doesn't fit into allocated buffer |
|
1185 { |
|
1186 tmpaudiobuffer = new (ELeave) TUint8[(TUint)iBufferSize + iAudioBufferFrameSize]; |
|
1187 Mem::Copy(tmpaudiobuffer, iAudioBuffer, (TInt)iAudioBufferFrameSize); |
|
1188 delete [] iAudioBuffer; |
|
1189 iAudioBuffer = tmpaudiobuffer; |
|
1190 iAudioBufferSize = (TUint)iBufferSize + iAudioBufferFrameSize; |
|
1191 } |
|
1192 |
|
1193 Mem::Copy(iAudioBuffer + iAudioBufferFrameSize, aBuffer->Data().Ptr(), iBufferSize); |
|
1194 iAudioBufferFrameSize += (TUint)iBufferSize; |
|
1195 iAudioFramesInBuffer++; |
|
1196 |
|
1197 if (iAudioFramesInBuffer == KAMRAudioFramesPerSample) // Buffer several audio frames before writing to disk |
|
1198 { |
|
1199 error = MP4ComposeWriteAudioFrames(iMP4Handle, |
|
1200 (mp4_u8 *)iAudioBuffer, |
|
1201 (mp4_u32)iAudioBufferFrameSize, |
|
1202 (mp4_u32)iAudioFramesInBuffer, |
|
1203 (mp4_u32)iAudioFramesInBuffer * KAudioFrameDuration); |
|
1204 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL AMR-NB MP4ComposeWriteAudioFrames, error=%d"), error)); |
|
1205 if (error != MP4_OK) |
|
1206 { |
|
1207 User::Leave(KErrGeneral); |
|
1208 } |
|
1209 |
|
1210 iAudioFramesInBuffer = 0; |
|
1211 iAudioBufferFrameSize = 0; |
|
1212 } |
|
1213 |
|
1214 break; |
|
1215 } |
|
1216 case CCMRMediaBuffer::EAudioMPEG4AAC: |
|
1217 { |
|
1218 if ( !iAudioAACFrameDuration ) |
|
1219 { |
|
1220 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL AAC Audio frameduration not set! Error= -18"), error)); |
|
1221 User::Leave ( KErrNotReady ); |
|
1222 } |
|
1223 |
|
1224 iAudioFrameNumber++; |
|
1225 error = MP4ComposeWriteAudioFrames(iMP4Handle, |
|
1226 (mp4_u8 *)aBuffer->Data().Ptr(), |
|
1227 (mp4_u32)aBuffer->BufferSize(), |
|
1228 (mp4_u32)KAACAudioFramesPerSample, |
|
1229 (mp4_u32)KAACAudioFramesPerSample * iAudioAACFrameDuration); |
|
1230 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL AAC MP4ComposeWriteAudioFrames, error=%d"), error)); |
|
1231 if (error != MP4_OK) |
|
1232 { |
|
1233 User::Leave(KErrGeneral); |
|
1234 } |
|
1235 break; |
|
1236 } |
|
1237 case CCMRMediaBuffer::EAudioAMRWB: |
|
1238 { |
|
1239 break; |
|
1240 } |
|
1241 case CCMRMediaBuffer::EVideoH263: |
|
1242 case CCMRMediaBuffer::EVideoMPEG4: |
|
1243 { |
|
1244 iVideoTimestamp = aBuffer->TimeStamp(); |
|
1245 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH263/EVideoMPEG4 Timestamp of the buffer is %d"), I64INT(iVideoTimestamp.Int64()))); |
|
1246 iVideoRandomAccessPoint = aBuffer->RandomAccessPoint(); |
|
1247 iVideoFrameNumber++; |
|
1248 if (iVideoRandomAccessPoint) |
|
1249 { |
|
1250 iVideoIntraFrameNumber++; |
|
1251 } |
|
1252 |
|
1253 if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) // First frame |
|
1254 { |
|
1255 iFirstVideoFrameTimestamp = iVideoTimestamp; |
|
1256 iVideoBufferTimestamp = iVideoTimestamp; |
|
1257 iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint; |
|
1258 |
|
1259 if ((TUint)iBufferSize > iVideoBufferSize) |
|
1260 { |
|
1261 delete [] iVideoBuffer; |
|
1262 iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize]; |
|
1263 iVideoBufferSize = (TUint)iBufferSize; |
|
1264 } |
|
1265 |
|
1266 Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize); |
|
1267 iVideoBufferFrameSize = (TUint)iBufferSize; |
|
1268 |
|
1269 break; |
|
1270 } |
|
1271 |
|
1272 videoduration = iVideoTimestamp.Int64() - iVideoBufferTimestamp.Int64(); // Duration in microseconds |
|
1273 videoduration = TInt64((videoduration * KVideoTimeScale) / 1E6 + 0.5); // Duration scaled to KVideoTimeScale |
|
1274 iVideoFrameDuration = (TUint)I64INT(videoduration); |
|
1275 |
|
1276 error = MP4ComposeWriteVideoFrame(iMP4Handle, |
|
1277 (mp4_u8 *)iVideoBuffer, |
|
1278 (mp4_u32)iVideoBufferFrameSize, |
|
1279 (mp4_u32)iVideoFrameDuration, |
|
1280 (mp4_bool)iVideoBufferRandomAccessPoint); |
|
1281 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoFrame, error=%d"), error)); |
|
1282 if (error != MP4_OK) |
|
1283 { |
|
1284 User::Leave(KErrGeneral); |
|
1285 } |
|
1286 |
|
1287 if ((TUint)iBufferSize > iVideoBufferSize) |
|
1288 { |
|
1289 delete [] iVideoBuffer; |
|
1290 iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize]; |
|
1291 iVideoBufferSize = (TUint)iBufferSize; |
|
1292 } |
|
1293 |
|
1294 Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize); |
|
1295 iVideoBufferFrameSize = (TUint)iBufferSize; |
|
1296 iVideoBufferTimestamp = iVideoTimestamp; |
|
1297 iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint; |
|
1298 |
|
1299 break; |
|
1300 } |
|
1301 case CCMRMediaBuffer::EVideoMPEG4DecSpecInfo: |
|
1302 { |
|
1303 iVideoDecSpecInfoSize = iBufferSize; |
|
1304 |
|
1305 error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle, |
|
1306 (mp4_u8 *)aBuffer->Data().Ptr(), |
|
1307 (mp4_u32)iBufferSize); |
|
1308 if (error != MP4_OK) |
|
1309 { |
|
1310 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error)); |
|
1311 User::Leave(KErrGeneral); |
|
1312 } |
|
1313 |
|
1314 break; |
|
1315 } |
|
1316 case CCMRMediaBuffer::EVideoH264NAL: |
|
1317 { |
|
1318 iVideoTimestamp = aBuffer->TimeStamp(); |
|
1319 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264NAL Timestamp of the buffer is %d"), I64INT(iVideoTimestamp.Int64()))); |
|
1320 iVideoRandomAccessPoint = aBuffer->RandomAccessPoint(); |
|
1321 iVideoFrameNumber++; |
|
1322 if (iVideoRandomAccessPoint) |
|
1323 { |
|
1324 iVideoIntraFrameNumber++; |
|
1325 } |
|
1326 |
|
1327 if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) // First frame |
|
1328 { |
|
1329 iFirstVideoFrameTimestamp = iVideoTimestamp; |
|
1330 iVideoBufferTimestamp = iVideoTimestamp; |
|
1331 iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint; |
|
1332 |
|
1333 if ((TUint)(iBufferSize) > iVideoBufferSize) |
|
1334 { |
|
1335 delete [] iVideoBuffer; |
|
1336 iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize]; |
|
1337 iVideoBufferSize = (TUint)iBufferSize; |
|
1338 } |
|
1339 |
|
1340 ConvertNALEncapsulationToNALSizes( aBuffer ); |
|
1341 break; |
|
1342 } |
|
1343 |
|
1344 videoduration = iVideoTimestamp.Int64() - iVideoBufferTimestamp.Int64(); // Duration in microseconds |
|
1345 videoduration = TInt64((videoduration * KVideoTimeScale) / 1E6 + 0.5); // Duration scaled to KVideoTimeScale |
|
1346 iVideoFrameDuration = (TUint)I64INT(videoduration); |
|
1347 |
|
1348 error = MP4ComposeWriteVideoFrame(iMP4Handle, |
|
1349 (mp4_u8 *)iVideoBuffer, |
|
1350 (mp4_u32)iVideoBufferFrameSize, |
|
1351 (mp4_u32)iVideoFrameDuration, |
|
1352 (mp4_bool)iVideoBufferRandomAccessPoint); |
|
1353 if (error != MP4_OK) |
|
1354 { |
|
1355 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoFrame, error=%d"), error)); |
|
1356 User::Leave(KErrGeneral); |
|
1357 } |
|
1358 |
|
1359 if ((TUint)(iBufferSize) > iVideoBufferSize) |
|
1360 { |
|
1361 delete [] iVideoBuffer; |
|
1362 iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize]; |
|
1363 iVideoBufferSize = (TUint)iBufferSize; |
|
1364 } |
|
1365 |
|
1366 ConvertNALEncapsulationToNALSizes( aBuffer ); |
|
1367 |
|
1368 iVideoBufferTimestamp = iVideoTimestamp; |
|
1369 iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint; |
|
1370 break; |
|
1371 } |
|
1372 case CCMRMediaBuffer::EVideoH264Bytestream: |
|
1373 { |
|
1374 // need to add NAL header to end on bytestream buffer |
|
1375 iVideoTimestamp = aBuffer->TimeStamp(); |
|
1376 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264Bytestream Timestamp of the buffer is %d"), I64INT(iVideoTimestamp.Int64()))); |
|
1377 iVideoRandomAccessPoint = aBuffer->RandomAccessPoint(); |
|
1378 iVideoFrameNumber++; |
|
1379 if (iVideoRandomAccessPoint) |
|
1380 { |
|
1381 iVideoIntraFrameNumber++; |
|
1382 } |
|
1383 |
|
1384 if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) // First frame |
|
1385 { |
|
1386 iFirstVideoFrameTimestamp = iVideoTimestamp; |
|
1387 iVideoBufferTimestamp = iVideoTimestamp; |
|
1388 iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint; |
|
1389 |
|
1390 if ((TUint)(iBufferSize) > iVideoBufferSize) |
|
1391 { |
|
1392 delete [] iVideoBuffer; |
|
1393 iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize]; |
|
1394 iVideoBufferSize = (TUint)iBufferSize; |
|
1395 } |
|
1396 |
|
1397 ConvertBytestreamHeadersToNALSizes(aBuffer); |
|
1398 Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize); |
|
1399 iVideoBufferFrameSize = iBufferSize; |
|
1400 break; |
|
1401 } |
|
1402 |
|
1403 videoduration = iVideoTimestamp.Int64() - iVideoBufferTimestamp.Int64(); // Duration in microseconds |
|
1404 videoduration = TInt64((videoduration * KVideoTimeScale) / 1E6 + 0.5); // Duration scaled to KVideoTimeScale |
|
1405 iVideoFrameDuration = (TUint)I64INT(videoduration); |
|
1406 |
|
1407 error = MP4ComposeWriteVideoFrame(iMP4Handle, |
|
1408 (mp4_u8 *)iVideoBuffer, |
|
1409 (mp4_u32)iVideoBufferFrameSize, |
|
1410 (mp4_u32)iVideoFrameDuration, |
|
1411 (mp4_bool)iVideoBufferRandomAccessPoint); |
|
1412 if (error != MP4_OK) |
|
1413 { |
|
1414 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoFrame, error=%d"), error)); |
|
1415 User::Leave(KErrGeneral); |
|
1416 } |
|
1417 |
|
1418 if ((TUint)(iBufferSize) > iVideoBufferSize) |
|
1419 { |
|
1420 delete [] iVideoBuffer; |
|
1421 iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize]; |
|
1422 iVideoBufferSize = (TUint)iBufferSize; |
|
1423 } |
|
1424 |
|
1425 ConvertBytestreamHeadersToNALSizes(aBuffer); |
|
1426 Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize); |
|
1427 |
|
1428 iVideoBufferFrameSize = (TUint)iBufferSize; |
|
1429 iVideoBufferTimestamp = iVideoTimestamp; |
|
1430 iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint; |
|
1431 break; |
|
1432 } |
|
1433 case CCMRMediaBuffer::EVideoH264NALDecSpecInfo: |
|
1434 { |
|
1435 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264NALDecSpecInfo"))); |
|
1436 HBufC8* outputAVCHeader = 0; |
|
1437 outputAVCHeader = (HBufC8*) HBufC8::NewLC(16384); |
|
1438 TPtr8 destptr = outputAVCHeader->Des(); |
|
1439 |
|
1440 // parse header & convert it to AVCDecoderConfigurationRecord -format |
|
1441 ConvertAVCHeaderNALL(aBuffer, destptr); |
|
1442 iVideoDecSpecInfoSize = destptr.Length(); |
|
1443 |
|
1444 error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle, |
|
1445 (mp4_u8 *)destptr.Ptr(), |
|
1446 (mp4_u32)iVideoDecSpecInfoSize); |
|
1447 |
|
1448 CleanupStack::PopAndDestroy( outputAVCHeader ); |
|
1449 if (error != MP4_OK) |
|
1450 { |
|
1451 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error)); |
|
1452 User::Leave(KErrGeneral); |
|
1453 } |
|
1454 break; |
|
1455 } |
|
1456 case CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo: |
|
1457 { |
|
1458 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264BytestreamDecSpecInfo"))); |
|
1459 HBufC8* outputAVCHeader = 0; |
|
1460 outputAVCHeader = (HBufC8*) HBufC8::NewLC(16384); |
|
1461 TPtr8 destptr = outputAVCHeader->Des(); |
|
1462 |
|
1463 // parse header & convert it to AVCDecoderConfigurationRecord -format |
|
1464 ConvertAVCHeaderByteStreamL(aBuffer, destptr); |
|
1465 iVideoDecSpecInfoSize = destptr.Length(); |
|
1466 |
|
1467 error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle, |
|
1468 (mp4_u8 *)destptr.Ptr(), |
|
1469 (mp4_u32)iVideoDecSpecInfoSize); |
|
1470 |
|
1471 CleanupStack::PopAndDestroy( outputAVCHeader ); |
|
1472 if (error != MP4_OK) |
|
1473 { |
|
1474 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error)); |
|
1475 User::Leave(KErrGeneral); |
|
1476 } |
|
1477 break; |
|
1478 } |
|
1479 case CCMRMediaBuffer::EAudioDecSpecInfo: |
|
1480 { |
|
1481 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo in"), error)); |
|
1482 iAudioDecSpecInfoSize = iBufferSize; |
|
1483 |
|
1484 error = MP4ComposeWriteAudioDecoderSpecificInfo(iMP4Handle, |
|
1485 (mp4_u8 *)aBuffer->Data().Ptr(), |
|
1486 (mp4_u32)iBufferSize); |
|
1487 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo, error=%d"), error)); |
|
1488 if (error != MP4_OK) |
|
1489 { |
|
1490 User::Leave(KErrGeneral); |
|
1491 } |
|
1492 |
|
1493 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo - flags: iFileCodecType=%d Frameduration=%d"), iFileCodecType, iAudioAACFrameDuration)); |
|
1494 if ( (iFileCodecType & MP4_TYPE_MPEG4_AUDIO) && !iAudioAACFrameDuration ) |
|
1495 { |
|
1496 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo determining new AAC samplerate."), error)); |
|
1497 DetermineAACFrameDurationL( aBuffer ); |
|
1498 // done here because timescale is dependent of samplerate. |
|
1499 error = MP4ComposeAddAudioDescription(iMP4Handle, |
|
1500 (mp4_u32)iAudioAACSamplerate, |
|
1501 (mp4_u8)KAACAudioFramesPerSample, |
|
1502 (mp4_u16)KAudioModeSet); |
|
1503 if (error != MP4_OK) |
|
1504 { |
|
1505 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeAddAudioDescription, error=%d"), error)); |
|
1506 User::Leave(KErrGeneral); |
|
1507 } |
|
1508 } |
|
1509 PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo out"), error)); |
|
1510 break; |
|
1511 } |
|
1512 default: |
|
1513 { |
|
1514 break; |
|
1515 } |
|
1516 } |
|
1517 } |
|
1518 |
|
1519 |
|
1520 // ----------------------------------------------------------------------------- |
|
1521 // CCamC3GPDataSinkImp::SetVideoFrameSize |
|
1522 // |
|
1523 // Give video frame size to sink. |
|
1524 // ----------------------------------------------------------------------------- |
|
1525 // |
|
1526 TInt CCamC3GPDataSinkImp::SetVideoFrameSize(TSize aSize) |
|
1527 { |
|
1528 if (aSize.iWidth < 0) |
|
1529 { |
|
1530 return KErrArgument; |
|
1531 } |
|
1532 if (aSize.iHeight < 0) |
|
1533 { |
|
1534 return KErrArgument; |
|
1535 } |
|
1536 |
|
1537 if (iBytesReceived) |
|
1538 { |
|
1539 return KErrNotReady; |
|
1540 } |
|
1541 |
|
1542 iVideoXResolution = aSize.iWidth; |
|
1543 iVideoYResolution = aSize.iHeight; |
|
1544 return KErrNone; |
|
1545 } |
|
1546 |
|
1547 |
|
1548 // ----------------------------------------------------------------------------- |
|
1549 // CCamC3GPDataSinkImp::SetAverageVideoBitRate |
|
1550 // |
|
1551 // Give average video bitrate to sink. |
|
1552 // ----------------------------------------------------------------------------- |
|
1553 // |
|
1554 TInt CCamC3GPDataSinkImp::SetAverageVideoBitRate(TInt aBitRate) |
|
1555 { |
|
1556 if (aBitRate < 0) |
|
1557 { |
|
1558 return KErrArgument; |
|
1559 } |
|
1560 |
|
1561 iVideoAverageBitRate = aBitRate; |
|
1562 return KErrNone; |
|
1563 } |
|
1564 |
|
1565 |
|
1566 // ----------------------------------------------------------------------------- |
|
1567 // CCamC3GPDataSinkImp::SetMaxVideoBitRate |
|
1568 // |
|
1569 // Give maximum video bitrate to sink. |
|
1570 // ----------------------------------------------------------------------------- |
|
1571 // |
|
1572 TInt CCamC3GPDataSinkImp::SetMaxVideoBitRate(TInt aBitRate) |
|
1573 { |
|
1574 if (aBitRate < 0) |
|
1575 { |
|
1576 return KErrArgument; |
|
1577 } |
|
1578 |
|
1579 iVideoMaxBitRate = aBitRate; |
|
1580 return KErrNone; |
|
1581 } |
|
1582 |
|
1583 |
|
1584 // ----------------------------------------------------------------------------- |
|
1585 // CCamC3GPDataSinkImp::SetAverageAudioBitRate |
|
1586 // |
|
1587 // Give average audio bitrate to sink. |
|
1588 // ----------------------------------------------------------------------------- |
|
1589 // |
|
1590 TInt CCamC3GPDataSinkImp::SetAverageAudioBitRate(TInt aBitRate) |
|
1591 { |
|
1592 if (aBitRate < 0) |
|
1593 { |
|
1594 return KErrArgument; |
|
1595 } |
|
1596 |
|
1597 iAudioAverageBitRate = aBitRate; |
|
1598 return KErrNone; |
|
1599 } |
|
1600 |
|
1601 |
|
1602 // ----------------------------------------------------------------------------- |
|
1603 // CCamC3GPDataSinkImp::CurrentFileSize |
|
1604 // |
|
1605 // Estimate current output file size. |
|
1606 // Total file size = metadata size + media data size |
|
1607 // ----------------------------------------------------------------------------- |
|
1608 // |
|
1609 TUint CCamC3GPDataSinkImp::CurrentFileSize() const |
|
1610 { |
|
1611 TUint filesize = 0; |
|
1612 |
|
1613 // Media data |
|
1614 filesize += 8; // mdat box type and size |
|
1615 filesize += iBytesReceived; // Data received from media recorder |
|
1616 |
|
1617 return filesize; |
|
1618 } |
|
1619 |
|
1620 |
|
1621 // ----------------------------------------------------------------------------- |
|
1622 // CCamC3GPDataSinkImp::CurrentMetadataSize |
|
1623 // |
|
1624 // Calculates current metadata size. |
|
1625 // ----------------------------------------------------------------------------- |
|
1626 // |
|
1627 TUint CCamC3GPDataSinkImp::CurrentMetadataSize() const |
|
1628 { |
|
1629 TBool haveAudio; |
|
1630 TBool haveVideo; |
|
1631 TUint metadatasize = 0; |
|
1632 |
|
1633 haveAudio = EFalse; |
|
1634 haveVideo = EFalse; |
|
1635 |
|
1636 |
|
1637 // Metadata |
|
1638 |
|
1639 metadatasize += KFTYPSize; // FTYP |
|
1640 |
|
1641 if ((iFileCodecType & MP4_TYPE_H263_PROFILE_0) || |
|
1642 (iFileCodecType & MP4_TYPE_H263_PROFILE_3)) // H.263 |
|
1643 { |
|
1644 haveVideo = ETrue; |
|
1645 metadatasize += 574; // Constant size H.263 metadata |
|
1646 metadatasize += (iVideoFrameNumber * 16 + iVideoIntraFrameNumber * 4); // Content dependent H.263 metadata |
|
1647 } |
|
1648 |
|
1649 if (iFileCodecType & MP4_TYPE_MPEG4_VIDEO) // MPEG-4 video |
|
1650 { |
|
1651 haveVideo = ETrue; |
|
1652 metadatasize += 596; // Constant size MPEG-4 video metadata |
|
1653 metadatasize += (iVideoFrameNumber * 16 + iVideoIntraFrameNumber * 4 + (TUint)iVideoDecSpecInfoSize); // Content dependent MPEG-4 video metadata |
|
1654 } |
|
1655 |
|
1656 if ( iFileCodecType & MP4_TYPE_AMR_NB ) // AMR-NB |
|
1657 { |
|
1658 haveAudio = ETrue; |
|
1659 metadatasize += 514; // Constant size AMR metadata |
|
1660 metadatasize += ((iAudioFrameNumber + KAMRAudioFramesPerSample - 1) / KAMRAudioFramesPerSample) * 16; |
|
1661 } |
|
1662 |
|
1663 if ( iFileCodecType & MP4_TYPE_MPEG4_AUDIO ) // MPEG-4 AAC-LC |
|
1664 { |
|
1665 haveAudio = ETrue; |
|
1666 metadatasize += 514; // Constant size metadata |
|
1667 metadatasize += (iAudioFrameNumber * 16) + (TUint)iAudioDecSpecInfoSize; |
|
1668 } |
|
1669 |
|
1670 if (haveAudio && haveVideo) |
|
1671 metadatasize -= 116; // There is only one moov and mvhd in a file |
|
1672 |
|
1673 return metadatasize; |
|
1674 } |
|
1675 |
|
1676 |
|
1677 // ----------------------------------------------------------------------------- |
|
1678 // CCamC3GPDataSinkImp::DriveFreeSpaceL |
|
1679 // |
|
1680 // Calculate free space on a drive in bytes. |
|
1681 // ----------------------------------------------------------------------------- |
|
1682 // |
|
1683 TInt64 CCamC3GPDataSinkImp::DriveFreeSpaceL() |
|
1684 { |
|
1685 TVolumeInfo volumeinfo; |
|
1686 |
|
1687 if (iFreeDiskSpaceCounter % KFreeDiskSpaceCounter == 0) |
|
1688 { |
|
1689 PRINT((_L("CCamC3GPDataSinkImp::DriveFreeSpaceL Asking Disk Free space"))); |
|
1690 User::LeaveIfError(iFS->Volume(volumeinfo, iDriveNumber)); |
|
1691 iFreeDiskSpace = volumeinfo.iFree; |
|
1692 PRINT((_L("CCamC3GPDataSinkImp::DriveFreeSpaceL Received Disk Free space info"))); |
|
1693 } |
|
1694 |
|
1695 iFreeDiskSpaceCounter++; |
|
1696 return iFreeDiskSpace; |
|
1697 } |
|
1698 |
|
1699 |
|
1700 // ----------------------------------------------------------------------------- |
|
1701 // CCamC3GPDataSinkImp::DetermineAACFrameDuration |
|
1702 // |
|
1703 // Determines AAC audio frame duration. |
|
1704 // ----------------------------------------------------------------------------- |
|
1705 // |
|
1706 void CCamC3GPDataSinkImp::DetermineAACFrameDurationL( CCMRMediaBuffer* aBuffer ) |
|
1707 { |
|
1708 TInt sampleRate = 0; |
|
1709 TUint8 sampleRateIndex = *aBuffer->Data().Mid(0).Ptr(); |
|
1710 sampleRateIndex <<= 5; |
|
1711 sampleRateIndex >>= 4; |
|
1712 sampleRateIndex |= ((TUint8)*aBuffer->Data().Mid(1).Ptr())>>7; |
|
1713 |
|
1714 switch ( sampleRateIndex ) |
|
1715 { |
|
1716 case 0x3: |
|
1717 { |
|
1718 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 48000"))); |
|
1719 sampleRate = 48000; |
|
1720 break; |
|
1721 } |
|
1722 case 0x5: |
|
1723 { |
|
1724 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 32000"))); |
|
1725 sampleRate = 32000; |
|
1726 break; |
|
1727 } |
|
1728 case 0x6: |
|
1729 { |
|
1730 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 24000"))); |
|
1731 sampleRate = 24000; |
|
1732 break; |
|
1733 } |
|
1734 case 0x8: |
|
1735 { |
|
1736 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 16000"))); |
|
1737 sampleRate = 16000; |
|
1738 break; |
|
1739 } |
|
1740 case 0xb: |
|
1741 { |
|
1742 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 8000"))); |
|
1743 sampleRate = 8000; |
|
1744 break; |
|
1745 } |
|
1746 default: |
|
1747 { |
|
1748 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL unsupported AAC Samplerate - leaving -6"))); |
|
1749 User::Leave( KErrArgument ); |
|
1750 break; |
|
1751 } |
|
1752 } |
|
1753 |
|
1754 PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset from %d to %d"), iAudioAACSamplerate, sampleRate)); |
|
1755 iAudioAACSamplerate = sampleRate; |
|
1756 // formula to calculate frameduration from samplerate is: frameduration = (1024/samplerate)*1000 |
|
1757 // and in movie timescale: frameDurationInMovieTimescale = frameduration*samplerate/1000 |
|
1758 // thus with equal samplerate = timescale frameDurationInMovieTimescale for AAC is always 1024 |
|
1759 iAudioAACFrameDuration = 1024; |
|
1760 } |
|
1761 |
|
1762 // ----------------------------------------------------------------------------- |
|
1763 // CCamC3GPDataSinkImp::ConvertAVCHeaderL |
|
1764 // |
|
1765 // Convert AVC specific decoder config info to |
|
1766 // AVC Decoder Configuration Record -format |
|
1767 // ----------------------------------------------------------------------------- |
|
1768 // |
|
1769 void CCamC3GPDataSinkImp::ConvertAVCHeaderNALL( CCMRMediaBuffer* aBuffer, TDes8& aDstBuf ) |
|
1770 { |
|
1771 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL in Buffer length: %d"), aBuffer->Data().Length() )); |
|
1772 TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr()); |
|
1773 TUint8* outputPtr = (TUint8*)(aDstBuf.Ptr()); |
|
1774 TUint8* spsPtr; |
|
1775 TUint8* ppsPtr; |
|
1776 |
|
1777 TUint numSPS = 0; |
|
1778 TUint numPPS = 0; |
|
1779 |
|
1780 TUint totalSPSLength = 0; |
|
1781 TUint totalPPSLength = 0; |
|
1782 |
|
1783 TUint headerLength = aBuffer->Data().Length(); |
|
1784 TUint endIndex = headerLength; |
|
1785 |
|
1786 TInt nalType = 0; |
|
1787 TUint nalLength; |
|
1788 TUint nalIndex; |
|
1789 TUint nalOffset; |
|
1790 |
|
1791 // Allocate memory for the temporary buffers |
|
1792 HBufC8* temp1 = (HBufC8*) HBufC8::NewLC(1000); |
|
1793 HBufC8* temp2 = (HBufC8*) HBufC8::NewLC(5000); |
|
1794 |
|
1795 spsPtr = const_cast<TUint8*>( temp1->Des().Ptr() ); |
|
1796 ppsPtr = const_cast<TUint8*>( temp2->Des().Ptr() ); |
|
1797 |
|
1798 TUint numNalUnits = inputPtr[endIndex-4] + (inputPtr[endIndex-3]<<8) + (inputPtr[endIndex-2]<<16) + (inputPtr[endIndex-1]<<24); |
|
1799 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit count: %d"), numNalUnits)); |
|
1800 |
|
1801 // Move endIndex to point to the first NAL unit's offset information |
|
1802 endIndex = headerLength - numNalUnits*8 - 4; |
|
1803 nalIndex = 0; |
|
1804 |
|
1805 while (nalIndex < numNalUnits) |
|
1806 { |
|
1807 nalIndex++; |
|
1808 |
|
1809 TInt tmp1 = inputPtr[endIndex++]; |
|
1810 TInt tmp2 = inputPtr[endIndex++]<<8; |
|
1811 TInt tmp3 = inputPtr[endIndex++]<<16; |
|
1812 TInt tmp4 = inputPtr[endIndex++]<<24; |
|
1813 |
|
1814 nalOffset = tmp1 + tmp2 + tmp3 + tmp4; |
|
1815 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit start offset: %d"), nalOffset)); |
|
1816 |
|
1817 tmp1 = inputPtr[endIndex++]; |
|
1818 tmp2 = inputPtr[endIndex++]<<8; |
|
1819 tmp3 = inputPtr[endIndex++]<<16; |
|
1820 tmp4 = inputPtr[endIndex++]<<24; |
|
1821 |
|
1822 nalLength = tmp1 + tmp2 + tmp3 + tmp4; |
|
1823 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit length: %d"), nalLength)); |
|
1824 |
|
1825 nalType = inputPtr[nalOffset] & 0x1F; |
|
1826 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit type: %d"), nalType)); |
|
1827 |
|
1828 if(nalType == 7) |
|
1829 { |
|
1830 numSPS++; |
|
1831 |
|
1832 // First store the SPS unit length with two bytes |
|
1833 spsPtr[totalSPSLength] = (nalLength >> 8) & 0xFF; |
|
1834 spsPtr[totalSPSLength+1] = nalLength & 0xFF; |
|
1835 |
|
1836 // Copy the SPS unit to the buffer |
|
1837 Mem::Copy(&spsPtr[totalSPSLength+2], inputPtr+nalOffset , nalLength); |
|
1838 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL stored SPS from offset: %d size: %d"), inputPtr+nalOffset, nalLength)); |
|
1839 totalSPSLength += nalLength + 2; // Two more for the size |
|
1840 } |
|
1841 else if(nalType == 8) |
|
1842 { |
|
1843 numPPS++; |
|
1844 |
|
1845 // First store the SPS unit length with two bytes |
|
1846 ppsPtr[totalPPSLength] = (nalLength >> 8) & 0xFF; |
|
1847 ppsPtr[totalPPSLength+1] = nalLength & 0xFF; |
|
1848 |
|
1849 // Copy the SPS unit to the buffer |
|
1850 Mem::Copy(&ppsPtr[totalPPSLength+2], inputPtr+nalOffset , nalLength); |
|
1851 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL stored PPS from offset: %d size: %d"), inputPtr+nalOffset, nalLength)); |
|
1852 totalPPSLength += nalLength + 2; // Two more for the size |
|
1853 } |
|
1854 else |
|
1855 { |
|
1856 } |
|
1857 } |
|
1858 |
|
1859 // When the header has been parsed, form the AVC Decoder Configuration Record |
|
1860 outputPtr[0] = 0x01; // configurationVersion |
|
1861 // AVCProfileIndication contains the profile code as defined in the AVC specification |
|
1862 if (iFileCodecType & MP4_TYPE_AVC_PROFILE_BASELINE) |
|
1863 { |
|
1864 outputPtr[1] = 0x42; |
|
1865 outputPtr[2] = 0x80; // Bitstream obeys all Baseline profile constraints. |
|
1866 // Profile compatibility, i.e. all 4 constrain set flags + reserved 4 zero bits |
|
1867 if ( iAVCOutputLevel == 101 ) |
|
1868 { |
|
1869 outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero |
|
1870 } |
|
1871 // AVCLevelIndication contains the level code as defined in the AVC specification |
|
1872 outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel; |
|
1873 } |
|
1874 else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_MAIN) |
|
1875 { |
|
1876 outputPtr[1] = 0x4D; |
|
1877 outputPtr[2] = 0x40; // Bitstream obeys all main profile constraints. |
|
1878 if ( iAVCOutputLevel == 101 ) |
|
1879 { |
|
1880 outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero |
|
1881 } |
|
1882 // AVCLevelIndication contains the level code as defined in the AVC specification |
|
1883 outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel; |
|
1884 } |
|
1885 else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_HIGH) |
|
1886 { |
|
1887 outputPtr[1] = 0x64; |
|
1888 outputPtr[2] = 0x40; // Bitstream obeys all Baseline profile constraints. |
|
1889 outputPtr[3] = (iAVCOutputLevel == 101) ? 0x09 : iAVCOutputLevel; |
|
1890 } |
|
1891 else |
|
1892 { |
|
1893 User::Leave(KErrNotSupported); |
|
1894 } |
|
1895 |
|
1896 // lengthSizeMinusOne indicates the length in bytes of the NALUnitLength field minus one. |
|
1897 outputPtr[4] = 0x03; // 4 bytes |
|
1898 outputPtr[4] |= 0x0FC; // 6 reserved bits (all 1) |
|
1899 // numOfSequenceParameterSets indicates the number of sequence parameter sets |
|
1900 outputPtr[5] = numSPS; |
|
1901 outputPtr[5] |= 0xE0; // 3 reserved bits (all 1) |
|
1902 |
|
1903 TInt len = 6; |
|
1904 // Copy the SPS unit(s) to the buffer |
|
1905 Mem::Copy(&outputPtr[6], spsPtr , totalSPSLength); |
|
1906 len += totalSPSLength; |
|
1907 outputPtr[6+totalSPSLength] = numPPS; |
|
1908 len += 1; |
|
1909 |
|
1910 // Copy the PPS unit(s) to the buffer |
|
1911 Mem::Copy(&outputPtr[6+totalSPSLength+1], ppsPtr , totalPPSLength); |
|
1912 len += totalPPSLength; |
|
1913 aDstBuf.SetLength(len); |
|
1914 |
|
1915 CleanupStack::PopAndDestroy(temp2); |
|
1916 CleanupStack::PopAndDestroy(temp1); |
|
1917 } |
|
1918 |
|
1919 // ----------------------------------------------------------------------------- |
|
1920 // CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL |
|
1921 // |
|
1922 // Convert AVC specific decoder config info from Bytestream (ElementaryStream) encapsulation to |
|
1923 // AVC Decoder Configuration Record -format |
|
1924 // ----------------------------------------------------------------------------- |
|
1925 // |
|
1926 void CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL( CCMRMediaBuffer* aBuffer, TDes8& aDstBuf ) |
|
1927 { |
|
1928 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL in"))); |
|
1929 TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr()); |
|
1930 TUint8* outputPtr = (TUint8*)(aDstBuf.Ptr()); |
|
1931 TUint8* spsPtr; |
|
1932 TUint8* ppsPtr; |
|
1933 |
|
1934 TUint numSPS = 0; |
|
1935 TUint numPPS = 0; |
|
1936 |
|
1937 TUint totalSPSLength = 0; |
|
1938 TUint totalPPSLength = 0; |
|
1939 |
|
1940 TUint headerLength = aBuffer->Data().Length(); |
|
1941 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL buffer length: %d"), headerLength)); |
|
1942 |
|
1943 TInt nalType = 0; |
|
1944 |
|
1945 // Allocate memory for the temporary buffers |
|
1946 HBufC8* temp1 = (HBufC8*) HBufC8::NewLC(1000); |
|
1947 HBufC8* temp2 = (HBufC8*) HBufC8::NewLC(5000); |
|
1948 |
|
1949 spsPtr = const_cast<TUint8*>( temp1->Des().Ptr() ); |
|
1950 ppsPtr = const_cast<TUint8*>( temp2->Des().Ptr() ); |
|
1951 |
|
1952 // scan from beginning of buffer to end for SPS and PSP |
|
1953 TInt i = 0; |
|
1954 TInt j = 0; |
|
1955 for (i=0; i<headerLength; i++) |
|
1956 { |
|
1957 if ( inputPtr[i] == 0 && |
|
1958 inputPtr[i+1] == 0 && |
|
1959 inputPtr[i+2] == 0 && |
|
1960 inputPtr[i+3] == 1 ) |
|
1961 { // found bytestream header [00 00 00 01] |
|
1962 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL found header at: %d"), i)); |
|
1963 nalType = inputPtr[i+4] & 0x1F; |
|
1964 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL NAL type: %d"), nalType)); |
|
1965 if(nalType == 7) // SPS |
|
1966 { |
|
1967 numSPS++; |
|
1968 // find length of SPS |
|
1969 TInt j; |
|
1970 for (j=4; i+j+3<headerLength; j++) |
|
1971 { |
|
1972 if ( inputPtr[i+j] == 0 && |
|
1973 inputPtr[i+j+1] == 0 && |
|
1974 inputPtr[i+j+2] == 0 && |
|
1975 inputPtr[i+j+3] == 1 ) |
|
1976 { |
|
1977 totalSPSLength = j-i-4; |
|
1978 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL SPS length: %d, count: %d"), totalSPSLength, numSPS)); |
|
1979 break; |
|
1980 } |
|
1981 } |
|
1982 // if we didn't find next bytestream header then this is last buffer |
|
1983 if ( totalSPSLength == 0 ) |
|
1984 { |
|
1985 totalSPSLength = headerLength - i - 4; |
|
1986 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL SPS length: %d (last), count: %d"), totalSPSLength, numSPS)); |
|
1987 } |
|
1988 |
|
1989 // First store the SPS unit length with two bytes |
|
1990 spsPtr[0] = (totalSPSLength >> 8) & 0xFF; |
|
1991 spsPtr[1] = totalSPSLength & 0xFF; |
|
1992 |
|
1993 // Copy the SPS unit to the buffer |
|
1994 Mem::Copy(&spsPtr[2], &inputPtr[i+4] , totalSPSLength); |
|
1995 totalSPSLength +=2; |
|
1996 } |
|
1997 else if ( nalType == 8 ) // PPS) |
|
1998 { |
|
1999 numPPS++; |
|
2000 // find length of PPS |
|
2001 for (j=4; i+j+3<headerLength; j++) |
|
2002 { |
|
2003 if ( inputPtr[i+j] == 0 && |
|
2004 inputPtr[i+j+1] == 0 && |
|
2005 inputPtr[i+j+2] == 0 && |
|
2006 inputPtr[i+j+3] == 1 ) |
|
2007 { |
|
2008 totalPPSLength = j-i-4; |
|
2009 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL PPS length: %d, count: %d"), totalPPSLength, numPPS)); |
|
2010 break; |
|
2011 } |
|
2012 } |
|
2013 // if we didn't find next bytestream header then this is last buffer |
|
2014 if ( totalPPSLength == 0 ) |
|
2015 { |
|
2016 totalPPSLength = headerLength - i - 4; |
|
2017 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL PPS length: %d (last), count: %d"), totalPPSLength, numPPS)); |
|
2018 } |
|
2019 |
|
2020 // First store the SPS unit length with two bytes |
|
2021 ppsPtr[0] = (totalPPSLength >> 8) & 0xFF; |
|
2022 ppsPtr[1] = totalPPSLength & 0xFF; |
|
2023 |
|
2024 // Copy the SPS unit to the buffer |
|
2025 Mem::Copy(&ppsPtr[2], &inputPtr[i+4], totalPPSLength); |
|
2026 totalPPSLength +=2; |
|
2027 } |
|
2028 } |
|
2029 } |
|
2030 |
|
2031 // When the header has been parsed, form the AVC Decoder Configuration Record |
|
2032 outputPtr[0] = 0x01; // configurationVersion |
|
2033 // AVCProfileIndication contains the profile code as defined in the AVC specification |
|
2034 if (iFileCodecType & MP4_TYPE_AVC_PROFILE_BASELINE) |
|
2035 { |
|
2036 outputPtr[1] = 0x42; |
|
2037 outputPtr[2] = 0x80; // Bitstream obeys all Baseline profile constraints. |
|
2038 // Profile compatibility, i.e. all 4 constrain set flags + reserved 4 zero bits |
|
2039 if ( iAVCOutputLevel == 101 ) |
|
2040 { |
|
2041 outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero |
|
2042 } |
|
2043 // AVCLevelIndication contains the level code as defined in the AVC specification |
|
2044 outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel; |
|
2045 } |
|
2046 else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_MAIN) |
|
2047 { |
|
2048 outputPtr[1] = 0x4D; |
|
2049 outputPtr[2] = 0x40; // Bitstream obeys all main profile constraints. |
|
2050 if ( iAVCOutputLevel == 101 ) |
|
2051 { |
|
2052 outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero |
|
2053 } |
|
2054 // AVCLevelIndication contains the level code as defined in the AVC specification |
|
2055 outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel; |
|
2056 } |
|
2057 else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_HIGH) |
|
2058 { |
|
2059 outputPtr[1] = 0x64; |
|
2060 outputPtr[2] = 0x40; // Bitstream obeys all Baseline profile constraints. |
|
2061 outputPtr[3] = (iAVCOutputLevel == 101) ? 0x09 : iAVCOutputLevel; |
|
2062 } |
|
2063 else |
|
2064 { |
|
2065 User::Leave(KErrNotSupported); |
|
2066 } |
|
2067 |
|
2068 // lengthSizeMinusOne indicates the length in bytes of the NALUnitLength field minus one. |
|
2069 outputPtr[4] = 0x03; // 4 bytes |
|
2070 outputPtr[4] |= 0x0FC; // 6 reserved bits (all 1) |
|
2071 // numOfSequenceParameterSets indicates the number of sequence parameter sets |
|
2072 outputPtr[5] = numSPS; |
|
2073 outputPtr[5] |= 0xE0; // 3 reserved bits (all 1) |
|
2074 |
|
2075 TInt len = 6; |
|
2076 |
|
2077 // Copy the SPS unit(s) to the buffer |
|
2078 Mem::Copy(&outputPtr[6], spsPtr , totalSPSLength); |
|
2079 len += totalSPSLength; |
|
2080 outputPtr[6+totalSPSLength] = numPPS; |
|
2081 len += 1; |
|
2082 |
|
2083 // Copy the PPS unit(s) to the buffer |
|
2084 Mem::Copy(&outputPtr[6+totalSPSLength+1], ppsPtr , totalPPSLength); |
|
2085 len += totalPPSLength; |
|
2086 aDstBuf.SetLength(len); |
|
2087 |
|
2088 CleanupStack::PopAndDestroy(temp2); |
|
2089 CleanupStack::PopAndDestroy(temp1); |
|
2090 PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL out"))); |
|
2091 } |
|
2092 |
|
2093 // ----------------------------------------------------------------------------- |
|
2094 // CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL |
|
2095 // |
|
2096 // Converts AVC frame from Bytestream (ElementaryStream) encapsulation to |
|
2097 // file format AVC sample structure by replacing bytestream headers with NAL unit sizes. |
|
2098 // ----------------------------------------------------------------------------- |
|
2099 // |
|
2100 void CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizes( CCMRMediaBuffer* aBuffer ) |
|
2101 { |
|
2102 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL in"))); |
|
2103 TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr()); |
|
2104 TUint headerLength = aBuffer->Data().Length(); |
|
2105 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL buffer length: %d"), headerLength)); |
|
2106 |
|
2107 TInt nalLength = 0; |
|
2108 TBool moreThanOneNAL = EFalse; |
|
2109 TInt i = 0; |
|
2110 TInt j = 0; |
|
2111 for (i=0; i<headerLength; i++) |
|
2112 { |
|
2113 if ( inputPtr[i] == 0 && |
|
2114 inputPtr[i+1] == 0 && |
|
2115 inputPtr[i+2] == 0 && |
|
2116 inputPtr[i+3] == 1 ) |
|
2117 { // found bytestream header [00 00 00 01] |
|
2118 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL found header at: %d"), i)); |
|
2119 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL NAL type: %d"), TInt(inputPtr[i+4] & 0x1F) )); |
|
2120 if (moreThanOneNAL) |
|
2121 {// we found start of next NAL unit in memory buffer so update previous size |
|
2122 nalLength = i-j-4; // 4 is the bytestream header |
|
2123 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL NAL length: %d"), nalLength)); |
|
2124 inputPtr[j] = TUint8((nalLength >> 24) & 0xff); |
|
2125 inputPtr[j+1] = TUint8((nalLength >> 16) & 0xff); |
|
2126 inputPtr[j+2] = TUint8((nalLength >> 8) & 0xff); |
|
2127 inputPtr[j+3] = TUint8(nalLength & 0xff); |
|
2128 } |
|
2129 moreThanOneNAL = ETrue; |
|
2130 j=i; |
|
2131 } |
|
2132 } |
|
2133 // and update last (or if only 1 NAL size: |
|
2134 nalLength = headerLength-j-4; // 4 is the bytestream header |
|
2135 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL last NAL length: %d"), nalLength)); |
|
2136 inputPtr[j] = TUint8((nalLength >> 24) & 0xff); |
|
2137 inputPtr[j+1] = TUint8((nalLength >> 16) & 0xff); |
|
2138 inputPtr[j+2] = TUint8((nalLength >> 8) & 0xff); |
|
2139 inputPtr[j+3] = TUint8(nalLength & 0xff); |
|
2140 PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL out"))); |
|
2141 } |
|
2142 |
|
2143 // ----------------------------------------------------------------------------- |
|
2144 // CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes |
|
2145 // |
|
2146 // Converts AVC frame from NAL (EGenericPayload) encapsulation to |
|
2147 // file format AVC sample structure by replacing NAL encapsulation with NAL unit sizes. |
|
2148 // ----------------------------------------------------------------------------- |
|
2149 // |
|
2150 void CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes( CCMRMediaBuffer* aBuffer ) |
|
2151 { |
|
2152 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes in"))); |
|
2153 TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr()); |
|
2154 TUint bufferLength = aBuffer->Data().Length(); |
|
2155 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes buffer length: %d"), bufferLength)); |
|
2156 |
|
2157 // Offset to the end and get NAL unit count |
|
2158 TInt offset = bufferLength-4; //last 4 bytes are the NAL unit count |
|
2159 TInt nalCount = TInt(inputPtr[offset]) + |
|
2160 (TInt(inputPtr[offset + 1]) << 8) + |
|
2161 (TInt(inputPtr[offset + 2]) << 16) + |
|
2162 (TInt(inputPtr[offset + 3]) << 24); |
|
2163 |
|
2164 TInt frameStart = 0; |
|
2165 TInt frameSize = 0; |
|
2166 TInt outputOffset = 0; |
|
2167 for(TInt i=0; i<nalCount; i++) |
|
2168 {//go through all NAL units in buffer |
|
2169 // Offset to the start of NAL Unit infos |
|
2170 offset = bufferLength-4-(8*nalCount); // 4 is the NAL unit count at end of buffer, 8 bytes used per NAL Unit for FrameStartOffset and FrameSize. |
|
2171 |
|
2172 // Get frame start offset |
|
2173 offset += 8*i; |
|
2174 frameStart = TInt(inputPtr[offset]) + |
|
2175 (TInt(inputPtr[offset + 1]) << 8) + |
|
2176 (TInt(inputPtr[offset + 2]) << 16) + |
|
2177 (TInt(inputPtr[offset + 3]) << 24); |
|
2178 |
|
2179 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() NAL unit %d frame start: %d "), i, frameStart )); |
|
2180 |
|
2181 // Get frame size |
|
2182 offset += 4; |
|
2183 frameSize = TInt(inputPtr[offset]) + |
|
2184 (TInt(inputPtr[offset + 1]) << 8) + |
|
2185 (TInt(inputPtr[offset + 2]) << 16) + |
|
2186 (TInt(inputPtr[offset + 3]) << 24); |
|
2187 |
|
2188 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() NAL unit %d frame size: %d "), i, frameSize )); |
|
2189 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() NAL unit %d type: %d "), i, TInt(inputPtr[frameStart] & 0x1F) )); |
|
2190 |
|
2191 iVideoBuffer[outputOffset] = TUint8((frameSize >> 24) & 0xff); |
|
2192 iVideoBuffer[outputOffset+1] = TUint8((frameSize >> 16) & 0xff); |
|
2193 iVideoBuffer[outputOffset+2] = TUint8((frameSize >> 8) & 0xff); |
|
2194 iVideoBuffer[outputOffset+3] = TUint8(frameSize & 0xff); |
|
2195 |
|
2196 Mem::Copy(iVideoBuffer+outputOffset+4, inputPtr+frameStart, frameSize); |
|
2197 outputOffset += 4 + frameSize; // 4 bytes for length information. |
|
2198 } |
|
2199 iVideoBufferFrameSize = outputOffset; |
|
2200 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() new video buffer size: %d "), iVideoBufferFrameSize )); |
|
2201 PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes out"))); |
|
2202 } |
|
2203 |
|
2204 // ----------------------------------------------------------------------------- |
|
2205 // CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName |
|
2206 // ----------------------------------------------------------------------------- |
|
2207 // |
|
2208 void CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName( MP4FileName tempFileName ) |
|
2209 { |
|
2210 PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName entering, tempFileName=%x, file count=%d"),tempFileName, iDeleteFileQueue->Count())); |
|
2211 MP4FileName* tempFileNamePtr = NULL; |
|
2212 TInt result = KErrNoMemory; |
|
2213 |
|
2214 // Add image to the queue. |
|
2215 tempFileNamePtr = new MP4FileName; |
|
2216 PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName tempFileName=%x, tempFileNamePtr=%x"), tempFileName, tempFileNamePtr)); |
|
2217 if ( tempFileNamePtr && iDeleteFileQueue ) |
|
2218 { |
|
2219 *tempFileNamePtr = tempFileName; |
|
2220 result = iDeleteFileQueue->Append( tempFileNamePtr ); |
|
2221 } |
|
2222 if ( result != KErrNone ) // Append failed -> do sync remove |
|
2223 { |
|
2224 TInt err = wremove( tempFileName ); |
|
2225 PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName wremove sync err=%d, tempFileName=%x"), err, tempFileName)); |
|
2226 free(tempFileName); |
|
2227 tempFileName = 0; |
|
2228 if ( tempFileNamePtr ) |
|
2229 { |
|
2230 delete tempFileNamePtr; |
|
2231 tempFileNamePtr = 0; |
|
2232 } |
|
2233 } |
|
2234 else // Append OK, start async delete if not running already |
|
2235 { |
|
2236 if (iDeleteFileQueue->Count()) |
|
2237 { |
|
2238 |
|
2239 if ( !iIdleDelete->IsActive() ) |
|
2240 { |
|
2241 PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName() Start IdleDelete, file count=%d"), iDeleteFileQueue->Count())); |
|
2242 iIdleDelete->Start( TCallBack( IdleDelete, this ) ); |
|
2243 } |
|
2244 } |
|
2245 } |
|
2246 |
|
2247 PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName exiting"))); |
|
2248 } |
|
2249 |
|
2250 |
|
2251 // --------------------------------------------------------------------------- |
|
2252 // CCamC3GPDataSinkImp::IdleDelete |
|
2253 // --------------------------------------------------------------------------- |
|
2254 // |
|
2255 TInt CCamC3GPDataSinkImp::IdleDelete( TAny* aCont ) |
|
2256 { |
|
2257 CCamC3GPDataSinkImp* appCont = static_cast<CCamC3GPDataSinkImp*>( aCont ); |
|
2258 return ( appCont->DoIdleDelete() ); |
|
2259 } |
|
2260 |
|
2261 // --------------------------------------------------------------------------- |
|
2262 // CCamC3GPDataSinkImp::DoIdleDelete |
|
2263 // --------------------------------------------------------------------------- |
|
2264 // |
|
2265 TInt CCamC3GPDataSinkImp::DoIdleDelete() |
|
2266 { |
|
2267 PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() in, file count=%d"), iDeleteFileQueue->Count())); |
|
2268 TInt err = KErrNone; |
|
2269 MP4FileName tempFileName; |
|
2270 TInt filesLeft = EFalse; |
|
2271 |
|
2272 // Delete one file from queue |
|
2273 if ( iDeleteFileQueue ) |
|
2274 { |
|
2275 if ( iDeleteFileQueue->Count() ) |
|
2276 { |
|
2277 tempFileName = *(*iDeleteFileQueue)[0]; |
|
2278 PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete index 0:tempFileName=%x %s"), tempFileName, tempFileName)); |
|
2279 delete (*iDeleteFileQueue)[0]; |
|
2280 iDeleteFileQueue->Remove( 0 ); |
|
2281 err = wremove( tempFileName ); |
|
2282 PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete wremove async err=%d, tempFileName=%x %s"), err, tempFileName, tempFileName)); |
|
2283 err++; // remove compiler warning |
|
2284 free(tempFileName); |
|
2285 tempFileName = 0; |
|
2286 } |
|
2287 |
|
2288 // Start next deletion if queue is not empty |
|
2289 if ( iDeleteFileQueue->Count() ) |
|
2290 { |
|
2291 PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() continue, file count=%d"), iDeleteFileQueue->Count())); |
|
2292 filesLeft = ETrue; |
|
2293 } |
|
2294 } |
|
2295 |
|
2296 PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() out"))); |
|
2297 return ( filesLeft ); |
|
2298 } |
|
2299 |
|
2300 |
|
2301 // End of File |