diff -r 000000000000 -r 71ca22bcf22a mmfenh/advancedaudiocontroller/audiocontrollerpluginsvariant/3gpDataSourceAdapter/Src/3gpDataSourceAdapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmfenh/advancedaudiocontroller/audiocontrollerpluginsvariant/3gpDataSourceAdapter/Src/3gpDataSourceAdapter.cpp Tue Feb 02 01:08:46 2010 +0200 @@ -0,0 +1,962 @@ +/* +* Copyright (c) 2006 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: Class definition for the DataSourceAdapter functions. +* +*/ + + +// INCLUDES +#include "3gpDataSourceAdapter.h" +#include "DebugMacros.h" +#include +//#include +#include +#include +#include +#include + + +#include // EPeek +const TInt KDataSourceReadBufferSize = 16*1024; // read from source +const TInt KParserReadBufferSize = 2000; // read from parser - it only gives 1 frame +const TInt KMaxFrameSize = 1536; + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::C3gpDataSourceAdapter +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +C3gpDataSourceAdapter::C3gpDataSourceAdapter() : + MDataSink(KUidMmfFormatDecode) + + { + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::ConstructL() + { + // should end up doing this for all sources + iMediaId = KUidMediaTypeAudio; + iParserBuf = CreateSourceBufferOfSizeL(KParserReadBufferSize); + iSrcBuf = CreateSourceBufferOfSizeL(KDataSourceReadBufferSize); + iZeroBuffer = CMMFDataBuffer::NewL(0); // this is just for test to allow source seek + iHdrBuffer = CMMFDataBuffer::NewL(20); // just enough to cover the header lengths create by recorder + iAsyncProxyFillBuffer = new(ELeave) CAsyncProxyFillBuffer(*this); + + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C C3gpDataSourceAdapter* C3gpDataSourceAdapter::NewL() + { + DP0(_L("C3gpDataSourceAdapter::NewL")); + C3gpDataSourceAdapter* self = new(ELeave) C3gpDataSourceAdapter(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +// Destructor +EXPORT_C C3gpDataSourceAdapter::~C3gpDataSourceAdapter() + { + DP0(_L("C3gpDataSourceAdapter::~C3gpDataSourceAdapter")); + MP4ParseClose(iMP4Handle); + delete iParserBuf; + delete iSrcBuf; + delete iCafHandle; + iQueuedAsyncBuffers.Close(); // this is different from one in base class + delete iAsyncProxyFillBuffer; // this is different from one in base class + } + +// ----------------------------------------------------------------------------- +// From MDataSource +// ----------------------------------------------------------------------------- +// +EXPORT_C void C3gpDataSourceAdapter::FillBufferL(CMMFBuffer* aBuffer, MDataSink* aDataSink,TMediaId /*aMediaId*/) + { + TInt status = KErrNone; + CMMFDataBuffer* buffer = static_cast(aBuffer); + + DP1(_L("C3gpDataSourceAdapter::FillBufferL buffer[%x]"), buffer->Data().Ptr()); + if (aDataSink != this) + { // called from the controller + iControllerMDataSink = aDataSink; + iQueuedAsyncBuffers.Append(aBuffer); + if (iQueuedAsyncBuffers.Count() > 1) + { + DP1(_L("C3gpDataSourceAdapter::FillBufferL buffer queued count[%d]"), iQueuedAsyncBuffers.Count()); + return; + } + } + + if (iParserBuf->Data().Length()) + { + // Audio Frames previously read is appended first + buffer->Data().Append(iParserBuf->Data().Ptr(), iParserBuf->Data().Length()); + iParserBuf->Data().SetLength(0); + iParserBuf->SetPosition(0); + } + + iFillingBuffer = aBuffer; + if (iReadMp4LibSync) + { + iAsyncProxyFillBuffer->ReadSync(); + } + else + { + status = ReadAsync(); + } + + if (status == KErrNone) + { + // do nothing + } + else + { // define the use case for this... + DP1(_L("C3gpDataSourceAdapter::FillSharedBufferL, ReadAsync status[%d] calling frames available"), status); + M3GPMP4LibAudioFramesAvailable(status, 0, 0,0,0); + } + } + +EXPORT_C void C3gpDataSourceAdapter::SourcePrimeL() + { + DP0(_L("C3gpDataSourceAdapter::SourcePrimeL")); + iDataSource->SourcePrimeL(); + if (!iMP4Handle) + { + PrepareMP4ParserL(); + } + } + +EXPORT_C void C3gpDataSourceAdapter::SourceStopL() + { + DP0(_L("C3gpDataSourceAdapter::SourceStopL")); + ResetVariables(); + MP4ParseClose(iMP4Handle); + iMP4Handle = NULL; + iDataSource->SourceStopL(); + // Clear previously read Audio Frames + iParserBuf->Data().SetLength(0); + iParserBuf->SetPosition(0); + } + +// ----------------------------------------------------------------------------- +// From MMultimediaDataSourceObserver +// ----------------------------------------------------------------------------- +// +EXPORT_C void C3gpDataSourceAdapter::BufferFilled(CMMFBuffer* aBuffer) + { + TRAPD(err,BufferFilledL(aBuffer)); + if (err != KErrNone) + {//send event to client to notify error in source adapter + // SendEvent(TMMFEvent(KMMFEventCategoryPlaybackComplete, err)); + } + } + +EXPORT_C void C3gpDataSourceAdapter::Event(TUid aEvent) + { + iControllerMMultimediaDataSourceObserver->Event(aEvent); + } + +EXPORT_C TInt C3gpDataSourceAdapter::GetBitRate(TUint& aBitRate) + { + return iControllerMMultimediaDataSourceObserver->GetBitRate(aBitRate); + } + +// ----------------------------------------------------------------------------- +// From CDataSourceAdapter +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt C3gpDataSourceAdapter::SeekToTime(TUint aTimeMs, TUint& aFoundTimeMs) + { + DP0(_L("C3gpDataSourceAdapter::SeekToTime")); + TInt status = KErrNone; + mp4_u32 audioTimeStamp, videoTimeStamp; + MP4Err err = MP4ParseSeek(iMP4Handle, aTimeMs, &audioTimeStamp, &videoTimeStamp, EFalse); + + aFoundTimeMs = audioTimeStamp; + + DP3(_L("C3gpDataSourceAdapter::SeekToTime stat[%d] timeMs[%d] foundtimeMs[%d]"), err, aTimeMs,aFoundTimeMs); + + status = TranslateMP4Err(err); + return status; + } + +EXPORT_C void C3gpDataSourceAdapter::SetDataSourceL(MDataSource* aDataSource, + MMultimediaDataSourceObserver* aMMultimediaDataSourceObserver, + MAsyncEventHandler* aAsyncEventHandler) + { + DP0(_L("C3gpDataSourceAdapter::SetDataSource")); + iHeaderOnly = EFalse; + iControllerMMultimediaDataSourceObserver = aMMultimediaDataSourceObserver; + iAsyncEventHandler = aAsyncEventHandler; + ResetVariables(); + if (iDataSource) + { + return; + } + + if (iCafHandle) + { + delete iCafHandle; + iCafHandle = NULL; + } + + iDataSource = aDataSource; + iSourceType = iDataSource->DataSourceType(); + DP1(_L("C3gpDataSourceAdapter::SetDataSource DataSourceType[0x%x]"), iSourceType); + + if ((iSourceType == KMmdsStreamingSourceUid) || (iSourceType == KMmdsProgDLSourceUid) || + (iSourceType == KS60AudioStreamingSourceUid) || (iSourceType == KMmdsDescriptorSourceUid) || + (iSourceType == KUidMmfDescriptorSource) || (iSourceType == KMmdsFileSourceUid)) + { // data is streamed in buffers to parser and we read sync from parser - parser does not support seeking + iReadMp4LibSync = ETrue; + } + else + { // parser has file handle and we read async from parser - parser supports seeking + iReadMp4LibSync = EFalse; + iTimeSeekable = ETrue; + } + + if ((iSourceType == KMmdsStreamingSourceUid) || (iSourceType == KMmdsProgDLSourceUid) || + (iSourceType == KS60AudioStreamingSourceUid) || (iSourceType == KMmdsDescriptorSourceUid) || + (iSourceType == KMmdsFileSourceUid)) + { // data is written to parser + TInt err = CMultimediaDataSourceFactory::CreateDataSource(*iDataSource, iMMDataSource); + + User::LeaveIfError(err); + +// iMMDataSource->SetObserver(*this); + User::LeaveIfError(iMMDataSource->SetObserver(*this)); + User::LeaveIfError(iMMDataSource->Open()); + } + if ((iSourceType == KUidMmfFileSource) || (iSourceType == KOldProgDLSourceUid)) + { // parser has file handle + // read async from lib when it has a file handle + iClip = static_cast(iDataSource); + iDataSource->SourcePrimeL(); + iIsProtected = static_cast(iDataSource)->IsProtectedL(); + iClip->SourceThreadLogon(*aAsyncEventHandler); + iClip->ReadBufferL(iHdrBuffer,0); + iClip->ReadBufferL(iZeroBuffer, 0); // seek back to 0 position + const TUint8* ptr = iHdrBuffer->Data().Ptr(); + if (iClip->Size() == 11) + { // check for just the header from recorder + TUint32* w1p = (TUint32*)ptr; + TUint32* w2p = (TUint32*)(ptr+4); + TUint32* w3p = (TUint32*)(ptr+8); + if (((*w1p & 0x1C000000)==0x1C000000) && + ((*w2p & 0x70797466)==0x70797466) && + ((*w3p & 0x0034706D)==0x0034706D)) + { + iClip->SourceStopL(); + iHeaderOnly = ETrue; + return; + } + } + + if (iSourceType == KUidMmfFileSource) + { + CMMFFile* File = static_cast(iDataSource); + RFile rFile = File->FileL(); + iCafHandle = ContentAccess::CData::NewL(rFile, File->UniqueId(), EPeek); + } + } + } + +// ----------------------------------------------------------------------------- +// From MDataSink +// ----------------------------------------------------------------------------- +// +EXPORT_C void C3gpDataSourceAdapter::BufferFilledL(CMMFBuffer* aBuffer) + { // only talks to MMDataSource asynchronously using a single iSrcBuf + // aBuffer here is just the one iSrcBuf + CMMFDataBuffer* buffer = static_cast(aBuffer); + DP2(_L("C3gpDataSourceAdapter::BufferFilledL[%x], LastBuffer[%d]"), buffer->Data().Ptr(), aBuffer->LastBuffer()); + + TUint bufferSize = buffer->Data().Length(); + + DP1(_L("C3gpDataSourceAdapter::BufferFilledL, Length[%d]"), bufferSize); + + TUint8* bufPtr = const_cast(buffer->Data().Ptr()); + TInt err = KErrNone; +/* + if ( bufferSize > 5 ) + { + DP5(_L("C3gpDataSourceAdapter::BufferFilledL data[0x%x][0x%x][0x%x][0x%x][0x%x]"), \ + *bufPtr,*(bufPtr+1),*(bufPtr+2),*(bufPtr+3),*(bufPtr+4)); + } +*/ + if (bufferSize > 0) + { + err = TranslateMP4Err(MP4ParseWriteData(iMP4Handle, bufPtr, bufferSize)); + //mp4_u32 audioLength, audioType, timeScale, averateBitRate; + mp4_u32 audioLength, timeScale, averateBitRate; + mp4_u8 framesPerSample; + if (!iMp4HeaderAvail) + { + if (MP4_OK == MP4ParseRequestAudioDescription(iMP4Handle, &audioLength, &iAudioType, &framesPerSample, &timeScale, &averateBitRate)) + { // header is required to do anything. + iMp4HeaderAvail = ETrue; + } + } + + DP3(_L("C3gpDataSourceAdapter::BufferFilledL, MP4ParseWriteData err[%d], bufferSize[%d] d0[%x]"), err, bufferSize, bufPtr[0]); + if (err == MP4_OUT_OF_MEMORY) + { + DP0(_L("C3gpDataSourceAdapter::BufferFilledL, out of memory abort")); + User::Leave(KErrAbort); + } + if (err == MP4_OK) + { + if (!aBuffer->LastBuffer()) + { + // continue getting next buffer + DP1(_L("C3gpDataSourceAdapter::BufferFilledL, iMMDataSource->FillBuffer buffer[%x]"), iSrcBuf->Data().Ptr()); + buffer->SetPosition(0); + buffer->Data().SetLength(0); + iMMDataSource->FillBuffer(iSrcBuf); + } + else + { + // do nothing, since the file has reach the end + DP0(_L("C3gpDataSourceAdapter::BufferFilledL, reach EOF")); + iLastBufferWrittenToMp4Lib = ETrue; + } + } + } // buffersize > 0 + else + { // buffersize <= 0 + // should never reach here, since no callback should occur if no data available for streaming + DP0(_L("C3gpDataSourceAdapter::BufferFilledL, unexpected 0 length buffer")); + User::Leave(KErrAbort); + } + if (iRestartSyncRead) + { + iRestartSyncRead = EFalse; + DP0(_L("C3gpDataSourceAdapter::BufferFilledL, restarting parser read ReadSync()")); + iAsyncProxyFillBuffer->ReadSync(); + } + } + +EXPORT_C void C3gpDataSourceAdapter::EmptyBufferL( + CMMFBuffer* /*aBuffer*/, + MDataSource* /*aSupplier*/, + TMediaId /*aMediaId*/ ) + {} + +EXPORT_C TFourCC C3gpDataSourceAdapter::SinkDataTypeCode( + TMediaId /*aMediaId*/ ) + { + return KFourCCNULL; + } + +EXPORT_C TBool C3gpDataSourceAdapter::CanCreateSinkBuffer() + { + return EFalse; + } + +EXPORT_C CMMFBuffer* C3gpDataSourceAdapter::CreateSinkBufferL( + TMediaId /*aMediaId*/, + TBool& /*aReference*/ ) + { + return NULL; + } + +EXPORT_C void C3gpDataSourceAdapter::ConstructSinkL( + const TDesC8& /*aInitData*/ ) + {} + +EXPORT_C TBool C3gpDataSourceAdapter::IsPositonSeekable() + { + DP1(_L("C3gpDataSourceAdapter::IsPositonSeekable DataSourceType[0x%x]"), iSourceType); + if ((iSourceType == KMmdsStreamingSourceUid) || (iSourceType == KMmdsProgDLSourceUid) || + (iSourceType == KS60AudioStreamingSourceUid) || (iSourceType == KMmdsDescriptorSourceUid) || + (iSourceType == KUidMmfDescriptorSource) || (iSourceType == KMmdsFileSourceUid) || + (iSourceType == KOldProgDLSourceUid)) + { + return EFalse; + } + else + { + return ETrue; + } + } +// ----------------------------------------------------------------------------- +// From M3GPMP4LibAsyncObserver +// ----------------------------------------------------------------------------- +// +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable(MP4Err aError, + mp4_u32 aAudioSize, + mp4_u32 /*aTimeStamp*/, + mp4_u32 /*aReturnedFrames*/, + mp4_u32 /*aTimestamp2*/) + { + DP2(_L("C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable, aError = %d, aAudioSize = %d"), aError, aAudioSize); + DP2(_L("C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable, iParserBuf[%x] d0[%x]"), static_cast(iParserBuf)->Data().Ptr(), static_cast(iParserBuf)->Data().Ptr()[0]); + + TInt err = aError; + if (err == MP4_OK) + { + TUint8* bufPtr = const_cast(iParserBuf->Data().Ptr()); + TInt requestSize = static_cast(iFillingBuffer)->RequestSize(); + TInt bufferlength = static_cast(iFillingBuffer)->Data().Length()+aAudioSize; + + if (bufferlength <= requestSize) + { +/* TUint32 timePositionInMilliSecs = I64INT(iPlayWindowEndPosition.Int64())/1000; + + if ((iPlayWindowEndPosition != TTimeIntervalMicroSeconds(0)) && (aTimeStamp >= timePositionInMilliSecs)) + { + iFillingBuffer->SetLastBuffer(ETrue); + iFillingBuffer->SetStatus(EFull); + } + else // Not reached end of playwindow or no playwindow at all +*/ { + static_cast(iFillingBuffer)->Data().Append(iParserBuf->Data().Ptr(), aAudioSize); + iParserBuf->Data().SetLength(0); + iParserBuf->SetPosition(0); + + err = ReadAsync(); + // this error return value is handled below + + } + } + else + { + // Save this read for the next source buffer + DP2(_L("C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable, iFillingBuffer[%x] - FULL, Length[%d]"), + static_cast(iFillingBuffer)->Data().Ptr(), static_cast(iFillingBuffer)->Data().Length()); + iParserBuf->Data().SetLength(aAudioSize); + iQueValid = ETrue; + TRAP(err,iControllerMDataSink->BufferFilledL(iFillingBuffer)); // setpos could come in here and clear the queue here and add another read + // this error return value is handled below + if (iQueValid) + { // this detects if the que has been cleared and refilled + // we don't want to do this with the new buffers in the queue + iQueuedAsyncBuffers.Remove(0); + if (iQueuedAsyncBuffers.Count() > 0) + { + DP0(_L("C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable calls FillBufferL")); + TRAP(err,FillBufferL(iQueuedAsyncBuffers[0],this,iMediaId)); + // this error return value is handled below + } + } + } + } + if (err == MP4_NO_FRAME) + { + DP0(_L("C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable sending last buffer")); + iFillingBuffer->SetLastBuffer(ETrue); + TRAP(err,iControllerMDataSink->BufferFilledL(iFillingBuffer)); + if (err != KErrNone) + { + DP1(_L("C3gpDataSourceAdapter::M3GPMP4LibAudioFramesAvailable, BufferFilledL err[%d]"), err); + +// SendEvent(TMMFEvent(KMMFEventCategoryPlaybackComplete, err)); + } + } + else if (err != MP4_OK) + { + DP1(_L("error %d..."), TranslateMP4Err(err)); + + //send event to client to notify error in source adapter + if(iAsyncEventHandler) + { + iAsyncEventHandler->SendEventToClient(TMMFEvent(KMMFEventCategoryPlaybackComplete, KErrSourceAdapter)); + } + } + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::M3GPMP4LibVideoFrameAvailable +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::M3GPMP4LibVideoFrameAvailable(MP4Err /*aError*/, + mp4_u32 /*aFrameSize*/, + mp4_u32 /*aTimeStamp*/, + mp4_bool /*aKeyFrame*/, + mp4_u32 /*aTimestamp2*/) + { + // do nothing, not used + } + +// ----------------------------------------------------------------------------- +// New +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt C3gpDataSourceAdapter::ReadHeader(TUint32& aAudioLength, TUint32& aAudioType, + TUint8& aFramesPerSample, TUint32& aTimeScale, TUint32& aAverateBitRate) + { + TInt err = MP4ParseRequestAudioDescription(iMP4Handle, &aAudioLength, &aAudioType, &aFramesPerSample, &aTimeScale, &aAverateBitRate); + DP6(_L("C3gpDataSourceAdapter::ReadHeader stat[%d] aAudioLength[%d], aAudioType[%d], aFramesPerSample[%d], aTimeScale[%d], aAverateBitRate[%d]"), + err, aAudioLength, aAudioType, aFramesPerSample, aTimeScale, aAverateBitRate); + iAudioType = aAudioType; + return(TranslateMP4Err(err)); + } + +EXPORT_C TInt C3gpDataSourceAdapter::ReadAudioSpecificConfig(TUint8* aDecSpecInfo, TUint32 aDecSpecInfoSizeIn, TUint32* aDecSpecInfoSizeOut) + { + TInt err = KErrNone; + MP4Err stat = MP4ParseReadAudioDecoderSpecificInfo(iMP4Handle, aDecSpecInfo, aDecSpecInfoSizeIn, aDecSpecInfoSizeOut); + if ((stat == MP4_BUFFER_TOO_SMALL) && (aDecSpecInfo == NULL)) // This is valid Error as we are just getting the buffersize + { + err = KErrNone; + } + else + { + err = TranslateMP4Err(stat); + } + DP2(_L("C3gpDataSourceAdapter::ReadAudioSpecificConfig info[0x%x] err[%d]"), aDecSpecInfo, err); + return err; + } + +// ----------------------------------------------------------------------------- +// Local +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::PrepareMP4ParserL() + { + DP0(_L("C3gpDataSourceAdapter::PrepareMP4ParserL")); + + MP4Err err = MP4_ERROR; + + if (iCafHandle) + { + // SourceStopL might terminate the access to the File, SourcePrimeL to regain access + err = MP4ParseOpenCAF(&iMP4Handle, iCafHandle); + DP1(_L("C3gpDataSourceAdapter::PrepareMP4ParserL, MP4ParseOpenCAF err = %d"), err); + User::LeaveIfError(TranslateMP4Err(err)); + } + else if (iSourceType == KUidMmfDescriptorSource) // KUidMmfDescriptorSource + { + err = MP4ParseOpen(&iMP4Handle, NULL); + User::LeaveIfError(TranslateMP4Err(err)); + + CMMFClip* clip = static_cast(iDataSource); + + TBool endOfFile = EFalse; + iSourceReadPosition = 0; + TUint8* buffer = const_cast(iSrcBuf->Data().Ptr()); + while (!endOfFile) + { + clip->ReadBufferL(iSrcBuf, iSourceReadPosition); + TUint buffersize = iSrcBuf->Data().Length(); + + if (buffersize > 0) + { + err = MP4ParseWriteData(iMP4Handle, buffer, buffersize); + DP1(_L("C3gpDataSourceAdapter::PrepareMP4ParserL, write desc buffer to parser stat[%d]"), err); + User::LeaveIfError(TranslateMP4Err(err)); + iSourceReadPosition += buffersize; + } + else + { + endOfFile = ETrue; + // This call with empty buffer indicates to the 3GP library that + // this is the last buffer. + iLastBufferWrittenToMp4Lib = ETrue; + err = MP4ParseWriteData(iMP4Handle, buffer, 0); + DP1(_L("C3gpDataSourceAdapter::PrepareMP4ParserL, write last desc buffer to parser stat[%d]"), err); + User::LeaveIfError(TranslateMP4Err(err)); + } + } + + clip->SourceStopL(); + } + else if (iReadMp4LibSync && (iSourceType != KOldProgDLSourceUid)) +// (iSourceType == KMmdsStreamingSourceUid) || (iSourceType == KMmdsProgDLSourceUid) || +// (iSourceType == KS60AudioStreamingSourceUid) || (iSourceType == KMmdsFileSourceUid) || +// (iSourceType == KMmdsDescriptorSourceUid)) + { + err = MP4ParseOpen(&iMP4Handle, NULL); + User::LeaveIfError(TranslateMP4Err(err)); + DP1(_L("C3gpDataSourceAdapter::PrepareMP4ParserL, iMMDataSource->FillBuffer buffer[%x]"), iSrcBuf->Data().Ptr()); + iSrcBuf->SetPosition(0); + iSrcBuf->Data().SetLength(0); + iMMDataSource->FillBuffer(iSrcBuf); + } + else if (iSourceType == KOldProgDLSourceUid) + { + err = MP4ParseOpen(&iMP4Handle, NULL); + User::LeaveIfError(TranslateMP4Err(err)); + + iSourceReadPosition = 0; + StartReadingSourceL(); + } + else + { + User::Leave(KErrNotSupported); + } + + // MP4ParseRequestAudioDescription() is used here to initialize the parser internally + // before other parser functions can be used. + // The data gathered here is not used and the function may return an error in some cases. + // mp4_u32 audioLength, audioType, timeScale, averateBitRate; + mp4_u32 audioLength, timeScale, averateBitRate; + mp4_u8 framesPerSample; + err = MP4ParseRequestAudioDescription(iMP4Handle, &audioLength, &iAudioType, &framesPerSample, &timeScale, &averateBitRate); + if (err == MP4_OK) + { // mmf descriptor source or a short file would put complete content to the parser + // so this needs to be set here. + iMp4HeaderAvail = ETrue; + } + if /*( ((iSourceType == KOldProgDLSourceUid) || (iSourceType == KMmdsFileSourceUid) || + (iSourceType == KMmdsStreamingSourceUid) || (iSourceType == KMmdsProgDLSourceUid) || + (iSourceType == KS60AudioStreamingSourceUid) || (iSourceType == KMmdsDescriptorSourceUid)) &&*/ + ((err == MP4_NOT_AVAILABLE) || (err == MP4_FILE_ERROR)) //) + { + // do nothing + } + else + { + DP1(_L("C3gpDataSourceAdapter::PrepareMP4ParserL Leave, err = %d"), err); + User::LeaveIfError(TranslateMP4Err(err)); + } + } + + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::TranslateMP4Err +// ----------------------------------------------------------------------------- +// +TInt C3gpDataSourceAdapter::TranslateMP4Err( + MP4Err aError) + { + DP1(_L("C3gpDataSourceAdapter::TranslateMP4Err err = %d"), aError); + TInt err; + switch (aError) + { + case MP4_OK: + err = KErrNone; + break; + case MP4_OUT_OF_MEMORY: + err = KErrNoMemory; + break; + case MP4_NOT_AVAILABLE: // valid error for progressive download and streaming source + err = KErrNotReady; + break; + case MP4_FILE_ERROR: + err = KErrBadHandle; + break; + case MP4_INVALID_TYPE: + err = KErrNotSupported; + break; + case MP4_TIMESCALE_NOT_SET: + err = KErrNotReady; + break; + case MP4_NOT_STREAMABLE: + case MP4_NO_REQUESTED_FRAME: + case MP4_CANT_SEEK: + case MP4_INVALID_INPUT_STREAM: + case MP4_NO_FRAME: + err = KErrArgument; + break; + case MP4_ERROR: + case MP4_FILE_MODE: + case MP4_BUFFER_TOO_SMALL: + case MP4_END_OF_VIDEO: + case MP4_METADATA_ERROR: + case MP4_NO_VIDEO: + case MP4_NO_AUDIO: + err = KErrGeneral; + break; + default: + if (aError > 0) //For Any 3GPLib Errors + { + err = KErrGeneral; + } + else // For CAF Errors + { + err = aError; + } + + break; + } + + return err; + } + + +CMMFDataBuffer* C3gpDataSourceAdapter::CreateSourceBufferOfSizeL( + TUint aSize ) + { + CMMFDataBuffer* buffer = CMMFDataBuffer::NewL(aSize); + CleanupStack::PushL(buffer); + buffer->SetRequestSizeL(aSize); + buffer->SetPosition(0); + buffer->Data().SetLength(0); + CleanupStack::Pop(buffer); + return buffer; + } + + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::StartReadingSourceL +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::StartReadingSourceL() + { + DP1(_L("C3gpDataSourceAdapter::StartReadingSourceL, iSourceReadPosition = %d"), iSourceReadPosition); + + // kick off the asynchronous read from source +// iClip->SourcePrimeL(); +// iClip->SourceThreadLogon(*this); + iSrcBuf->SetPosition(0); + iSrcBuf->Data().SetLength(0); + iClip->ReadBufferL(iSrcBuf, iSourceReadPosition, this); + iContinueReading = ETrue; + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::ReadAsync +// ----------------------------------------------------------------------------- +// +TInt C3gpDataSourceAdapter::ReadAsync() + { + TUint8* bufPtr = const_cast(iParserBuf->Data().Ptr()); + mp4_u32 buffersize = iParserBuf->RequestSize(); + DP2(_L("C3gpDataSourceAdapter::ReadAsync ptr[%x] size[%d]"), bufPtr, buffersize); + MP4Err err = MP4_ERROR; + + if (iMP4Handle) + { + err = MP4ParseReadAudioFramesAsync(iMP4Handle, this, bufPtr, &buffersize); + } + return err; + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::ReadSyncL +// ----------------------------------------------------------------------------- +// +TInt C3gpDataSourceAdapter::ReadSyncL() + { + TInt err = MP4_ERROR; + CMMFDataBuffer* buffer = static_cast(iFillingBuffer); + TUint8* bufPtr = const_cast(buffer->Data().Ptr()) + iFillingBuffer->Position(); + TInt buffersize = iFillingBuffer->RequestSize() - iFillingBuffer->Position(); + DP4(_L("C3gpDataSourceAdapter::ReadSyncL, buffer[%x] length[%d] buffersize[%d] position[%d]"), + buffer->Data().Ptr(), buffer->Data().Length(), buffersize, iFillingBuffer->Position()); + + TInt bytesAdded = 0; + mp4_u32 framesize; + + while (ETrue) + { + if (iMp4HeaderAvail) + { // know audio type after header read + err = MP4ParseNextFrameSize(iMP4Handle, iAudioType, &framesize); + if (err != MP4_OK) + { // default in case not enough data + framesize = KMaxFrameSize; + err = MP4_OK; + } + } + else + { + framesize = KMaxFrameSize; + } + if (buffersize >= framesize) + { + mp4_u32 audiosize, timestamp, returnedframes, timestamp2; + if (iMp4HeaderAvail) + { + err = MP4ParseReadAudioFrames(iMP4Handle, bufPtr, buffersize, &audiosize, ×tamp, &returnedframes, ×tamp2); + DP4(_L("C3gpDataSourceAdapter::ReadSyncL, MP4ParseReadAudioFrames err[%d] timestamp[%d] size[%d] d0[%x]"), + err, timestamp, audiosize, bufPtr[0]); + mp4_u32 bytes; + TInt s = MP4ParseGetBufferedBytes(iMP4Handle, &bytes); + DP2(_L("C3gpDataSourceAdapter::ReadSyncL bufferedbytes[%x] stat[%d]"),bytes,s); +/* + TInt block,aNumber =2; + RHeap &heap = User::Heap(); + RDebug::Print(_L("### SB-Cont%d"), aNumber); + RDebug::Print(_L("### SB-Cont%d: Heap Base Address: [0x%x]"),aNumber, heap.Base()); + RDebug::Print(_L("### SB-Cont%d: Available Heap Memory [%6d]"),aNumber, heap.Available(block)); + RDebug::Print(_L("### SB-Cont%d: Largest block: [%6d]"),aNumber, block); + RDebug::Print(_L("### SB-Cont%d: Size: [%8d]"),aNumber, heap.Size()); + RDebug::Print(_L("### SB-Cont%d: Max length: [%8d]"),aNumber, heap.MaxLength()); +*/ + + } + else + { + err = MP4_NOT_AVAILABLE; + DP0(_L("C3gpDataSourceAdapter::ReadSyncL no read - header not available yet")); + } + + if (err == MP4_OK) + { +/* if (!((iSourceType == KMmfAudioStreamingSourceUid) || (iSourceType == KMmfAudioProgDLSourceUid) + || (iSourceType == KS60AudioStreamingSourceUid) || (iSourceType == KMmfFileSourceUid) || (iSourceType == KMmfDescriptorSourceUid))) // pay attention to the ! (not condition) + { + TUint32 timePositionInMilliSecs = I64LOW(iPlayWindowEndPosition.Int64()/1000); + + if ((iPlayWindowEndPosition != TTimeIntervalMicroSeconds(0)) && + (timestamp >= timePositionInMilliSecs)) + { + aBuffer->SetLastBuffer(ETrue); + break; + } + } +*/ + bufPtr += audiosize; + buffersize -= audiosize; + bytesAdded += audiosize; + } + else if ((err == MP4_NO_FRAME) || + ((err == MP4_NOT_AVAILABLE) && iLastBufferWrittenToMp4Lib)) + { // if the file is cut short, it might return not_available - so check for last buffer + iFillingBuffer->SetLastBuffer(ETrue); + break; + } + else if (err == MP4_NOT_AVAILABLE) + { // in case parser is totally out of data + TInt pos = buffer->Data().Length()+bytesAdded; + buffer->Data().SetLength(pos); // must set length first to accomodate position + iFillingBuffer->SetPosition(pos); + iRestartSyncRead = ETrue; + DP3(_L("C3gpDataSourceAdapter::ReadSyncL, MP4_NOT_AVAILABLE bytesAdded[%d] pos[%d] length[%d]"), + bytesAdded, iFillingBuffer->Position(), buffer->Data().Length()); + break; + } + } // if buffer large enough for read + else + { // if buffer too small for read + DP3(_L("C3gpDataSourceAdapter::ReadSyncL, buffersize[%d] too small for next frame[%d] err[%d] should be 0"), + buffersize, framesize, err); + break; + } + } // while ETrue keep filling buffer + if ((err == MP4_OK) || (iFillingBuffer->LastBuffer())) + { + iQueValid = ETrue; + buffer->Data().SetLength(buffer->Data().Length() + bytesAdded); + DP2(_L("C3gpDataSourceAdapter::ReadSyncL, sending buffer to controller iFillingBuffer[%x], Length[%d]"), + buffer->Data().Ptr(), buffer->Data().Length()); + iControllerMDataSink->BufferFilledL(iFillingBuffer); // setpos could come in here and clear the queue here and add another read + if (iQueValid) + { // this detects if the que has been cleared and refilled + // we don't want to do this with the new buffers in the queue + iQueuedAsyncBuffers.Remove(0); + if (iQueuedAsyncBuffers.Count() > 0) + { + DP0(_L("C3gpDataSourceAdapter::ReadSyncL calls FillBufferL")); + FillBufferL(iQueuedAsyncBuffers[0],this,iMediaId); + } + } + } + TInt status = TranslateMP4Err(err); + return status; + } + +void C3gpDataSourceAdapter::ResetVariables() + { + iRestartSyncRead = EFalse; + iLastBufferWrittenToMp4Lib = EFalse; + iMp4HeaderAvail = EFalse; + iQueuedAsyncBuffers.Reset(); + iQueValid = EFalse; + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer::CAsyncProxyFillBuffer +// ----------------------------------------------------------------------------- +// +C3gpDataSourceAdapter::CAsyncProxyFillBuffer::CAsyncProxyFillBuffer(C3gpDataSourceAdapter& a3gpDataSourceAdapter) : + CActive(EPriorityHigh), + i3gpDataSourceAdapter(a3gpDataSourceAdapter) + { + DP0(_L("C3gpDataSourceAdapter::CAsyncProxyFillBuffer::CAsyncProxyFillBuffer")); + CActiveScheduler::Add(this); + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer::~CAsyncProxyFillBuffer +// ----------------------------------------------------------------------------- +// +C3gpDataSourceAdapter::CAsyncProxyFillBuffer::~CAsyncProxyFillBuffer() + { + DP0(_L("C3gpDataSourceAdapter::CAsyncProxyFillBuffer::~CAsyncProxyFillBuffer")); + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer::GenerateCallback +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::CAsyncProxyFillBuffer::ReadSync() + { + DP0(_L("C3gpDataSourceAdapter::CAsyncProxyFillBuffer::ReadSync")); + iStatus = KRequestPending; // service request would be made here and pending set by service provider + SetActive(); + iRequestStatus = &iStatus; + User::RequestComplete(iRequestStatus, KErrNone); + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer::DoCancel +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::CAsyncProxyFillBuffer::DoCancel() + { + DP0(_L("C3gpDataSourceAdapter::CAsyncProxyFillBuffer::DoCancel")); + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer::RunL +// ----------------------------------------------------------------------------- +// +void C3gpDataSourceAdapter::CAsyncProxyFillBuffer::RunL() + { + DP0(_L("C3gpDataSourceAdapter::CAsyncProxyFillBuffer::RunL")); + i3gpDataSourceAdapter.ReadSyncL(); + } + +// ----------------------------------------------------------------------------- +// C3gpDataSourceAdapter::CAsyncProxyFillBuffer::RunError +// ----------------------------------------------------------------------------- +// +TInt C3gpDataSourceAdapter::CAsyncProxyFillBuffer::RunError(TInt aError) + { + if (aError) + { + DP1(_L("C3gpDataSourceAdapter::CAsyncProxyFillBuffer::RunError, aError = %d"), aError); + } + return KErrNone; + } + +// ========================== OTHER EXPORTED FUNCTIONS ========================= + +// End of File +