Update contrib.
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 #include <f32file64.h>
20 #include <3gplibrary/mp4lib.h>
22 #include "mp4memwrap.h"
23 #include "asyncfileparser.h"
27 #if defined(_DEBUG) && defined(_ASYNCFILEPARSERLOGGING)
34 // ============================ MEMBER FUNCTIONS ===============================
36 // -----------------------------------------------------------------------------
37 // CFileAsyncParser::CFileAsyncParser
38 // C++ default constructor can NOT contain any code, that
40 // -----------------------------------------------------------------------------
42 CFileAsyncParser::CFileAsyncParser() : CActive( EPriorityHigh ), iDiskBufferPointer(NULL,0)
47 // -----------------------------------------------------------------------------
48 // CFileAsyncParser::ConstructL
49 // Symbian 2nd phase constructor can leave.
50 // -----------------------------------------------------------------------------
52 void CFileAsyncParser::ConstructL( MP4HandleStruct* aHandle, RFile64& aFile )
54 PRINT(_L("CFileAsyncParser::ConstructL() IN"));
59 iReturnedAudioFrames = 0;
61 iAudioTimeStamp2 = 1; // always fill timestamp2 too (null = dont fill)
62 iAllDataInMemory = EFalse;
64 if ( iHandle->readBufferSize == 0)
66 iReadBufferSize = READBUFSIZE;
70 iReadBufferSize = iHandle->readBufferSize;
73 iDiskBuffer = HBufC8::NewL(iReadBufferSize);
74 iCurrentDiskReadPosition = 0;
75 iCurrentBufferReadPosition = 0;
76 CActiveScheduler::Add(this);
78 PRINT(_L("CFileAsyncParser::ConstructL() OUT"));
81 // -----------------------------------------------------------------------------
82 // CFileAsyncParser::NewL
83 // Two-phased constructor.
84 // -----------------------------------------------------------------------------
86 CFileAsyncParser* CFileAsyncParser::NewL( MP4HandleStruct* aHandle, RFile64& aFile )
88 CFileAsyncParser* self = new(ELeave) CFileAsyncParser;
89 CleanupStack::PushL(self);
90 self->ConstructL( aHandle, aFile );
91 CleanupStack::Pop(self);
95 // -----------------------------------------------------------------------------
97 // -----------------------------------------------------------------------------
99 CFileAsyncParser::~CFileAsyncParser()
101 PRINT(_L("CFileAsyncParser::~CFileAsyncParser() in"));
105 if ( iAsyncReadOngoing )
112 PRINT(_L("CFileAsyncParser::~CFileAsyncParser() out"));
115 // -----------------------------------------------------------------------------
116 // CFileAsyncParser::ReadAudioFrames( );
117 // Writes incoming buffer data to internal buffers for writing to disk.
118 // (other items were commented in a header).
119 // -----------------------------------------------------------------------------
121 TInt CFileAsyncParser::ReadAudioFrames( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
123 PRINT(_L("CFileAsyncParser::ReadAudioFrames()"));
124 iProcessingAudio = ETrue;
125 return ReadDataAsync( buffer, aPosition, aBytesToRead );
128 // -----------------------------------------------------------------------------
129 // CFileAsyncParser::ReadVideoFrame( );
130 // Writes incoming buffer data to internal buffers for writing to disk.
131 // (other items were commented in a header).
132 // -----------------------------------------------------------------------------
134 TInt CFileAsyncParser::ReadVideoFrame( mp4_u8* buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
136 PRINT(_L("CFileAsyncParser::ReadVideoFrame()"));
137 iProcessingAudio = EFalse;
138 return ReadDataAsync( buffer, aPosition, aBytesToRead );
142 // -----------------------------------------------------------------------------
143 // CFileAsyncParser::ReadDataAsync( );
144 // Reads data from file asynchronously.
145 // (other items were commented in a header).
146 // -----------------------------------------------------------------------------
148 TInt CFileAsyncParser::ReadDataAsync( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
150 PRINT(_L("CFileAsyncParser::ReadDataAsync() in"));
152 if ( iAsyncReadOngoing )
154 return -1; // only one async read can be ongoing at one time;
161 // Is the new seek point inside the current disk buffer?
162 if ( (iCurrentDiskReadPosition > aPosition) &&
163 (( iCurrentDiskReadPosition - iDiskBuffer->Length() ) <= aPosition ))
166 iCurrentBufferReadPosition = iDiskBuffer->Length() - (iCurrentDiskReadPosition - aPosition);
170 // No, set current position and zero diskbuffer
171 iCurrentBufferReadPosition = 0;
172 iCurrentDiskReadPosition = (mp4_i64)aPosition;
173 iDiskBuffer->Des().SetLength(0);
176 iBytesToRead = aBytesToRead;
180 // How much data is available in diskbuffer.
181 available = iDiskBuffer->Length() - iCurrentBufferReadPosition;
182 if (available > iBytesToRead)
184 available = iBytesToRead;
187 // If any available copy it first to output buffer
190 memcpy(iBuffer, iDiskBuffer->Ptr() + iCurrentBufferReadPosition, available);
191 iCurrentBufferReadPosition += available;
192 iBytesRead += available;
195 // If we got everything from diskbuffer process it right away
196 if (iBytesRead == iBytesToRead)
198 PRINT(_L("CFileAsyncParser::ReadDataAsync() Data found in memory, no need to read file - return right away"));
199 iAllDataInMemory = ETrue;
201 TRequestStatus* tmp = &iStatus;
202 User::RequestComplete(tmp, KErrNone);
203 PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
208 // Need to read rest of the requested data from file.
209 iAllDataInMemory = EFalse;
212 // Determine used readbuffer size
213 if ( iHandle->readBufferSize == 0)
215 iReadBufferSize = READBUFSIZE;
219 iReadBufferSize = iHandle->readBufferSize;
222 // Increase disk read buffer size if requested frames are larger than current disk buffer.
223 if ( (iBytesToRead > iReadBufferSize ) || (iReadBufferSize != iDiskBuffer->Des().MaxLength()) )
225 iReadBufferSize = iBytesToRead;
230 TRAPD(memerror, iDiskBuffer = HBufC8::NewL(iReadBufferSize));
233 return MP4_OUT_OF_MEMORY;
237 iCurrentBufferReadPosition = 0;
242 iAsyncReadOngoing = ETrue;
243 iDiskBufferPointer.Set(iDiskBuffer->Des());
244 iCurrentDiskReadPosition = aPosition + iBytesRead;
245 switch (iHandle->sourceType)
247 case MP4_SOURCE_RFILE:
249 PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading RFile64"));
250 RFile64* rfile = (RFile64*)iHandle->rfile;
251 rfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
256 PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading CAF object"));
257 iHandle->cafError = iHandle->cfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
258 if ( iHandle->cafError != KErrNone)
270 PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
276 // -----------------------------------------------------------------------------
277 // CFileAsyncParser::DoCancel()
278 // From CActive Cancels async request.
279 // -----------------------------------------------------------------------------
281 void CFileAsyncParser::DoCancel()
283 PRINT(_L("CFileAsyncParser::DoCancel() in"));
284 if (iAsyncReadOngoing)
286 if (iHandle->sourceType == MP4_SOURCE_RFILE)
288 // cancel read from file
289 ((RFile64 *)(iHandle->rfile))->ReadCancel();
291 else if (iHandle->sourceType == MP4_SOURCE_CAF)
293 // cancel read from caf object
294 iHandle->cfile->ReadCancel(iStatus);
296 iAsyncReadOngoing = EFalse;
299 PRINT(_L("CFileAsyncParser::DoCancel() out"));
302 // -----------------------------------------------------------------------------
303 // CFileAsyncParser::ReturnAudioFrames()
304 // Return audio frames to observer.
305 // -----------------------------------------------------------------------------
307 void CFileAsyncParser::ReturnAudioFrames()
309 PRINT(_L("CFileAsyncParser::ReturnAudioFrames() in"));
310 TInt error = KErrNone;
312 // Update last accessed position in file pointer
313 if (iHandle->audioSampleOffset + iHandle->audioSampleSize - 1 > iHandle->lastAccessedPosInFile)
315 iHandle->lastAccessedPosInFile = iHandle->audioSampleOffset + iHandle->audioSampleSize - 1;
318 // Fill audio frame size
319 iAudioSize = iHandle->audioSampleSize;
321 // Fill audio timestamp information
323 iAudioTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
324 error = convertAudioSampleToTime(iHandle, iHandle->moov->trakAudio->mdia, &iAudioTimeStamp, &iAudioTimeStamp2);
327 // Fill iReturnedAudioFrames
328 iReturnedAudioFrames = 0;
329 error = CalculateAudioFrameCount();
332 // Move forward in audio samples
335 error = advanceAudioSample(iHandle, iHandle->moov->trakAudio);
340 else if ( error == -2 )
343 iHandle->audioLast = MP4TRUE;
347 iAsyncReadOngoing = EFalse;
348 iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(error,
351 iReturnedAudioFrames,
353 PRINT(_L("CFileAsyncParser::ReturnAudioFrames() out"));
356 // -----------------------------------------------------------------------------
357 // CFileAsyncParser::ReturnVideoFrame()
358 // Return video frame to observer.
359 // -----------------------------------------------------------------------------
361 void CFileAsyncParser::ReturnVideoFrame()
363 PRINT(_L("CFileAsyncParser::ReturnVideoFrame() in"));
364 TInt error = KErrNone;
366 // Update last accessed position in file pointer
367 if (iHandle->videoFrameOffset + iHandle->videoFrameSize - 1 > iHandle->lastAccessedPosInFile)
369 iHandle->lastAccessedPosInFile = iHandle->videoFrameOffset + iHandle->videoFrameSize - 1;
372 // Fill video frame size
373 iVideoSize = iHandle->videoFrameSize;
375 // Fill video timestamp information
377 iVideoTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
378 error = convertVideoSampleToTime(iHandle, iHandle->moov->trakVideo->mdia, &iVideoTimeStamp, &iVideoTimeStamp2);
383 error = isVideoFrameKeyFrame(iHandle, iHandle->moov->trakVideo, &iVideoKeyFrame);
386 // Move forward in video frames
389 error = advanceVideoFrame(iHandle, iHandle->moov->trakVideo);
394 else if ( error == -2 )
397 iHandle->videoLast = MP4TRUE;
401 iAsyncReadOngoing = EFalse;
402 iHandle->asyncObserver->M3GPMP4LibVideoFrameAvailable(error,
407 PRINT(_L("CFileAsyncParser::ReturnVideoFrame() out"));
410 // -----------------------------------------------------------------------------
411 // CFileAsyncParser::CalculateAudioFrameCount()
412 // Return video frame to observer.
413 // -----------------------------------------------------------------------------
415 TInt CFileAsyncParser::CalculateAudioFrameCount()
417 mp4_i32 frameLength = 0;
418 mp4_u32 numOfFrames = 0;
419 mp4_u8 *framepointer = 0;
420 mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};
421 trackAtom *trak = iHandle->moov->trakAudio;
429 if (trak->mdia->minf)
430 if (trak->mdia->minf->stbl)
431 if (trak->mdia->minf->stbl->stsd)
432 if (iHandle->type & MP4_TYPE_AMR_NB)
434 framepointer = iBuffer;
436 while ( iBytesRead > 0 )
438 frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
439 if ( frameLength == 0)
443 iBytesRead -= frameLength;
444 framepointer += frameLength;
447 iReturnedAudioFrames = numOfFrames;
449 else if (iHandle->type & MP4_TYPE_AMR_WB)
451 /* Return the number of sample entries listed for this particular sample entry index */
452 if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1])
453 if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr)
454 iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr->framesPerSample;
461 if (trak->mdia->minf)
462 if (trak->mdia->minf->stbl)
463 if (trak->mdia->minf->stbl->stsd)
464 if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
465 iReturnedAudioFrames = 1;
467 /* QCELP 13K as QCELPSampleEntry*/
468 if (trak->mdia->minf)
469 if (trak->mdia->minf->stbl)
470 if (trak->mdia->minf->stbl->stsd)
471 if ((iHandle->type & MP4_TYPE_QCELP_13K) && (!iHandle->qcelpStoredAsMPEGAudio))
473 /* Return the number of sample entries listed for this particular sample entry index */
474 if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1])
475 if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp)
476 iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
479 /* QCELP 13K as MPEG-4 audio */
480 if (trak->mdia->minf)
481 if (trak->mdia->minf->stbl)
482 if (trak->mdia->minf->stbl->stsd)
483 if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
484 iReturnedAudioFrames = 1;
489 // -----------------------------------------------------------------------------
490 // CFileAsyncParser::RunL()
491 // From CActive Called when async request completes.
492 // -----------------------------------------------------------------------------
494 void CFileAsyncParser::RunL()
496 PRINT(_L("CFileAsyncParser::RunL() in"));
497 if ( iStatus != KErrNone )
499 PRINT((_L("CFileAsyncParser::RunL() error in previous async: %d "), iStatus.Int() ));
500 iError = iStatus.Int();
501 iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(MP4_FILE_ERROR,0,0,0,0);
505 if (!iAllDataInMemory)
507 if ((mp4_u32)iDiskBuffer->Length() == 0) // EOF or error
509 iError = MP4_FILE_ERROR; // metadata info doesn't match file -> corrupted clip.
512 memcpy(iBuffer+iBytesRead, iDiskBuffer->Ptr(), iBytesToRead-iBytesRead);
513 iCurrentBufferReadPosition += iBytesToRead-iBytesRead;
514 iCurrentDiskReadPosition += iDiskBuffer->Length();
515 iBytesRead = iBytesToRead;
517 // set handle disk buffer sizes to zero just in case.
518 iHandle->diskReadBufPos = 0;
519 iHandle->diskReadSize = 0;
520 iHandle->diskReadBufStart = 0;
521 iHandle->diskReadPos = iCurrentDiskReadPosition;
524 if ( iProcessingAudio )
533 PRINT(_L("CFileAsyncParser::RunL() out"));