--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/audioeditorengine/codecs/mp3/src/ProcMP3InFileHandler.cpp Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,1463 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "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:
+* Ixonos Plc
+*
+* Description:
+*
+*/
+
+
+/*-- Project Headers. --*/
+#include "AudPanic.h"
+#include "ProcTools.h"
+#include "ProcMP3InFileHandler.h"
+#include "mpheader.h"
+#include "audconstants.h"
+
+
+#include "ProcMP3FrameHandler.h"
+
+// Debug print macro
+#if defined _DEBUG
+#include <e32svr.h>
+#define PRINT(x) RDebug::Print x;
+#else
+#define PRINT(x)
+#endif
+
+/*
+ Purpose: Minimum buffer size for determining the payload size
+ of a free format mp3 bitstream.
+ Explanation: - */
+#define MIN_MP3_FREE_FORMAT_BUF_SIZE (42)
+
+/*
+ Purpose: Buffer size for searching the start of a mp3 frame.
+ Explanation: - */
+const int16 Kmp3BufSize = 8;
+
+/*
+ Purpose: Buffer size for determining an avarage frame size of a mp3 stream.
+ Explanation: - */
+const int16 Kmp3BitrateRegions = 4;
+
+/*
+ Purpose: # of frames processed from each region.
+ Explanation: This is used when the avarage frame size is determined. */
+const int16 Kmp3BitrateNumFrames = 125;
+
+/*
+ Purpose: Buffer size for determining if a clip is valid mp3
+ Explanation: - */
+const TUint Kmp3TempBufferSize = 4096;
+
+// ID3v2 header's tag offset
+const TUint KSizeOfTagOffset = 6;
+
+// The size of MP3 header, header must include bits for determining frame length
+const TInt KRawMp3FrameHeaderSize = 5;
+
+// 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},
+ };
+
+const TInt KRawMp3MaxFrameSize = 1441; // 320kbit/s @ 32kHz = int((144*320000/32000)+1)
+
+CProcMP3InFileHandler* CProcMP3InFileHandler::NewL(const TDesC& aFileName, RFile* aFileHandle, CAudClip* aClip,
+ TInt aReadBufferSize, TInt aTargetSampleRate, TChannelMode aChannelMode)
+{
+ CProcMP3InFileHandler* self = NewLC(aFileName, aFileHandle, aClip, aReadBufferSize,
+ aTargetSampleRate, aChannelMode);
+ CleanupStack::Pop(self);
+
+ return self;
+}
+
+CProcMP3InFileHandler*
+CProcMP3InFileHandler::NewLC(const TDesC& aFileName, RFile* aFileHandle, CAudClip* aClip,
+ TInt aReadBufferSize, TInt aTargetSampleRate, TChannelMode aChannelMode)
+{
+ CProcMP3InFileHandler* self = new (ELeave) CProcMP3InFileHandler();
+ CleanupStack::PushL(self);
+ self->ConstructL(aFileName, aFileHandle, aClip, aReadBufferSize,
+ aTargetSampleRate, aChannelMode);
+
+ return self;
+}
+
+CProcMP3InFileHandler::CProcMP3InFileHandler() : CProcInFileHandler(), mp3FileFormat(0),
+ isValidMP3(0), mp3HeaderBytes(0),
+ mp3Log(0), isFreeFormatMP3(0), isVbrMP3(0)
+{
+}
+
+
+
+
+TBool CProcMP3InFileHandler::GetEncAudioFrameL(HBufC8*& aFrame, TInt& aSize, TInt32& aTime)
+ {
+ TBool rValue = EFalse;
+
+ if(!iFileOpen)
+ {
+ TAudPanic::Panic(TAudPanic::EInternal);
+ }
+
+ aSize = 0;
+ aTime = 0;
+ aFrame = NULL;
+
+ if(isValidMP3)
+ {
+ TMpFrameState frState;
+ int16 frameFound;
+ TInt bufSize;
+ TPtr8 mp3DataBuf(mp3HeaderBytes, Kmp3BufSize);
+
+ /*-- Search start of next frame. --*/
+
+ bufSize = BufferedFileRead((TDes8&) mp3DataBuf);
+ if(bufSize < Kmp3BufSize)
+ ZERO_MEMORY(mp3HeaderBytes + bufSize, Kmp3BufSize - bufSize);
+ frameFound = GetMP3Frame(mp3HeaderBytes, Kmp3BufSize, &frState, 0);
+
+ /*-- Frame found. --*/
+ if(frameFound == 0)
+ {
+ TInt fLen;
+
+ fLen = frState.frameBytes + frState.headerBytes;
+ fLen -= Kmp3BufSize - (frState.readBytes - frState.headerBytes);
+ if(fLen > 0)
+ {
+ TInt offset;
+ uint8 *audFrameOffsetPtr;
+ HBufC8 *audioFrame = HBufC8::NewL(frState.frameBytes + frState.headerBytes);
+
+ offset = frState.readBytes - frState.headerBytes;
+ mp3DataBuf.Set(mp3HeaderBytes + offset, Kmp3BufSize - offset, Kmp3BufSize - offset);
+
+ audioFrame->Des().Copy(((const TDesC8 &) mp3DataBuf));
+
+ audFrameOffsetPtr = (uint8 *) audioFrame->Des().Ptr();
+
+ TPtr8 audTmpPtr(audFrameOffsetPtr + Kmp3BufSize - offset, fLen, fLen);
+
+ bufSize = BufferedFileRead(audTmpPtr, fLen);
+
+ fLen = frState.frameBytes + frState.headerBytes;
+ audioFrame->Des().SetLength(fLen);
+
+ aFrame = audioFrame;
+ aSize = fLen;
+ aTime = iMp3Edit->GetFrameTime(mp3FileFormat);
+ iCurrentTimeMilliseconds += aTime;
+
+ TRAPD(err, ManipulateGainL(aFrame));
+
+ if (err != KErrNone)
+ {
+ // something went wrong with the gain manipulation
+ // continue by returning the original frame
+ }
+
+
+ rValue = ETrue;
+ }
+ }
+ }
+
+
+
+
+ return (rValue);
+ }
+
+
+
+CProcMP3InFileHandler::~CProcMP3InFileHandler()
+{
+// if(iFileOpen)
+ CloseFile();
+
+ if (iMp3Edit != 0)
+ {
+ delete iMp3Edit;
+ iMp3Edit = 0;
+ }
+
+ if (iFileName != 0)
+ {
+ delete iFileName;
+ iFileName = 0;
+ }
+
+ if (iReadBuffer != 0)
+ {
+ delete iReadBuffer;
+ iReadBuffer = 0;
+ }
+
+ if (mp3FileFormat != 0)
+ {
+ delete mp3FileFormat;
+ mp3FileFormat = 0;
+ }
+
+ if (mp3HeaderBytes != 0)
+ {
+ delete mp3HeaderBytes;
+ mp3HeaderBytes = 0;
+ }
+
+ if (iDecoder != 0)
+ {
+ delete iDecoder;
+ iDecoder = 0;
+ }
+
+ if (iFrameHandler != 0)
+ {
+ delete iFrameHandler;
+ iFrameHandler = 0;
+ }
+
+ if (iSilentFrame != 0)
+ {
+ delete iSilentFrame;
+ iSilentFrame = 0;
+ }
+}
+
+int16 CProcMP3InFileHandler::
+GetMP3Frame(uint8 *dataBytes, int16 bufSize, TMpFrameState *frState, uint8 syncStatus)
+{
+
+
+ int16 locateFrame;
+ int16 seekSyncStatus = 0;
+ TPtr8 mp3DataBuf(dataBytes, bufSize);
+
+ /*-- Search start of 1st frame. --*/
+ locateFrame = 0;
+ frState->totalReadBytes = 0;
+
+ while(locateFrame == 0)
+ {
+ if(syncStatus == 3)
+ seekSyncStatus = iMp3Edit->FreeMode(mp3FileFormat, dataBytes, bufSize,
+ &frState->readBytes, &frState->frameBytes,
+ &frState->headerBytes);
+ else
+ seekSyncStatus = iMp3Edit->SeekSync(mp3FileFormat, dataBytes, bufSize,
+ &frState->readBytes, &frState->frameBytes,
+ &frState->headerBytes, (uint8) syncStatus);
+
+ /*-- Start of 1st frame found. --*/
+ if(seekSyncStatus == 0 || seekSyncStatus == 3)
+ locateFrame = 1;
+
+ /*-- Update data buffer, start of 1st frame not found yet. --*/
+ else if(seekSyncStatus == 2)
+ {
+ if(frState->readBytes)
+ {
+ TInt tmpBufLen, tmp2;
+
+ /*-- New data bytes to be read into buffer. --*/
+ tmpBufLen = (int16) (bufSize - frState->readBytes);
+
+ /*-- Move data that is possibly left in the buffer. --*/
+ if(tmpBufLen) COPY_MEMORY(dataBytes, dataBytes + frState->readBytes, tmpBufLen);
+
+ /*-- Prepare to read. --*/
+ mp3DataBuf.Set(dataBytes + tmpBufLen, frState->readBytes, frState->readBytes);
+
+ /*-- Update buffer. --*/
+ tmp2 = BufferedFileRead((TDes8&) mp3DataBuf);
+ if(tmp2 < frState->readBytes)
+ ZERO_MEMORY(dataBytes + tmpBufLen + tmp2, frState->readBytes - tmp2);
+
+ frState->totalReadBytes += frState->readBytes;
+ }
+ }
+
+ /*-- Abort, start of 1st frame cannot be located. --*/
+ else locateFrame = 1;
+ }
+
+ return (seekSyncStatus);
+
+
+}
+
+void CProcMP3InFileHandler::
+ConstructL(const TDesC& aFileName, RFile* aFileHandle, CAudClip* aClip, TInt aReadBufferSize,
+ TInt aTargetSampleRate, TChannelMode aChannelMode)
+{
+
+
+ iTargetSampleRate = aTargetSampleRate;
+ iChannelMode = aChannelMode;
+
+
+ int16 locate1stFrame;
+ TMpFrameState frState;
+
+ isVbrMP3 = 0;
+ isValidMP3 = 0;
+ isFreeFormatMP3 = 0;
+
+ //-- Initialize file format handle. --
+ mp3FileFormat = (TMpTransportHandle *) new (ELeave) TMpTransportHandle[1];
+ ZERO_MEMORY(mp3FileFormat, sizeof(TMpTransportHandle));
+
+ //-- Buffer for header search. --
+ mp3HeaderBytes = new (ELeave) uint8[Kmp3BufSize];
+ ZERO_MEMORY(mp3HeaderBytes, Kmp3BufSize);
+
+ // -- Buffer for validity check --
+ HBufC8* vldBuffer = (HBufC8*) HBufC8::NewLC(Kmp3TempBufferSize);
+
+ iMp3Edit = CMp3Edit::NewL();
+
+ // Set the file format parameters to default values. Note that this function
+ // should be called only once; when searching the start of 1st frame.
+ //
+ iMp3Edit->InitTransport(mp3FileFormat);
+
+ iClip = aClip;
+
+ //-- Open file. --//
+ InitAndOpenFileL(aFileName, aFileHandle, aReadBufferSize);
+
+ TPtr8 mp3DataBuf(mp3HeaderBytes, Kmp3BufSize);
+
+ /*-- Read 1st bytes in. --*/
+ BufferedFileSetFilePos(0);
+ BufferedFileRead((TDes8&) mp3DataBuf);
+
+
+ // ----------------------------------------->
+
+ // Identify ID3v2 header:
+
+ // more info in http://www.id3.org/
+
+ TInt tagLen = 0;
+ if (mp3DataBuf.Left(3).Compare(_L8("ID3")) == 0)
+ {
+
+ const TInt KLenOffset = 6;
+
+ BufferedFileSetFilePos(KLenOffset);
+ BufferedFileRead((TDes8&) mp3DataBuf);
+
+ // ID3v2 tag found, calculate lenght:
+
+ const TInt K2Pow7 = 128;
+ const TInt K2Pow14 = 16384;
+ const TInt K2Pow21 = 2097152;
+
+ tagLen = K2Pow21 * mp3DataBuf[0] +
+ K2Pow14 * mp3DataBuf[1] +
+ K2Pow7 * mp3DataBuf[2] +
+ mp3DataBuf[3];
+
+
+ tagLen += 10; // include ID3v2 header
+
+ }
+
+ // <-----------------------------------------
+
+ BufferedFileSetFilePos(tagLen);
+
+ TPtr8 vldDes( vldBuffer->Des() );
+
+ TInt bytesRead = BufferedFileRead((TDes8&) vldDes);
+ vldDes.SetLength(bytesRead);
+
+ TBool result = Validate(vldDes);
+
+ CleanupStack::PopAndDestroy(vldBuffer);
+
+ if (!result)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ BufferedFileSetFilePos(tagLen);
+ bytesRead = BufferedFileRead((TDes8&) mp3DataBuf);
+
+ /*-- Search start of 1st frame. --*/
+ locate1stFrame = GetMP3Frame(mp3HeaderBytes, Kmp3BufSize, &frState, 1);
+
+ /*-- If free format, we must determine the payload size of the frames. --*/
+ if(locate1stFrame == 3)
+ {
+ int16 tmpBufLen;
+ uint8 tmpBuf[MIN_MP3_FREE_FORMAT_BUF_SIZE];
+
+ /*-- Switch to larger buffer. --*/
+ tmpBufLen = (int16) (Kmp3BufSize - frState.readBytes);
+ COPY_MEMORY(tmpBuf, mp3HeaderBytes + frState.readBytes, tmpBufLen);
+ if(frState.readBytes)
+ {
+ int16 tmpBufLen2;
+
+ tmpBufLen2 = (int16) (MIN_MP3_FREE_FORMAT_BUF_SIZE - tmpBufLen);
+ mp3DataBuf.Set(tmpBuf + tmpBufLen, tmpBufLen2, tmpBufLen2);
+ BufferedFileRead((TDes8&) mp3DataBuf);
+ }
+
+ /*-- Determine the payload size. --*/
+ locate1stFrame = GetMP3Frame(tmpBuf, MIN_MP3_FREE_FORMAT_BUF_SIZE, &frState, 3);
+
+ /*-- If payload size known, then go back to the start of 1st frame. --*/
+ if(locate1stFrame == 0)
+ {
+ isFreeFormatMP3 = 1;
+
+ BufferedFileSetFilePos(0);
+ mp3DataBuf.Set(mp3HeaderBytes, Kmp3BufSize, Kmp3BufSize);
+ BufferedFileRead((TDes8&) mp3DataBuf);
+
+ locate1stFrame = GetMP3Frame(mp3HeaderBytes, Kmp3BufSize, &frState, 0);
+ }
+ }
+
+ if(locate1stFrame == 0)
+ isValidMP3 = 1;
+
+ BufferedFileSetFilePos(0);
+
+ TAudFileProperties prop;
+ GetPropertiesL(&prop);
+
+ if (iProperties != 0)
+ {
+
+
+ // generate a header -------------->
+
+
+ TUint8 byte1 = 0xFF; // sync
+ TUint8 byte2 = 0xFB; // sync + V1,L3 (mp3), no CRC
+
+ TBuf8<8> byte3B;
+
+ switch (iProperties->iBitrate)
+ {
+
+ case (32000):
+ {
+ byte3B.Append(_L8("0001"));
+ break;
+ }
+ case (40000):
+ {
+ byte3B.Append(_L8("0010"));
+ break;
+ }
+ case (48000):
+ {
+ byte3B.Append(_L8("0011"));
+ break;
+ }
+ case (56000):
+ {
+ byte3B.Append(_L8("0100"));
+ break;
+ }
+ case (64000):
+ {
+ byte3B.Append(_L8("0101"));
+ break;
+ }
+ case (80000):
+ {
+ byte3B.Append(_L8("0110"));
+ break;
+ }
+ case (96000):
+ {
+ byte3B.Append(_L8("0111"));
+ break;
+ }
+ case (112000):
+ {
+ byte3B.Append(_L8("1000"));
+ break;
+ }
+ case (128000):
+ {
+ byte3B.Append(_L8("1001"));
+ break;
+ }
+ case (160000):
+ {
+ byte3B.Append(_L8("1010"));
+ break;
+ }
+ case (192000):
+ {
+ byte3B.Append(_L8("1011"));
+ break;
+ }
+ case (224000):
+ {
+ byte3B.Append(_L8("1100"));
+ break;
+ }
+ case (256000):
+ {
+ byte3B.Append(_L8("1101"));
+ break;
+ }
+ case (320000):
+ {
+ byte3B.Append(_L8("1110"));
+ break;
+ }
+ default:
+ {
+ if ( iProperties->iBitrateMode == EAudVariable )
+ {
+ // bitrate for silent frames in variable bitrate mode; use the lowest bitrate.
+ // However, mp3 is not an output format so this is not so relevant currently
+ byte3B.Append(_L8("0001"));
+
+ }
+ else
+ {
+
+ User::Leave(KErrGeneral);
+ }
+ break;
+
+ }
+
+ }
+
+ switch (iProperties->iSamplingRate)
+ {
+
+ case(44100):
+ {
+ byte3B.Append(_L8("00"));
+ break;
+ }
+ case(48000):
+ {
+ byte3B.Append(_L8("01"));
+ break;
+ }
+ case(32000):
+ {
+ byte3B.Append(_L8("10"));
+ break;
+ }
+ default:
+ {
+ User::Leave(KErrGeneral);
+ break;
+ }
+ }
+
+
+ byte3B.Append(_L8("00")); // padding + protection bits
+
+ TBuf8<8> byte4B;
+
+ switch (iProperties->iChannelMode)
+ {
+
+ case(EAudStereo):
+ {
+ byte4B.Append(_L8("00"));
+ break;
+ }
+ case(EAudDualChannel):
+ {
+ byte4B.Append(_L8("10"));
+ break;
+ }
+ case(EAudSingleChannel):
+ {
+ byte4B.Append(_L8("11"));
+ break;
+ }
+ default:
+ {
+ User::Leave(KErrGeneral);
+ break;
+ }
+ }
+
+
+ byte4B.Append(_L8("000")); // mode extension,
+ // not copyrighted,
+
+ if (iProperties->iOriginal)
+ {
+ byte4B.Append(_L8("100"));
+ }
+ else
+ {
+ byte4B.Append(_L8("000"));
+ }
+ //copy of original, no emphasis
+
+ TInt frameLength;
+ if ( iProperties->iBitrateMode == EAudVariable )
+ {
+ // Use the lowest bitrate for silent frames in variable bitrate mode.
+ // However, mp3 is not an output format so this is not so relevant currently
+ frameLength = (144*32000)/(iProperties->iSamplingRate);
+ }
+ else
+ {
+ frameLength = (144*iProperties->iBitrate)/(iProperties->iSamplingRate);
+ }
+
+ iSilentFrame = HBufC8::NewL(frameLength);
+
+ TUint byte3 = 0;
+ ProcTools::Bin2Dec(byte3B, byte3);
+
+ TUint byte4 = 0;
+ ProcTools::Bin2Dec(byte4B, byte4);
+
+ TPtr8 silentFramePtr(iSilentFrame->Des());
+
+ silentFramePtr.FillZ(frameLength);
+
+ silentFramePtr[0] = byte1;
+ silentFramePtr[1] = byte2;
+ silentFramePtr[2] = static_cast<TUint8>(byte3);
+ silentFramePtr[3] = static_cast<TUint8>(byte4);
+ iSilentFrameDuration = ProcTools::MilliSeconds(iProperties->iFrameDuration);
+
+ }
+
+ if (aClip != 0)
+ {
+ iCutInTime = ProcTools::MilliSeconds(aClip->CutInTime());
+
+ }
+
+ iDecoder = CProcDecoder::NewL();
+
+ iDecodingPossible = iDecoder->InitL(*iProperties, aTargetSampleRate, aChannelMode);
+
+ iFrameHandler = CProcMP3FrameHandler::NewL();
+
+
+ if (iClip != 0 && iClip->Normalizing())
+ {
+ SetNormalizingGainL(iFrameHandler);
+ }
+
+}
+
+TBool CProcMP3InFileHandler::Validate(TDes8& aDes)
+{
+
+ const TUint8* bufferPtr = aDes.Ptr();
+
+ TInt bufferSize = aDes.Length();
+
+ TInt scannedBuffer = 0;
+ TInt lenMetaData = 0;
+ TInt syncOffset = 0;
+ TInt bufferPosition = 0;
+
+ if (lenMetaData == 0)
+ {
+ syncOffset = 0;
+ lenMetaData = ID3HeaderLength(aDes, bufferPosition);
+ }
+
+ TInt bufferRemaining = bufferSize;
+
+ while (lenMetaData > 0)
+ {
+ if (lenMetaData >= bufferRemaining)
+ {
+ // this buffer contains all metadata
+ syncOffset += bufferRemaining;
+ lenMetaData -= bufferRemaining;
+ return KErrCorrupt;
+ }
+ else
+ {
+ syncOffset += lenMetaData;
+ scannedBuffer += lenMetaData;
+ // be sure to check for following id3 tags
+ bufferRemaining = bufferSize - scannedBuffer;
+ bufferPosition = scannedBuffer;
+ lenMetaData = ID3HeaderLength(aDes, bufferPosition);
+ }
+ }
+
+
+ TInt seekOffset = 0;
+ bufferPosition = scannedBuffer;
+
+ seekOffset = SeekSync(aDes, bufferPosition);
+
+ syncOffset += seekOffset; // offset to this point from content beginning
+ scannedBuffer += seekOffset; // offset to this point in this buffer
+
+ bufferPosition = scannedBuffer;
+
+ if (seekOffset == bufferSize)
+ {
+ return EFalse;
+ }
+
+ return ETrue;
+
+ }
+
+
+TInt CProcMP3InFileHandler::SeekSync(TDes8& aDes, TInt aBufPos)
+ {
+ const TUint bufStart = aBufPos;
+
+ TInt bufLen = aDes.Length();
+ const TUint8* buf = aDes.Ptr() + bufStart;
+ const TInt KMaxFrames = 3; // number of frames to check
+ const TInt KNotFound = bufLen; // sync not found position
+
+ TInt i = 0;
+ TInt syncPos = KNotFound;
+ TInt maxSeek = KMaxFrames;
+ TInt bitRate = 0;
+
+ const TUint8* endPtr = buf+bufLen-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 = bufLen;
+ 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, bitRate);
+
+ if (length == 0)
+ {
+ syncPos = KNotFound;
+ }
+
+ if ((length > 0) && (bitRate < 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 += (bufLen-1); // force an exit from while loop
+ }
+
+ }
+ buf++; bufLen--; i++;
+ }
+ return syncPos;
+ }
+
+TInt CProcMP3InFileHandler::FrameInfo(const TUint8* aBuf,TInt aBufLen,TInt& aBitRate)
+ {
+ TInt length = 0;
+ TUint temp;
+ TUint lTempVal;
+
+ TInt samplingRate = 0;
+ TInt id = 0;
+ TInt Padding = 0;
+
+ 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:
+ id = 2; // MPEG2.5
+ break;
+ case 1:
+ return length;
+ case 2:
+ id = 0; // MPEG 2
+ break;
+ case 3:
+ id = 1; // MPEG 1
+ break;
+ }
+
+ lTempVal = (temp >> 17) & 0x03;
+ if (lTempVal != 1)
+ {
+ return length;
+ }
+
+ lTempVal = (temp >> 12) & 0x0F;
+ aBitRate = cBitRateTable[id][lTempVal]*1000;
+
+ if (aBitRate == 0)
+ {
+ return length;
+ }
+
+ lTempVal = (temp >> 10) & 0x03;
+ if (lTempVal == 3)
+ {
+ return length;
+ }
+ else
+ {
+ samplingRate = cSamplingFrequencyTable[id][lTempVal];
+ }
+
+ Padding = (temp >> 9) & 0x01;
+
+ lTempVal = (temp >> 6) & 0x03;
+
+
+ if (lTempVal == 3)
+ {
+ }
+ else
+ {
+ }
+
+ if (aBitRate == -1)
+ {
+ // For free mode operation
+ length = KRawMp3MaxFrameSize;
+ }
+
+ if (samplingRate > 0 && aBitRate > 0)
+ {
+ length = (144*aBitRate)/samplingRate;
+
+ if (id != 1)
+ {
+ length >>= 1; /*for MPEG2 and MPEG2.5 */
+ }
+
+ if (Padding)
+ {
+ length++;
+ }
+ }
+ }
+ return length;
+ }
+
+
+TInt CProcMP3InFileHandler::ID3HeaderLength(TDes8& aDes, TInt aPosition)
+ {
+ TInt lenMetaData;
+ TUint offset = aPosition;
+
+ _LIT8 (KTagID3, "ID3");
+ TPtrC8 searchBuf;
+
+ // Set search buffer
+ searchBuf.Set(aDes);
+
+ const TUint8* ptr = aDes.Ptr();
+ TInt len = aDes.Length();
+ searchBuf.Set(ptr+offset, len-offset);
+
+ TInt startTagPos = searchBuf.Find (KTagID3);
+ if (startTagPos == KErrNotFound || startTagPos != 0)
+ {
+ lenMetaData = 0;
+ }
+ else
+ {
+ lenMetaData = searchBuf[KSizeOfTagOffset];
+ lenMetaData = ((lenMetaData << 8) | (searchBuf[KSizeOfTagOffset+1] << 1)) >> 1;
+ lenMetaData = ((lenMetaData << 8) | (searchBuf[KSizeOfTagOffset+2] << 1)) >> 1;
+ lenMetaData = ((lenMetaData << 8) | (searchBuf[KSizeOfTagOffset+3] << 1)) >> 1;
+ lenMetaData += 10;
+ }
+
+ return lenMetaData;
+ }
+
+
+int16
+CProcMP3InFileHandler::GetMP3Bitrate(void)
+{
+
+
+ TMpFrameState frState;
+ int16 bitRate, frameFound, offsetBytes;
+ TPtr8 mp3DataBuf(mp3HeaderBytes, Kmp3BufSize);
+
+ bitRate = 0;
+ isVbrMP3 = 0;
+
+ /*-- Search start of 1st frame. --*/
+ BufferedFileRead((TDes8&) mp3DataBuf);
+ frameFound = GetMP3Frame(mp3HeaderBytes, Kmp3BufSize, &frState, 0);
+
+ /*-- How many unknown bytes at the start of the file? --*/
+ offsetBytes = static_cast<int16>(frState.totalReadBytes + (frState.readBytes - frState.headerBytes));
+
+ /*-- Get bitrate information. --*/
+ if(frameFound == 0)
+ {
+ if(isFreeFormatMP3)
+ bitRate = iMp3Edit->EstimateBitrate(mp3FileFormat, 0);
+
+ /*
+ * Since the mp3 stream is not using free format, we must somehow
+ * determine the (average) bitrate. Yes, mp3 header includes
+ * information about the bitrate but that's valid only for
+ * the current frame. In case variable coding is used the bitrate
+ * can vary quite a lot depending on the goodness of the encoder
+ * and signal conditions. Also if the mp3 stream is already an edited
+ * version, the bitrate can change quite radicly between different portions
+ * of the file. At the moment we determine the avarage frame size by
+ * dividing the file into 'Kmp3BitrateRegions' regions of equal width
+ * and from each region we determine the average frame size. The 1st
+ * 'Kmp3BitrateNumFrames' frames are used from each region. The final
+ * average frame size is then averaged across each region.
+ * The reason why the bitrate estimation is so complicated is related
+ * to seeking. At the moment we jump to the desired position and in order
+ * to make this jump as accurate as possible we must have accurate information
+ * about the average frame size. The advantages of jumping is that it's fast,
+ * the side effect might be that we jump to incorrect position, the deviation
+ * is negligible with constant bitrate streams but with variable bitrate streams
+ * this can lead to quite large deviations, especially if the stream is using
+ * the full range of allowed bitrates. Fortunately, this is not the case in
+ * typical mp3 streams but after a series of editing we might have a
+ * file where bitrate changes are significant. Of course this means also that
+ * the quality is not so good either, so probably the user will never create
+ * such files due to poor sound quality...
+ *
+ * The other approach would be the loop each frame and store frame positions,
+ * let's say for every second. Works great, but the side effect is quite considerable
+ * delay, since it certainly takes some time to process 5000-10000 mp3 frames...
+ */
+ else
+ {
+ int32 fPosOffset[Kmp3BitrateRegions];
+ TInt fileSize, stepSize, nRegions, byteOffset;
+
+ if(iFile.Size(fileSize) == KErrNone)
+ {
+ uint8 idx;
+ int32 nFrames;
+ int16 prevBitRate;
+ TMPEG_Header *header;
+ TInt ProcessingOnGoing;
+
+ fileSize -= offsetBytes;
+ if(fileSize < 0)
+ return (0);
+
+ header = &mp3FileFormat->header;
+
+ /*-- Build the data region boundaries. --*/
+ nRegions = 1;
+ stepSize = fileSize / Kmp3BitrateRegions;
+ byteOffset = stepSize;
+ fPosOffset[0] = stepSize;
+ TInt i = 0;
+ for(i = 1; i < Kmp3BitrateRegions - 1; i++)
+ {
+ byteOffset += stepSize;
+ if(byteOffset < fileSize)
+ {
+ nRegions++;
+ fPosOffset[i] = byteOffset;
+ }
+ else break;
+ }
+
+ idx = 0;
+ nFrames = 0;
+ ProcessingOnGoing = 1;
+ mp3FileFormat->aveFrameLen = 0;
+
+ prevBitRate = bit_rate(header);
+
+ /*-- Process each data region and accumulate the frame size. --*/
+ while(ProcessingOnGoing)
+ {
+ TInt rValue, bufSize;
+
+ for(i = 0; i < Kmp3BitrateNumFrames; i++)
+ {
+ TInt fLen;
+
+ nFrames++;
+ fLen = static_cast<int16>(frState.frameBytes + frState.headerBytes);
+
+ frameFound = 2;
+ mp3FileFormat->aveFrameLen += fLen;
+
+ /*-- Check whether bitrate changed => variable bitrate. --*/
+ if(!isVbrMP3)
+ if(prevBitRate != bit_rate(header))
+ isVbrMP3 = 1;
+
+ /*
+ * Skip the payload, remember that the input buffer has 'Kmp3BufSize'
+ * bytes already that belong to the current mp3 frame. These bytes
+ * need to be compensated before jumping to the start of next frame.
+ */
+ fLen -= static_cast<int16>(Kmp3BufSize - (frState.readBytes - frState.headerBytes));
+ if(fLen < 0) fLen = 1;
+ rValue = BufferedFileSetFilePos(BufferedFileGetFilePos() + fLen);
+
+ if(rValue)
+ {
+ /*-- Read new data for parsing of next frame. --*/
+ bufSize = BufferedFileRead((TDes8&) mp3DataBuf);
+ if(bufSize < Kmp3BufSize)
+ ZERO_MEMORY(mp3HeaderBytes + bufSize, Kmp3BufSize - bufSize);
+
+ frameFound = GetMP3Frame(mp3HeaderBytes, Kmp3BufSize, &frState, 0);
+ }
+
+ if(frameFound != 0)
+ {
+ ProcessingOnGoing = 0;
+ break;
+ }
+ }
+
+ if(ProcessingOnGoing && idx < nRegions)
+ {
+ frameFound = 2;
+
+ /*-- Seek to start of next data region. --*/
+ rValue = BufferedFileSetFilePos(fPosOffset[idx++]);
+
+ if(rValue)
+ {
+ /*-- Read new data and search start of frame. --*/
+ bufSize = BufferedFileRead((TDes8&) mp3DataBuf);
+ if(bufSize < Kmp3BufSize)
+ ZERO_MEMORY(mp3HeaderBytes + bufSize, Kmp3BufSize - bufSize);
+
+ frameFound = GetMP3Frame(mp3HeaderBytes, Kmp3BufSize, &frState, 0);
+ }
+
+ if(frameFound != 0)
+ ProcessingOnGoing = 0;
+ }
+ else ProcessingOnGoing = 0;
+ }
+
+ if(frameFound != 0)
+ {
+ mp3FileFormat->execState.execMode = GLITCH_FREE;
+ mp3FileFormat->header.header = mp3FileFormat->headerOld.header;
+ }
+
+ /*-- Average frame length, in bytes. --*/
+ if(nFrames)
+ {
+ FLOAT tmp;
+
+ tmp = mp3FileFormat->aveFrameLen / (FLOAT) nFrames;
+ mp3FileFormat->aveFrameLen = (int16) (tmp + 0.5f);
+ }
+
+ /*-- This is our estimated bitrate. --*/
+ bitRate = iMp3Edit->EstimateBitrate(mp3FileFormat, 1);
+ }
+ }
+ }
+ return (bitRate);
+
+}
+
+void
+CProcMP3InFileHandler::GetPropertiesL(TAudFileProperties* aProperties)
+{
+ PRINT((_L("CProcMP3InFileHandler::GetPropertiesL in") ));
+
+
+ if (iProperties != 0)
+ {
+ *aProperties = *iProperties;
+ return;
+ }
+
+ if(iFileOpen)
+ {
+ TInt origFilePos = iFilePos;
+
+ aProperties->iFileFormat = EAudFormatUnrecognized;
+ aProperties->iAudioType = EAudTypeUnrecognized;
+ aProperties->iAudioTypeExtension = EAudExtensionTypeNoExtension;
+ aProperties->iBitrate = 0;
+ aProperties->iBitrateMode = EAudBitrateModeNotRecognized;
+ aProperties->iChannelMode = EAudChannelModeNotRecognized;
+ aProperties->iDuration = 0;
+ aProperties->iSamplingRate = 0;
+ aProperties->iFrameLen = 0;
+ aProperties->iFrameCount = 0;
+
+ /*-- First mp3 frame found? --*/
+ if(isValidMP3)
+ {
+ TMPEG_Header *header;
+
+ header = &mp3FileFormat->header;
+
+ /*-- Seek to start of file. --*/
+ BufferedFileSetFilePos(0);
+
+
+
+ if (version(header) != 1)
+ {
+ PRINT((_L("CProcMP4InFileHandler::GetPropertiesL header unsupported, leaving") ));
+ User::Leave(KErrNotSupported);
+ return;
+ }
+
+
+ /*-- Determine bitrate. --*/
+ aProperties->iBitrate = GetMP3Bitrate();
+
+
+ if(aProperties->iBitrate)
+ {
+ TInt fileSize;
+
+ iFile.Size(fileSize);
+
+ aProperties->iAudioType = EAudMP3;
+ aProperties->iFileFormat = EAudFormatMP3;
+ aProperties->iBitrateMode = (!isVbrMP3) ? EAudConstant : EAudVariable;
+
+ /*-- Determine channel mode. --*/
+ switch(mode(header))
+ {
+ case 0:
+ case 1:
+ aProperties->iChannelMode = EAudStereo;
+ break;
+
+ case 2:
+ aProperties->iChannelMode = EAudDualChannel;
+ break;
+
+ case 3:
+ default:
+ aProperties->iChannelMode = EAudSingleChannel;
+ break;
+ }
+
+ /*-- Estimate duration. --*/
+ TInt64 tmp = (TInt64)iMp3Edit->FileLengthInMs(mp3FileFormat, fileSize) * 1000;
+ TTimeIntervalMicroSeconds durationMicro(tmp);
+ aProperties->iDuration = durationMicro;
+
+ aProperties->iSamplingRate = frequency(header);
+
+ // Check that the sample rate is supported
+ if( (aProperties->iSamplingRate != KAedSampleRate8kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate11kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate16kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate22kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate24kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate32kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate44kHz) &&
+ (aProperties->iSamplingRate != KAedSampleRate48kHz) )
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ aProperties->iFrameLen = mp3FileFormat->aveFrameLen;
+
+ // casting for PC-Lint
+ tmp = (TInt64) (TInt)(iMp3Edit->GetFrameTime(mp3FileFormat) * 1000);
+ aProperties->iFrameDuration = tmp;
+ aProperties->iFrameCount = ProcTools::GetTInt((aProperties->iDuration).Int64()/(aProperties->iFrameDuration).Int64());
+
+ if (((TUint32)header->header & 0x4) != 0)
+ {
+
+ aProperties->iOriginal = ETrue;
+
+ }
+
+ BufferedFileSetFilePos(origFilePos);
+ }
+ }
+ else
+ {
+ PRINT((_L("CProcMP4InFileHandler::GetPropertiesL could not parse frames, leaving") ));
+ User::Leave(KErrNotSupported);
+ }
+ }
+ else
+ {
+ TAudPanic::Panic(TAudPanic::EInternal);
+ }
+
+ // bitrate is bytes not kilobytes
+ aProperties->iBitrate *= 1000;
+
+
+ if (iProperties == 0)
+ {
+ iProperties = new (ELeave) TAudFileProperties;
+ *iProperties = *aProperties;
+
+ }
+
+}
+
+TBool
+CProcMP3InFileHandler::SeekAudioFrame(TInt32 aTime)
+{
+ TBool rValue = EFalse;
+
+
+
+ if(!iFileOpen)
+ {
+ TAudPanic::Panic(TAudPanic::EInternal);
+ }
+
+ if(isValidMP3)
+ {
+ int32 fPos;
+
+ mp3FileFormat->aveFrameLen = iProperties->iFrameLen;
+ fPos = iMp3Edit->GetSeekOffset(mp3FileFormat, aTime);
+
+ BufferedFileSetFilePos(fPos);
+
+ iCurrentTimeMilliseconds = aTime;
+
+ rValue = ETrue;
+ }
+
+
+
+ return (rValue);
+}
+
+TBool
+CProcMP3InFileHandler::SeekCutInFrame()
+{
+ iCurrentTimeMilliseconds = iCutInTime;
+
+ return SeekAudioFrame(iCutInTime);
+}
+
+
+TBool
+CProcMP3InFileHandler::GetDurationL(TInt32& aTime, TInt& aFrameAmount)
+{
+ TBool rValue = EFalse;
+
+
+
+ if(!iFileOpen)
+ {
+ TAudPanic::Panic(TAudPanic::EInternal);
+ }
+
+ aTime = 0;
+ aFrameAmount = 0;
+
+ if(isValidMP3)
+ {
+ TInt filePos;
+ TAudFileProperties aProperties;
+
+ filePos = iFilePos;
+
+ GetPropertiesL(&aProperties);
+
+ if(aProperties.iBitrate)
+ {
+ rValue = ETrue;
+ aTime = ProcTools::MilliSeconds(aProperties.iDuration);
+ aFrameAmount = aTime / iMp3Edit->GetFrameTime(mp3FileFormat);
+ }
+
+ BufferedFileSetFilePos(filePos);
+ }
+
+
+ return (rValue);
+}
+
+
+TBool
+CProcMP3InFileHandler::SetNormalizingGainL(const CProcFrameHandler* aFrameHandler)
+{
+
+ HBufC8* point = 0;
+ TInt siz;
+ TInt32 tim = 0;
+ TInt maxGain = 0;
+ RArray<TInt> gains;
+ TInt maxAverage = 0;
+ TInt tmpGain = 0;
+ TInt gainCounter = 0;
+ TInt timeNow = 0;
+ TBitStream bs;
+
+ while(GetEncAudioFrameL(point, siz, tim))
+ {
+ timeNow += tim;
+ ((CProcMP3FrameHandler*) aFrameHandler)->GetMP3Gains(point, gains, maxGain, bs);
+
+ for (TInt a = 0 ; a < gains.Count() ; a = a+2)
+ {
+ tmpGain += gains[a];
+ gainCounter++;
+ }
+ gains.Reset();
+
+ if (timeNow > 1000)
+ {
+ if (tmpGain/gainCounter > maxAverage)
+ {
+ maxAverage = tmpGain/gainCounter;
+ }
+
+ timeNow = 0;
+ tmpGain = 0;
+ gainCounter = 0;
+ }
+
+ delete point;
+
+ }
+
+ // bigger value makes normalizing more efficient, but makes
+ // dynamic compression more likely to occur
+ TInt NormalizingFactor = 179;
+ if (iProperties->iBitrate > 20000 && iProperties->iBitrate < 40000)
+ {
+
+ // 32 kBit/s
+ NormalizingFactor = 187;
+
+ }
+ else if (iProperties->iBitrate > 40000 && iProperties->iBitrate < 80000)
+ {
+ // 64 kBit/s
+ NormalizingFactor = 181;
+
+ }
+
+
+ else if (iProperties->iBitrate > 80000 && iProperties->iBitrate < 140000)
+ {
+ // 128 kBit/s
+ if (iProperties->iChannelMode == EAudSingleChannel)
+ NormalizingFactor = 170;
+ else
+ NormalizingFactor = 179;
+
+ }
+ else if (iProperties->iBitrate > 140000)
+ {
+ // 256 kBit/s
+ if (iProperties->iChannelMode == EAudSingleChannel)
+ NormalizingFactor = 155;
+ else
+ NormalizingFactor = 167;
+
+ }
+ else
+ {
+
+ if (iProperties->iChannelMode == EAudSingleChannel)
+ NormalizingFactor = 170;
+
+ }
+
+
+ TInt gainBoost = (NormalizingFactor-maxAverage)*3;
+
+ if (gainBoost < 0) gainBoost = 0;
+
+ iNormalizingMargin = static_cast<TInt8>(gainBoost);
+
+ SeekAudioFrame(0);
+
+ mp3FileFormat->execState.a0_s16[0] = 0;
+ mp3FileFormat->execState.a0_s16[1] = 0;
+ mp3FileFormat->execState.a0_s16[2] = 0;
+
+ mp3FileFormat->execState.a0_u32[0] = 0;
+ mp3FileFormat->execState.a0_u32[1] = 0;
+ mp3FileFormat->execState.a0_u32[2] = 0;
+
+
+
+
+ return ETrue;
+
+
+}
+
+