sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "mmfwavformat.h" sl@0: sl@0: #include "WavDecodeUtility.h" sl@0: sl@0: sl@0: CWavDecodeUtility::CWavDecodeUtility() sl@0: { sl@0: } sl@0: sl@0: void CWavDecodeUtility::ConstructL(TDesC8& aBuffer) sl@0: { sl@0: iBuffer = &aBuffer; sl@0: FindRiffChunksL(); sl@0: ProcessFormatHeaderL(); sl@0: } sl@0: sl@0: CWavDecodeUtility* CWavDecodeUtility::NewL(TDesC8& aBuffer) sl@0: { sl@0: CWavDecodeUtility* self = new (ELeave) CWavDecodeUtility(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aBuffer); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: CWavDecodeUtility::~CWavDecodeUtility() sl@0: { sl@0: } sl@0: sl@0: TUint16 CWavDecodeUtility::Read16(const TUint8* aPtr) sl@0: sl@0: { sl@0: TUint16 ret = *(REINTERPRET_CAST(const TUint16*, aPtr)); sl@0: return ret; sl@0: } sl@0: sl@0: TUint32 CWavDecodeUtility::Read32(const TUint8* aPtr) sl@0: { sl@0: TUint32 x = *aPtr++; sl@0: x |= *aPtr++ << 8; sl@0: x |= *aPtr++ << 16; sl@0: x |= *aPtr++ << 24; sl@0: return x; sl@0: } sl@0: void CWavDecodeUtility::AssignChunkTo(TMdaRiffChunk* aAssignedChunk) sl@0: { sl@0: Mem::Copy(REINTERPRET_CAST(TUint8*, aAssignedChunk), REINTERPRET_CAST(TUint8*, &iCurrent),sizeof(TMdaRiffChunk)); sl@0: aAssignedChunk->iFound=ETrue; sl@0: } sl@0: sl@0: void CWavDecodeUtility::ReadChunk(TMdaRiffChunk* aChunk) sl@0: { sl@0: Mem::FillZ(REINTERPRET_CAST(TUint8*, aChunk),sizeof(TMdaRiffChunk)); // Zero data sl@0: aChunk->iPosition=iPos + KRiffChunkHeaderLength; sl@0: aChunk->iName = Read32(iStartPtr + iPos - iLastReadPosition); sl@0: aChunk->iLength = Read32(iStartPtr + iPos - iLastReadPosition + KRiffChunkDataLength); sl@0: } sl@0: void CWavDecodeUtility::FindRiffChunksL() sl@0: { sl@0: if (!iFoundChunks) sl@0: { sl@0: iFoundChunks=ETrue; sl@0: // iStartPtr=iBuffer->Data().Ptr(); sl@0: iStartPtr=iBuffer->Ptr(); sl@0: iPos=0; sl@0: iLastReadPosition=0;//Set by CBase, but what the heck sl@0: iDone=EFalse; sl@0: } sl@0: else sl@0: {//We've done another read. If there's < chunk in the buffer then something's wrong sl@0: if (iBuffer->Length() < STATIC_CAST(TInt, KRiffChunkHeaderLength)) sl@0: { sl@0: if ((iFormatChunk.iFound) && (iDataChunk.iFound)) sl@0: { sl@0: iDone = ETrue; //it should be ok to exit loop sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: } sl@0: } sl@0: sl@0: while (!iDone) sl@0: { sl@0: TInt advance=0; sl@0: sl@0: ReadChunk(&iCurrent); sl@0: sl@0: if (iCurrent.iName == KRiffChunkNameRiff)//we need to look INSIDE the RIFF chunk sl@0: { sl@0: if(iBuffer->Length() < STATIC_CAST(TInt, KRiffContainerChunkHeaderLength)) sl@0: User::Leave(KErrCorrupt); sl@0: iRiffChunkLength=iCurrent.iLength + KRiffChunkHeaderLength; sl@0: advance=KRiffContainerChunkHeaderLength; sl@0: } sl@0: else sl@0: { sl@0: advance=iCurrent.iLength + KRiffChunkHeaderLength; //... and skip all others sl@0: } sl@0: sl@0: if (iCurrent.iName == KRiffChunkNameFmt_) sl@0: AssignChunkTo(&iFormatChunk); sl@0: sl@0: else if (iCurrent.iName == KRiffChunkNameFact) sl@0: AssignChunkTo(&iFactChunk); sl@0: sl@0: else if (iCurrent.iName == KRiffChunkNameData) sl@0: AssignChunkTo(&iDataChunk); sl@0: sl@0: if (iDataChunk.iFound && iFormatChunk.iFound && iFactChunk.iFound) sl@0: { sl@0: iDone=ETrue; sl@0: } sl@0: else sl@0: {//still have chunks to look for sl@0: iPos+=advance; sl@0: if (iPos & 1) sl@0: iPos++; sl@0: sl@0: if ((TUint)iPos>=(TUint)iRiffChunkLength) sl@0: { sl@0: iDone=ETrue;//end of file sl@0: iClipLength = iRiffChunkLength; sl@0: } sl@0: else sl@0: {//make sure we have at least a chunk's worth left in the buffer sl@0: if ((TUint)(iPos-iLastReadPosition) > sl@0: (TUint)(iBuffer->Length() -KRiffChunkHeaderLength)) sl@0: { sl@0: iLastReadPosition=iPos; sl@0: //DoReadL(iLastReadPosition); sl@0: return; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: iClipLength = iRiffChunkLength; sl@0: if (iClipLength == 0) User::Leave(KErrNotFound); sl@0: else if (!(iDataChunk.iFound && iFormatChunk.iFound)) sl@0: User::Leave(KErrCorrupt); sl@0: sl@0: } sl@0: sl@0: void CWavDecodeUtility::ProcessFormatHeaderL() sl@0: { sl@0: TMdaRiffChunk* chunk = &iFormatChunk; sl@0: sl@0: if (!chunk) sl@0: User::Leave(KErrCorrupt); sl@0: sl@0: iLastReadPosition = chunk->iPosition; // Should be beginning of fmt block sl@0: //DoReadL(iLastReadPosition); sl@0: sl@0: // Set the real format sl@0: const TUint8* rawform = iBuffer->Ptr() + iLastReadPosition; //skip _fmt & length sl@0: iCodecId = Read16(rawform); rawform+=2; sl@0: iChannels = Read16(rawform); rawform+=2; sl@0: if ((iChannels != 1)&&(iChannels != 2)) //only 1 or 2 channels allowed sl@0: User::Leave(KErrCorrupt); sl@0: sl@0: iSampleRate = Read32(rawform); rawform+=4; // Skip bytes per second estimate sl@0: if (!iSampleRate) User::Leave(KErrCorrupt); sl@0: sl@0: iAverageBytesPerSecond = Read32(rawform); rawform+=4; sl@0: iBlockAlign = Read16(rawform); rawform+=2; sl@0: sl@0: iBitsPerSample = Read16(rawform); sl@0: rawform+=2; sl@0: sl@0: switch (iCodecId) sl@0: { sl@0: case KMMFWavFormatTypePcm: sl@0: { sl@0: } sl@0: break; sl@0: case KMMFWavFormatTypeImaAdpcm: sl@0: { sl@0: } sl@0: break; sl@0: case KMMFWavFormatTypeAlaw: sl@0: { sl@0: } sl@0: break; sl@0: case KMMFWavFormatTypeMulaw: sl@0: { sl@0: } sl@0: break; sl@0: case KMMFWavFormatTypeGSM610: sl@0: { sl@0: } sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: if (iCodecId == KMMFWavFormatTypeImaAdpcm) sl@0: { sl@0: TUint16 extraData = Read16(rawform); sl@0: if (extraData == 2) sl@0: { sl@0: rawform+=2; sl@0: iSamplesPerBlock = Read16(rawform); sl@0: rawform+=2; sl@0: } sl@0: } sl@0: sl@0: // Is there a fact chunk? sl@0: if (iFactChunk.iFound) sl@0: iHasFactChunk = ETrue; sl@0: sl@0: // Find the data block sl@0: chunk=&iDataChunk; sl@0: iStartPosition = chunk->iPosition; sl@0: iDataLength = chunk->iLength; sl@0: }