--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/Recogniser/src/mp3parser.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,348 @@
+// 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 "parsers.h"
+
+//
+// Masks used for reading bits.
+//
+static const TInt KMP3Sync1Mask = 0xff; // 11111111
+static const TInt KMP3Sync2Mask = 0xe0; // 11100000
+static const TInt KMP3VersionMask = 0x18; // 00011000
+static const TInt KMP3LayerMask = 0x06; // 00000110
+static const TInt KMP3BitrateMask = 0xf0; // 11110000
+static const TInt KMP3SampleRateMask = 0x0c; // 00001100
+static const TInt KMP3PaddingMask = 0x02; // 00000010
+
+static const TInt KBitsPerByte = 8;
+
+//
+// Macros for retrieving the values.
+//
+#define MP3_GET_SYNC1(d) (d & KMP3Sync1Mask)
+#define MP3_GET_SYNC2(d) ((d & KMP3Sync2Mask) >> 5)
+#define MP3_GET_VERSION(d) ((d & KMP3VersionMask) >> 3)
+#define MP3_GET_LAYER(d) ((d & KMP3LayerMask) >> 1)
+#define MP3_GET_BITRATE(d) ((d & KMP3BitrateMask) >> 4)
+#define MP3_GET_SAMPLE_RATE(d) ((d & KMP3SampleRateMask) >> 2)
+#define MP3_GET_PADDING(d) ((d & KMP3PaddingMask) >> 1)
+
+
+//
+// Macros used for checking various bitfields.
+//
+#define IS_BAD_MP3_FRAME_SYNC1(s) ((s) != 0xff)
+#define IS_BAD_MP3_FRAME_SYNC2(s) ((s) != 0x07)
+#define IS_BAD_MP3_VERSION(v) ((v) < 0x02)
+#define IS_BAD_MP3_LAYER(l) ((l) == 0x00)
+#define IS_BAD_MP3_BITRATE(b) ((b) == 0x0f)
+#define IS_BAD_MP3_SAMPLE_RATE(s) ((s) == 0x03)
+
+
+//
+// Meanings of the 'Version' field.
+// --------------------------------
+// 00 - MPEG Version 2.5 (Unofficial standard. We don't support it.)
+// 01 - Reserved
+// 10 - MPEG Version 2
+// 11 - MPEG Version 1
+//
+static const TInt8 KMP3Version2 = 2;
+static const TInt8 KMP3Version1 = 3;
+
+
+//
+// Meanings of the 'Layer' field.
+// ------------------------------
+// 00 - Reserved
+// 01 - Layer III
+// 10 - Layer II
+// 11 - Layer I
+//
+
+static const TUint16 KBad = 0;
+static const TUint16 KFree = 0;
+
+//
+// MPEG Version 1 bitrates. Measured in kilobits per second.
+//
+static const TUint16 KBitrateVersion1[4][16] =
+ {
+ { KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad}, // Reserved layer
+ {KFree, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, KBad}, // Layer III
+ {KFree, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, KBad}, // Layer II
+ {KFree, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, KBad} // Layer I
+ };
+
+//
+// MPEG Version 2 bitrates. Measured in kilobits per second.
+//
+static const TUint16 KBitrateVersion2[4][16] =
+ {
+ { KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad}, // Reserved layer
+ {KFree, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, KBad}, // Layer III
+ {KFree, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, KBad}, // Layer II
+ {KFree, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, KBad} // Layer I
+ };
+
+//
+// Sample rates for the MPEG versions.
+//
+static const TUint16 KSampleRate[4][4] =
+ {
+ {11025, 12000, 8000, KBad}, // Version 2.5
+ { KBad, KBad, KBad, KBad}, // Reserved
+ {22050, 24000, 16000, KBad}, // Version 2
+ {44100, 48000, 32000, KBad} // Version 1
+ };
+
+//
+// Sample rates per frame for the MPEG layers.
+//
+static const TUint16 KSamplesPerFrame[4][4] =
+ {
+ {KBad, KBad, KBad, KBad}, // Reserved layer
+ { 576, KBad, 576, 1152}, // Layer III
+ {1152, KBad, 1152, 1152}, // Layer II
+ { 384, KBad, 384, 384} // Layer I
+ };
+
+//
+// The various states the recognition process goes through.
+//
+typedef enum
+ {
+ ESearchFrame1,
+ ESearchFrame2
+ }
+TMP3State;
+
+//
+// This truth table maps the following flags to a confidence level.
+// -----------------------------------------------------------------
+// A: Frame2 found.
+// B: Frame1 found.
+// C: Extension recognised.
+//
+// A B C -> Confidence
+// ===================
+// 0 0 0 -> ENotRecognized
+// 0 0 1 -> EPossible
+// 0 1 0 -> ENotRecognized
+// 0 1 1 -> ECertain
+// 1 0 0 -> EPossible
+// 1 0 1 -> EProbable
+// 1 1 0 -> EProbable
+// 1 1 1 -> ECertain
+//
+// In the case where two consecutive mp3 frames
+// are found, ECertain is automatically returned.
+//
+static const TInt KMP3FlagsToConfidence[8] =
+ {
+ KConfNotRecognised,
+ KConfPossible,
+ KConfNotRecognised,
+ KConfCertain,
+ KConfPossible,
+ KConfProbable,
+ KConfProbable,
+ KConfCertain
+ };
+
+#define KMP3ConfidenceMask 0x07 // 00000111
+#define KMP3Frame1Bit KBit1
+#define KMP3Frame2Bit KBit2
+
+//
+//
+//
+TMP3Parser::TMP3Parser(CReader& aReader, TFlags& aFlags)
+ : iReader(aReader),
+ iFlags(aFlags)
+ {
+ }
+
+
+//
+// MP3 recogition function.
+//
+void TMP3Parser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
+ {
+ TFlags flags;
+
+ // Try to match the extension.
+ if (aExt.MatchF(TPtrC(KExtMP3)) != KErrNotFound)
+ {
+ flags.SetExtensionFlag();
+ }
+
+ // Parse the data.
+ TMP3Parser parser(aReader, flags);
+ TRAP_IGNORE(parser.ParseL());
+
+ TInt confIndex = flags.GetBitField(KMP3ConfidenceMask);
+ aMatch.iConfidence = KMP3FlagsToConfidence[confIndex];
+ if (aMatch.iConfidence != KConfNotRecognised)
+ {
+ aMatch.iMime = KMimeMP3;
+ }
+ }
+
+
+//
+// Attempts to parse an mp3 file.
+// First of all it checks if there is an ID3 metadata header
+// present at the current reader position. Then it checks for up to
+// two consecutive mp3 audio frames.
+//
+void TMP3Parser::ParseL()
+ {
+ TInt length;
+ TMP3State state = ESearchFrame1;
+
+ FOREVER
+ {
+ TID3Parser::ReadAndSkipID3L(iReader);
+
+ TInt err = CheckForFrameHeaderL(length);
+ if (err == KErrNotFound)
+ {
+ return;
+ }
+
+ switch (state)
+ {
+ case ESearchFrame1:
+ iFlags.SetBit(KMP3Frame1Bit);
+ state = ESearchFrame2;
+ break;
+
+ case ESearchFrame2:
+ iFlags.SetBit(KMP3Frame2Bit);
+ return;
+ }
+
+ // Skip over the audio frame.
+ // This should be done after flags have been set.
+ iReader.SeekL(length - KMP3FrameHeaderSize);
+ }
+ }
+
+
+//
+// Checks for an MP3 frame header at the current reader position.
+// If one is not found KErrNotFound is returned and aFrameLength
+// remains unchanged. If one is found KErrNone is retured and
+// aFrameLength is set to the length of the frame.
+//
+TInt TMP3Parser::CheckForFrameHeaderL(TInt& aFrameLength)
+ {
+ TBuf8<KMP3FrameHeaderSize> data;
+ TUint8 versionIndex;
+ TUint8 layerIndex;
+ TUint8 bitrateIndex;
+ TUint8 sampleRateIndex;
+ TUint8 padding;
+ TUint8 sync;
+
+ data.SetLength(KMP3FrameHeaderSize);
+ iReader.ReadBytesL(data);
+
+ do
+ {
+ sync = MP3_GET_SYNC1(data[0]);
+ if (IS_BAD_MP3_FRAME_SYNC1(sync))
+ {
+ break;
+ }
+
+ sync = MP3_GET_SYNC2(data[1]);
+ if (IS_BAD_MP3_FRAME_SYNC2(sync))
+ {
+ break;
+ }
+
+ versionIndex = MP3_GET_VERSION(data[1]);
+ if (IS_BAD_MP3_VERSION(versionIndex))
+ {
+ break;
+ }
+
+ layerIndex = MP3_GET_LAYER(data[1]);
+ if (IS_BAD_MP3_LAYER(layerIndex))
+ {
+ break;
+ }
+
+ bitrateIndex = MP3_GET_BITRATE(data[2]);
+ if (IS_BAD_MP3_BITRATE(bitrateIndex))
+ {
+ break;
+ }
+
+ sampleRateIndex = MP3_GET_SAMPLE_RATE(data[2]);
+ if (IS_BAD_MP3_SAMPLE_RATE(sampleRateIndex))
+ {
+ break;
+ }
+
+ padding = MP3_GET_PADDING(data[2]);
+
+ // All the data is valid.
+ // Compute the audio data length.
+ TUint32 bitRate = KBad;
+ TUint16 sampleRate = KBad;
+ TUint16 samplesPerFrame = KBad;
+
+ if (versionIndex == KMP3Version1)
+ {
+ bitRate = KBitrateVersion1[layerIndex][bitrateIndex];
+ }
+ else if (versionIndex == KMP3Version2)
+ {
+ bitRate = KBitrateVersion2[layerIndex][bitrateIndex];
+ }
+ else
+ {
+ // Version 2.5 is not supported.
+ break;
+ }
+
+ sampleRate = KSampleRate[versionIndex][sampleRateIndex];
+ samplesPerFrame = KSamplesPerFrame[layerIndex][versionIndex];
+
+ // Check we have valid values.
+ if ((bitRate == KBad) || (sampleRate == KBad) || (samplesPerFrame == KBad))
+ {
+ break;
+ }
+
+ bitRate *= 1000; // Convert to kilobits.
+ aFrameLength = (((samplesPerFrame / KBitsPerByte) * bitRate) / sampleRate) + padding;
+ return KErrNone;
+ }
+ while (EFalse);
+
+ // No valid frame header was found.
+ aFrameLength = 0;
+ iReader.SeekL(-KMP3FrameHeaderSize);
+ return KErrNotFound;
+ }
+
+
+
+