diff -r 000000000000 -r 40261b775718 mmplugins/lib3gp/impl/src/asyncfileparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmplugins/lib3gp/impl/src/asyncfileparser.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,536 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +// INCLUDE FILES +#include +#include +#include +#include <3gplibrary/mp4lib.h> +#include "mp4atom.h" +#include "mp4memwrap.h" +#include "asyncfileparser.h" + +// MACROS +// Debug print macro +#if defined(_DEBUG) && defined(_ASYNCFILEPARSERLOGGING) +#include +#define PRINT(x) +#else +#define PRINT(x) +#endif + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::CFileAsyncParser +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CFileAsyncParser::CFileAsyncParser() : CActive( EPriorityHigh ), iDiskBufferPointer(NULL,0) + { + + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CFileAsyncParser::ConstructL( MP4HandleStruct* aHandle, RFile64& aFile ) + { + PRINT(_L("CFileAsyncParser::ConstructL() IN")); + iError = KErrNone; + iInputFile = &aFile; + iHandle = aHandle; + iAudioSize = 0; + iReturnedAudioFrames = 0; + iAudioTimeStamp = 0; + iAudioTimeStamp2 = 1; // always fill timestamp2 too (null = dont fill) + iAllDataInMemory = EFalse; + + if ( iHandle->readBufferSize == 0) + { + iReadBufferSize = READBUFSIZE; + } + else + { + iReadBufferSize = iHandle->readBufferSize; + } + + iDiskBuffer = HBufC8::NewL(iReadBufferSize); + iCurrentDiskReadPosition = 0; + iCurrentBufferReadPosition = 0; + CActiveScheduler::Add(this); + + PRINT(_L("CFileAsyncParser::ConstructL() OUT")); + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CFileAsyncParser* CFileAsyncParser::NewL( MP4HandleStruct* aHandle, RFile64& aFile ) + { + CFileAsyncParser* self = new(ELeave) CFileAsyncParser; + CleanupStack::PushL(self); + self->ConstructL( aHandle, aFile ); + CleanupStack::Pop(self); + return self; + } + +// ----------------------------------------------------------------------------- +// Destructor +// ----------------------------------------------------------------------------- +// +CFileAsyncParser::~CFileAsyncParser() + { + PRINT(_L("CFileAsyncParser::~CFileAsyncParser() in")); + + if ( IsActive() ) + { + if ( iAsyncReadOngoing ) + { + Cancel(); + } + } + + delete iDiskBuffer; + PRINT(_L("CFileAsyncParser::~CFileAsyncParser() out")); + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::ReadAudioFrames( ); +// Writes incoming buffer data to internal buffers for writing to disk. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CFileAsyncParser::ReadAudioFrames( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead ) + { + PRINT(_L("CFileAsyncParser::ReadAudioFrames()")); + iProcessingAudio = ETrue; + return ReadDataAsync( buffer, aPosition, aBytesToRead ); + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::ReadVideoFrame( ); +// Writes incoming buffer data to internal buffers for writing to disk. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CFileAsyncParser::ReadVideoFrame( mp4_u8* buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead ) + { + PRINT(_L("CFileAsyncParser::ReadVideoFrame()")); + iProcessingAudio = EFalse; + return ReadDataAsync( buffer, aPosition, aBytesToRead ); + } + + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::ReadDataAsync( ); +// Reads data from file asynchronously. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +TInt CFileAsyncParser::ReadDataAsync( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead ) + { + PRINT(_L("CFileAsyncParser::ReadDataAsync() in")); + iBuffer = buffer; + if ( iAsyncReadOngoing ) + { + return -1; // only one async read can be ongoing at one time; + } + if (!iDiskBuffer) + { + return -1; + } + + // Is the new seek point inside the current disk buffer? + if ( (iCurrentDiskReadPosition > aPosition) && + (( iCurrentDiskReadPosition - iDiskBuffer->Length() ) <= aPosition )) + { + // Yes + iCurrentBufferReadPosition = iDiskBuffer->Length() - (iCurrentDiskReadPosition - aPosition); + } + else + { + // No, set current position and zero diskbuffer + iCurrentBufferReadPosition = 0; + iCurrentDiskReadPosition = (mp4_i64)aPosition; + iDiskBuffer->Des().SetLength(0); + } + + iBytesToRead = aBytesToRead; + iBytesRead = 0; + TInt available = 0; + + // How much data is available in diskbuffer. + available = iDiskBuffer->Length() - iCurrentBufferReadPosition; + if (available > iBytesToRead) + { + available = iBytesToRead; + } + + // If any available copy it first to output buffer + if (available ) + { + memcpy(iBuffer, iDiskBuffer->Ptr() + iCurrentBufferReadPosition, available); + iCurrentBufferReadPosition += available; + iBytesRead += available; + } + + // If we got everything from diskbuffer process it right away + if (iBytesRead == iBytesToRead) + { + PRINT(_L("CFileAsyncParser::ReadDataAsync() Data found in memory, no need to read file - return right away")); + iAllDataInMemory = ETrue; + SetActive(); + TRequestStatus* tmp = &iStatus; + User::RequestComplete(tmp, KErrNone); + PRINT(_L("CFileAsyncParser::ReadDataAsync() out")); + return MP4_OK; + } + else + { + // Need to read rest of the requested data from file. + iAllDataInMemory = EFalse; + } + + // Determine used readbuffer size + if ( iHandle->readBufferSize == 0) + { + iReadBufferSize = READBUFSIZE; + } + else + { + iReadBufferSize = iHandle->readBufferSize; + } + + // Increase disk read buffer size if requested frames are larger than current disk buffer. + if ( (iBytesToRead > iReadBufferSize ) || (iReadBufferSize != iDiskBuffer->Des().MaxLength()) ) + { + iReadBufferSize = iBytesToRead; + if (iDiskBuffer) + { + delete iDiskBuffer; + iDiskBuffer = NULL; + TRAPD(memerror, iDiskBuffer = HBufC8::NewL(iReadBufferSize)); + if (memerror) + { + return MP4_OUT_OF_MEMORY; + } + else + { + iCurrentBufferReadPosition = 0; + } + } + } + + iAsyncReadOngoing = ETrue; + iDiskBufferPointer.Set(iDiskBuffer->Des()); + iCurrentDiskReadPosition = aPosition + iBytesRead; + switch (iHandle->sourceType) + { + case MP4_SOURCE_RFILE: + { + PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading RFile64")); + RFile64* rfile = (RFile64*)iHandle->rfile; + rfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus); + break; + } + case MP4_SOURCE_CAF: + { + PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading CAF object")); + iHandle->cafError = iHandle->cfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus); + if ( iHandle->cafError != KErrNone) + return -2; + break; + } + default: + return -1; + } + + if ( !IsActive() ) + { + SetActive(); + } + PRINT(_L("CFileAsyncParser::ReadDataAsync() out")); + return 0; + } + + + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::DoCancel() +// From CActive Cancels async request. +// ----------------------------------------------------------------------------- +// +void CFileAsyncParser::DoCancel() + { + PRINT(_L("CFileAsyncParser::DoCancel() in")); + if (iAsyncReadOngoing) + { + if (iHandle->sourceType == MP4_SOURCE_RFILE) + { + // cancel read from file + ((RFile64 *)(iHandle->rfile))->ReadCancel(); + } + else if (iHandle->sourceType == MP4_SOURCE_CAF) + { + // cancel read from caf object + iHandle->cfile->ReadCancel(iStatus); + } + iAsyncReadOngoing = EFalse; + } + + PRINT(_L("CFileAsyncParser::DoCancel() out")); + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::ReturnAudioFrames() +// Return audio frames to observer. +// ----------------------------------------------------------------------------- +// +void CFileAsyncParser::ReturnAudioFrames() + { + PRINT(_L("CFileAsyncParser::ReturnAudioFrames() in")); + TInt error = KErrNone; + + // Update last accessed position in file pointer + if (iHandle->audioSampleOffset + iHandle->audioSampleSize - 1 > iHandle->lastAccessedPosInFile) + { + iHandle->lastAccessedPosInFile = iHandle->audioSampleOffset + iHandle->audioSampleSize - 1; + } + + // Fill audio frame size + iAudioSize = iHandle->audioSampleSize; + + // Fill audio timestamp information + iAudioTimeStamp = 0; + iAudioTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0) + error = convertAudioSampleToTime(iHandle, iHandle->moov->trakAudio->mdia, &iAudioTimeStamp, &iAudioTimeStamp2); + if (error == MP4_OK) + { + // Fill iReturnedAudioFrames + iReturnedAudioFrames = 0; + error = CalculateAudioFrameCount(); + } + + // Move forward in audio samples + if (error == MP4_OK) + { + error = advanceAudioSample(iHandle, iHandle->moov->trakAudio); + if ( error == -1) + { + error = MP4_ERROR; + } + else if ( error == -2 ) + { + error = MP4_OK; + iHandle->audioLast = MP4TRUE; + } + } + + iAsyncReadOngoing = EFalse; + iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(error, + iAudioSize, + iAudioTimeStamp, + iReturnedAudioFrames, + iAudioTimeStamp2); + PRINT(_L("CFileAsyncParser::ReturnAudioFrames() out")); + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::ReturnVideoFrame() +// Return video frame to observer. +// ----------------------------------------------------------------------------- +// +void CFileAsyncParser::ReturnVideoFrame() + { + PRINT(_L("CFileAsyncParser::ReturnVideoFrame() in")); + TInt error = KErrNone; + + // Update last accessed position in file pointer + if (iHandle->videoFrameOffset + iHandle->videoFrameSize - 1 > iHandle->lastAccessedPosInFile) + { + iHandle->lastAccessedPosInFile = iHandle->videoFrameOffset + iHandle->videoFrameSize - 1; + } + + // Fill video frame size + iVideoSize = iHandle->videoFrameSize; + + // Fill video timestamp information + iVideoTimeStamp = 0; + iVideoTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0) + error = convertVideoSampleToTime(iHandle, iHandle->moov->trakVideo->mdia, &iVideoTimeStamp, &iVideoTimeStamp2); + if (error == MP4_OK) + { + // Fill iKeyFrame + iVideoKeyFrame = 0; + error = isVideoFrameKeyFrame(iHandle, iHandle->moov->trakVideo, &iVideoKeyFrame); + } + + // Move forward in video frames + if (error == MP4_OK) + { + error = advanceVideoFrame(iHandle, iHandle->moov->trakVideo); + if ( error == -1) + { + error = MP4_ERROR; + } + else if ( error == -2 ) + { + error = MP4_OK; + iHandle->videoLast = MP4TRUE; + } + } + + iAsyncReadOngoing = EFalse; + iHandle->asyncObserver->M3GPMP4LibVideoFrameAvailable(error, + iVideoSize, + iVideoTimeStamp, + iVideoKeyFrame, + iVideoTimeStamp2); + PRINT(_L("CFileAsyncParser::ReturnVideoFrame() out")); + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::CalculateAudioFrameCount() +// Return video frame to observer. +// ----------------------------------------------------------------------------- +// +TInt CFileAsyncParser::CalculateAudioFrameCount() + { + mp4_i32 frameLength = 0; + mp4_u32 numOfFrames = 0; + mp4_u8 *framepointer = 0; + mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1}; + trackAtom *trak = iHandle->moov->trakAudio; + + if (!trak) + { + return -1; + } + + /* AMR */ + if (trak->mdia->minf) + if (trak->mdia->minf->stbl) + if (trak->mdia->minf->stbl->stsd) + if (iHandle->type & MP4_TYPE_AMR_NB) + { + framepointer = iBuffer; + numOfFrames = 0; + while ( iBytesRead > 0 ) + { + frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)]; + if ( frameLength == 0) + { + return -4; + } + iBytesRead -= frameLength; + framepointer += frameLength; + numOfFrames++; + } + iReturnedAudioFrames = numOfFrames; + } + else if (iHandle->type & MP4_TYPE_AMR_WB) + { + /* Return the number of sample entries listed for this particular sample entry index */ + if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]) + if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr) + iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr->framesPerSample; + } + else + { + } + + /* MPEG-4 audio */ + if (trak->mdia->minf) + if (trak->mdia->minf->stbl) + if (trak->mdia->minf->stbl->stsd) + if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1]) + iReturnedAudioFrames = 1; + + /* QCELP 13K as QCELPSampleEntry*/ + if (trak->mdia->minf) + if (trak->mdia->minf->stbl) + if (trak->mdia->minf->stbl->stsd) + if ((iHandle->type & MP4_TYPE_QCELP_13K) && (!iHandle->qcelpStoredAsMPEGAudio)) + { + /* Return the number of sample entries listed for this particular sample entry index */ + if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]) + if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp) + iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp->framesPerSample; + } + + /* QCELP 13K as MPEG-4 audio */ + if (trak->mdia->minf) + if (trak->mdia->minf->stbl) + if (trak->mdia->minf->stbl->stsd) + if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1]) + iReturnedAudioFrames = 1; + + return MP4_OK; + } + +// ----------------------------------------------------------------------------- +// CFileAsyncParser::RunL() +// From CActive Called when async request completes. +// ----------------------------------------------------------------------------- +// +void CFileAsyncParser::RunL() + { + PRINT(_L("CFileAsyncParser::RunL() in")); + if ( iStatus != KErrNone ) + { + PRINT((_L("CFileAsyncParser::RunL() error in previous async: %d "), iStatus.Int() )); + iError = iStatus.Int(); + iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(MP4_FILE_ERROR,0,0,0,0); + return; + } + + if (!iAllDataInMemory) + { + if ((mp4_u32)iDiskBuffer->Length() == 0) // EOF or error + { + iError = MP4_FILE_ERROR; // metadata info doesn't match file -> corrupted clip. + } + + memcpy(iBuffer+iBytesRead, iDiskBuffer->Ptr(), iBytesToRead-iBytesRead); + iCurrentBufferReadPosition += iBytesToRead-iBytesRead; + iCurrentDiskReadPosition += iDiskBuffer->Length(); + iBytesRead = iBytesToRead; + + // set handle disk buffer sizes to zero just in case. + iHandle->diskReadBufPos = 0; + iHandle->diskReadSize = 0; + iHandle->diskReadBufStart = 0; + iHandle->diskReadPos = iCurrentDiskReadPosition; + } + + if ( iProcessingAudio ) + { + ReturnAudioFrames(); + } + else + { + ReturnVideoFrame(); + } + + PRINT(_L("CFileAsyncParser::RunL() out")); + } + +// End of File