--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmfenh/advancedaudiocontroller/audiocontrollerpluginsvariant/AdvancedAudioControllerUtility/Src/MP3AudioControllerUtility.cpp Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,520 @@
+/*
+* 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 MP3 utility functions.
+*
+*/
+
+
+// INCLUDES
+#include "MP3AudioControllerUtility.h"
+#include "DebugMacros.h"
+#include <mmfdatabuffer.h>
+
+// CONSTANTS
+const TUint KFlagsOffset = 4;
+const TUint KFramesOffset = 8;
+
+// Bit rates in bits/sec supported by MPEG2, MPEG1 and MPEG2.5 respectively
+const TInt16 cBitRateTable[3][16] =
+ {
+ {-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},
+ {-1,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0},
+ {-1,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},
+ };
+
+// Sampling frequencies supported by MPEG2, MPEG1 and MPEG2.5 respectively
+const TUint16 cSamplingFrequencyTable[3][4] =
+ {
+ {22050,24000,16000,0},
+ {44100,48000,32000,0},
+ {11025,12000,8000,0},
+ };
+
+// Maximum MP3 frame size
+const TInt KRawMp3MaxFrameSize = 1441; // 320kbit/s @ 32kHz = int((144*320000/32000)+1)
+
+// The size of MP3 header, header must include bits for determining frame length
+const TInt KRawMp3FrameHeaderSize = 5;
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::CMP3AudioControllerUtility
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CMP3AudioControllerUtility::CMP3AudioControllerUtility()
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CMP3AudioControllerUtility::ConstructL()
+ {
+ DP0(_L("CMP3AudioControllerUtility::ConstructL"));
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CMP3AudioControllerUtility* CMP3AudioControllerUtility::NewL()
+ {
+ DP0(_L("CMP3AudioControllerUtility::NewL"));
+
+ CMP3AudioControllerUtility* self = new(ELeave) CMP3AudioControllerUtility;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// Destructor
+EXPORT_C CMP3AudioControllerUtility::~CMP3AudioControllerUtility()
+ {
+ iFramesArray.Close();
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::ScanHeaderL
+// Used to scan the header information
+// -----------------------------------------------------------------------------
+//
+void CMP3AudioControllerUtility::ScanHeaderL(
+ CMMFDataBuffer* aDataBuf)
+ {
+ DP0(_L("CMP3AudioControllerUtility::ScanHeaderL"));
+ iBitRateFrozen = EFalse;
+ const TUint8* bufferPtr = aDataBuf->Data().Ptr();
+ TInt bufferSize = aDataBuf->Data().Size();
+
+ TInt scannedBuffer = 0;
+
+ if (iLenMetaData == 0)
+ {
+ iSyncOffset = 0;
+ iLenMetaData = ID3HeaderLength(aDataBuf);
+ }
+
+ TInt bufferRemaining = bufferSize;
+
+ while (iLenMetaData > 0)
+ {
+ if (iLenMetaData >= bufferRemaining)
+ {
+ // this buffer contains all metadata
+ iSyncOffset += bufferRemaining;
+ iLenMetaData -= bufferRemaining;
+ User::Leave(KErrNotReady);
+ }
+ else
+ {
+ iSyncOffset += iLenMetaData;
+ scannedBuffer += iLenMetaData;
+ // be sure to check for following id3 tags
+ bufferRemaining = bufferSize - scannedBuffer;
+ aDataBuf->SetPosition(scannedBuffer);
+ iLenMetaData = ID3HeaderLength(aDataBuf);
+ }
+ }
+
+
+ TInt seekOffset = 0;
+ aDataBuf->SetPosition(scannedBuffer);
+ seekOffset = SeekSync(aDataBuf, bufferSize);
+
+ iSyncOffset += seekOffset; // offset to this point from content beginning
+ scannedBuffer += seekOffset; // offset to this point in this buffer
+ aDataBuf->SetPosition(scannedBuffer);
+
+ if (seekOffset == bufferSize)
+ {
+ User::Leave(KErrNotReady);
+ }
+
+ DP0(_L("CMP3AudioControllerUtility::ScanHeaderL - Calling FrameInfo"));
+
+ TAudioFrameInfo frameInfo;
+ TInt frameLen = FrameInfo(bufferPtr+scannedBuffer, bufferSize-scannedBuffer, frameInfo);
+
+ iHeaderOffset = 0;
+ iBitRate = 0;
+ iDurationUs = 0;
+
+ iSamplingRate = frameInfo.iSamplingRate;
+ iBitRate = frameInfo.iBitRate;
+ iSamplesPerFrame = frameInfo.iFrameSamples;
+ iChannels = frameInfo.iChannels;
+ iSamplingRateOut = frameInfo.iSamplingRateOut;
+ if (iSamplingRate > 0)
+ {
+ iFrameTimeMs = (iSamplesPerFrame*1000)/iSamplingRate;
+ }
+
+ TInt aNumFrames;
+ iFormatIsVBR = ParseFirstFrame(aDataBuf, &aNumFrames);
+ iNumFrames = aNumFrames;
+
+ TInt frameBytes = 0;
+ TInt avgFrameLen = 0;
+ TInt frames = 0;
+ // We could have used the bitrate found above for CBR MP3 content and not continue to average
+ // the bitrate. However, some users can manipulated the file and append other bitrate content.
+ // Since it is not too difficult, we can update the bitrate above with an averaged bitrate.
+ // If we want to only use the bitate above for cbr, we would set the bitrate frozen flag and
+ // on the condition that it's not iFormatIsVBR and the bitrate is non-zero.
+ for (TInt i=1; i<=100; i++)
+ {
+ if (scannedBuffer > bufferSize)
+ {
+ break;
+ }
+ frameLen = FrameInfo(bufferPtr+scannedBuffer, bufferSize-scannedBuffer, frameInfo);
+ scannedBuffer += frameLen;
+ if (frameLen <= 0)
+ {
+ break;
+ }
+ if (i == 10) // ignore the first 10 frames
+ {
+ frameBytes = frameLen;
+ frames = 1;
+ }
+ else
+ {
+ frameBytes += frameLen;
+ frames++;
+ }
+ avgFrameLen = frameBytes / frames; // frames is always non-zero here
+ }
+ iBitRate = (avgFrameLen * 8 * iSamplingRate) / iSamplesPerFrame;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::SeekSync
+// -----------------------------------------------------------------------------
+//
+TInt CMP3AudioControllerUtility::SeekSync(CMMFDataBuffer* aBuf, TInt aBufLen)
+ {
+ const TUint bufStart = aBuf->Position();
+ const TUint8* buf = aBuf->Data().Ptr() + bufStart;
+ const TInt KMaxFrames = 3; // number of frames to check
+ const TInt KNotFound = aBufLen; // sync not found position
+ TAudioFrameInfo frameInfo; // frame parameters
+ TInt i = 0;
+ TInt syncPos = KNotFound;
+ TInt maxSeek = KMaxFrames;
+ const TUint8* endPtr = buf+aBufLen-bufStart;
+
+ // Seek a valid frame candidate byte by byte until a valid frame
+ // is found or all bytes have been checked.
+ while (buf < endPtr && syncPos == KNotFound)
+ {
+ TInt seekCount = 0;
+ const TUint8* framePtr = buf;
+ TInt frameBufLen = aBufLen;
+ syncPos = i;
+
+ // Check the validity of this frame candidate and the nearest next
+ // frames. If they are not OK, syncPos will be set to KNotFound.
+ while (framePtr < endPtr && syncPos != KNotFound && seekCount < maxSeek)
+ {
+ TInt length = FrameInfo(framePtr, frameBufLen, frameInfo);
+
+ if (length == 0)
+ {
+ syncPos = KNotFound;
+ }
+ if ((length > 0) && (frameInfo.iBitRate < 0))
+ {
+ maxSeek = 1; // free formatcase
+ }
+ framePtr += length;
+ frameBufLen -= length;
+ seekCount++;
+
+ // consider SYNC not found if we reach end of buffer before finding 3 SYNC frames
+ if ((framePtr >= endPtr) && (seekCount < maxSeek))
+ {
+ syncPos = KNotFound;
+ buf += (aBufLen-1); // force an exit from while loop
+ }
+
+ }
+ buf++; aBufLen--; i++;
+ }
+ return syncPos;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::FrameInfo
+// -----------------------------------------------------------------------------
+//
+TInt CMP3AudioControllerUtility::FrameInfo(
+ const TUint8* aBuf,
+ TInt aBufLen,
+ TAudioFrameInfo& aInfo)
+ {
+ TInt length = 0;
+ TUint temp;
+ TUint lTempVal;
+
+ if (aBufLen >= KRawMp3FrameHeaderSize)
+ {
+ // Extract header fields to aInfo and check their bit syntax
+ // (including the sync word!). If the syntax is not OK the length
+ // is set to zero.
+
+ temp = 0;
+ temp = aBuf[0] << 24;
+ temp |= (aBuf[1] << 16);
+ temp |= (aBuf[2] << 8);
+ temp |= aBuf[3];
+ if (((temp >> 21) & 0x7FF) != 0x7FF)
+ {
+ return length;
+ }
+
+ lTempVal = (temp >> 19) & 0x03;
+ switch (lTempVal)
+ {
+ case 0:
+ aInfo.iId = 2; // MPEG2.5
+ aInfo.iFrameSamples = 576;
+ break;
+ case 1:
+ return length;
+ case 2:
+ aInfo.iId = 0; // MPEG 2
+ aInfo.iFrameSamples = 576;
+ break;
+ case 3:
+ aInfo.iId = 1; // MPEG 1
+ aInfo.iFrameSamples = 1152;
+ break;
+ }
+
+ lTempVal = (temp >> 17) & 0x03;
+ if (lTempVal != 1)
+ {
+ return length;
+ }
+
+ lTempVal = (temp >> 12) & 0x0F;
+ aInfo.iBitRate = cBitRateTable[aInfo.iId][lTempVal]*1000;
+
+ if (aInfo.iBitRate == 0)
+ {
+ return length;
+ }
+
+ lTempVal = (temp >> 10) & 0x03;
+ if (lTempVal == 3)
+ {
+ return length;
+ }
+ else
+ {
+ aInfo.iSamplingRate = cSamplingFrequencyTable[aInfo.iId][lTempVal];
+ }
+
+ aInfo.iPadding = (temp >> 9) & 0x01;
+
+ lTempVal = (temp >> 6) & 0x03;
+ aInfo.iMode = lTempVal;
+
+ if (lTempVal == 3)
+ {
+ aInfo.iChannels = 1;
+ }
+ else
+ {
+ aInfo.iChannels = 2;
+ }
+
+ aInfo.iSamplingRateOut = aInfo.iSamplingRate;
+// aInfo.iChannelsOut = 2; /* always set to stereo output */
+ aInfo.iChannelsOut = aInfo.iChannels;
+ aInfo.iFrameSamplesOut = aInfo.iFrameSamples;
+
+ if (aInfo.iBitRate == -1)
+ {
+ // For free mode operation
+ length = KRawMp3MaxFrameSize;
+ }
+
+ if (aInfo.iSamplingRate > 0 && aInfo.iBitRate > 0)
+ {
+ length = (144*aInfo.iBitRate)/aInfo.iSamplingRate;
+
+ if (aInfo.iId != 1)
+ {
+ length >>= 1; /*for MPEG2 and MPEG2.5 */
+ }
+
+ if (aInfo.iPadding)
+ {
+ length++;
+ }
+ }
+
+ aInfo.iFrameSize = length;
+ iChannelsOut = aInfo.iChannelsOut;
+ }
+ return length;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::SetCodecConfigData
+// -----------------------------------------------------------------------------
+//
+void CMP3AudioControllerUtility::SetCodecConfigData(
+ RArray<TInt>& aCodecConfig)
+ {
+// aCodecConfig[0] = 0; /*(iChannels == 2) ? 0 : 1*/; // don't have decoder downmix stereo to mono
+ // the sw codec always outputs 2 ch for mono and stereo,
+ // but for mono, we will downmix the 2ch to mono out
+ aCodecConfig[0] = (iChannels == 2) ? 0 : 1; // stereo to mono downmix
+ aCodecConfig[5] = iSamplingRate;
+ aCodecConfig[8] = iSamplesPerFrame;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::ParseFirstFrame
+// -----------------------------------------------------------------------------
+//
+TBool CMP3AudioControllerUtility::ParseFirstFrame(
+ const CMMFDataBuffer* aBuf,
+ TInt* aNumFrames)
+ {
+ _LIT8(KTagXing, "Xing");
+ _LIT8(KTagVBRI, "VBRI");
+
+// const TInt tocPresent = 0x00000001;
+// const TInt bytesPresent = 0x00000002;
+ const TInt framesPresent = 0x00000004;
+// const TInt qualityPresent = 0x00000008;
+
+ TBool firstFrameIsVBR = EFalse;
+
+ TPtrC8 searchBuf;
+ TInt numFrames = 0;
+
+ // Set search buffer
+// searchBuf.Set(aBuf->Data());
+ const TUint8* ptr = aBuf->Data().Ptr();
+ TInt pos = aBuf->Position();
+ TInt len = aBuf->Data().Size();
+ searchBuf.Set(ptr+pos, len-pos);
+
+ TInt startTagXing = searchBuf.Find (KTagXing);
+ TInt startTagVBRI = searchBuf.Find (KTagVBRI);
+
+
+ if (startTagXing != KErrNotFound)
+ {
+ TInt flags = searchBuf[startTagXing+KFlagsOffset];
+ flags = (flags << 8) | searchBuf[startTagXing+KFlagsOffset+1];
+ flags = (flags << 8) | searchBuf[startTagXing+KFlagsOffset+2];
+ flags = (flags << 8) | searchBuf[startTagXing+KFlagsOffset+3];
+ firstFrameIsVBR = ETrue;
+
+ if (flags & framesPresent)
+ {
+ numFrames = searchBuf[startTagXing+KFramesOffset];
+ numFrames = (numFrames << 8) | searchBuf[startTagXing+KFramesOffset+1];
+ numFrames = (numFrames << 8) | searchBuf[startTagXing+KFramesOffset+2];
+ numFrames = (numFrames << 8) | searchBuf[startTagXing+KFramesOffset+3];
+ }
+ }
+ else if (startTagVBRI != KErrNotFound)
+ {
+ numFrames = searchBuf[startTagVBRI+14];
+ numFrames = (numFrames << 8) | searchBuf[startTagVBRI+14+1];
+ numFrames = (numFrames << 8) | searchBuf[startTagVBRI+14+2];
+ numFrames = (numFrames << 8) | searchBuf[startTagVBRI+14+3];
+ firstFrameIsVBR = ETrue;
+ }
+ else
+ {
+ firstFrameIsVBR = EFalse;
+ }
+
+ *aNumFrames = numFrames;
+ return firstFrameIsVBR;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::FrameHeaderSize
+// Returns the Frame Header Size for the MP3 file.
+// -----------------------------------------------------------------------------
+//
+TInt CMP3AudioControllerUtility::FrameHeaderSize()
+ {
+ return KRawMp3FrameHeaderSize;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::Duration
+// -----------------------------------------------------------------------------
+//
+TInt64 CMP3AudioControllerUtility::Duration()
+ {
+ if (iFormatIsVBR && (iNumFrames > 0))
+ {
+ if (iSamplingRateOut > 0)
+ { // numframes may not be present
+ iDurationUs = ((TInt64)iSamplesPerFrame*(TInt64)iNumFrames*(TInt64)1000000)/iSamplingRateOut;
+ }
+ }
+ else
+ {
+ CAdvancedAudioUtility::Duration();
+ }
+ return iDurationUs;
+ }
+
+// -----------------------------------------------------------------------------
+// CMP3AudioControllerUtility::BitRate
+// -----------------------------------------------------------------------------
+//
+TInt CMP3AudioControllerUtility::BitRate()
+ {
+ if (iFormatIsVBR && (iNumFrames > 0))
+ {
+ Duration(); // for VBR bitrate depends on duration
+ TInt nonAudioBytes = iSyncOffset+iHeaderOffset;
+ TInt audioBytes = iClipSize - nonAudioBytes;
+ if (iDurationUs > 0)
+ {
+ iBitRate = 8*(((TInt64)audioBytes*(TInt64)1000000)/iDurationUs);
+ }
+ }
+ else
+ {
+ CAdvancedAudioUtility::BitRate();
+ }
+ return iBitRate;
+ }
+
+// ========================== OTHER EXPORTED FUNCTIONS =========================
+
+// End of File
+