1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmlibs/mmfw/Recogniser/src/mp3parser.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,348 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +
1.20 +#include "parsers.h"
1.21 +
1.22 +//
1.23 +// Masks used for reading bits.
1.24 +//
1.25 +static const TInt KMP3Sync1Mask = 0xff; // 11111111
1.26 +static const TInt KMP3Sync2Mask = 0xe0; // 11100000
1.27 +static const TInt KMP3VersionMask = 0x18; // 00011000
1.28 +static const TInt KMP3LayerMask = 0x06; // 00000110
1.29 +static const TInt KMP3BitrateMask = 0xf0; // 11110000
1.30 +static const TInt KMP3SampleRateMask = 0x0c; // 00001100
1.31 +static const TInt KMP3PaddingMask = 0x02; // 00000010
1.32 +
1.33 +static const TInt KBitsPerByte = 8;
1.34 +
1.35 +//
1.36 +// Macros for retrieving the values.
1.37 +//
1.38 +#define MP3_GET_SYNC1(d) (d & KMP3Sync1Mask)
1.39 +#define MP3_GET_SYNC2(d) ((d & KMP3Sync2Mask) >> 5)
1.40 +#define MP3_GET_VERSION(d) ((d & KMP3VersionMask) >> 3)
1.41 +#define MP3_GET_LAYER(d) ((d & KMP3LayerMask) >> 1)
1.42 +#define MP3_GET_BITRATE(d) ((d & KMP3BitrateMask) >> 4)
1.43 +#define MP3_GET_SAMPLE_RATE(d) ((d & KMP3SampleRateMask) >> 2)
1.44 +#define MP3_GET_PADDING(d) ((d & KMP3PaddingMask) >> 1)
1.45 +
1.46 +
1.47 +//
1.48 +// Macros used for checking various bitfields.
1.49 +//
1.50 +#define IS_BAD_MP3_FRAME_SYNC1(s) ((s) != 0xff)
1.51 +#define IS_BAD_MP3_FRAME_SYNC2(s) ((s) != 0x07)
1.52 +#define IS_BAD_MP3_VERSION(v) ((v) < 0x02)
1.53 +#define IS_BAD_MP3_LAYER(l) ((l) == 0x00)
1.54 +#define IS_BAD_MP3_BITRATE(b) ((b) == 0x0f)
1.55 +#define IS_BAD_MP3_SAMPLE_RATE(s) ((s) == 0x03)
1.56 +
1.57 +
1.58 +//
1.59 +// Meanings of the 'Version' field.
1.60 +// --------------------------------
1.61 +// 00 - MPEG Version 2.5 (Unofficial standard. We don't support it.)
1.62 +// 01 - Reserved
1.63 +// 10 - MPEG Version 2
1.64 +// 11 - MPEG Version 1
1.65 +//
1.66 +static const TInt8 KMP3Version2 = 2;
1.67 +static const TInt8 KMP3Version1 = 3;
1.68 +
1.69 +
1.70 +//
1.71 +// Meanings of the 'Layer' field.
1.72 +// ------------------------------
1.73 +// 00 - Reserved
1.74 +// 01 - Layer III
1.75 +// 10 - Layer II
1.76 +// 11 - Layer I
1.77 +//
1.78 +
1.79 +static const TUint16 KBad = 0;
1.80 +static const TUint16 KFree = 0;
1.81 +
1.82 +//
1.83 +// MPEG Version 1 bitrates. Measured in kilobits per second.
1.84 +//
1.85 +static const TUint16 KBitrateVersion1[4][16] =
1.86 + {
1.87 + { KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad}, // Reserved layer
1.88 + {KFree, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, KBad}, // Layer III
1.89 + {KFree, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, KBad}, // Layer II
1.90 + {KFree, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, KBad} // Layer I
1.91 + };
1.92 +
1.93 +//
1.94 +// MPEG Version 2 bitrates. Measured in kilobits per second.
1.95 +//
1.96 +static const TUint16 KBitrateVersion2[4][16] =
1.97 + {
1.98 + { KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad}, // Reserved layer
1.99 + {KFree, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, KBad}, // Layer III
1.100 + {KFree, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, KBad}, // Layer II
1.101 + {KFree, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, KBad} // Layer I
1.102 + };
1.103 +
1.104 +//
1.105 +// Sample rates for the MPEG versions.
1.106 +//
1.107 +static const TUint16 KSampleRate[4][4] =
1.108 + {
1.109 + {11025, 12000, 8000, KBad}, // Version 2.5
1.110 + { KBad, KBad, KBad, KBad}, // Reserved
1.111 + {22050, 24000, 16000, KBad}, // Version 2
1.112 + {44100, 48000, 32000, KBad} // Version 1
1.113 + };
1.114 +
1.115 +//
1.116 +// Sample rates per frame for the MPEG layers.
1.117 +//
1.118 +static const TUint16 KSamplesPerFrame[4][4] =
1.119 + {
1.120 + {KBad, KBad, KBad, KBad}, // Reserved layer
1.121 + { 576, KBad, 576, 1152}, // Layer III
1.122 + {1152, KBad, 1152, 1152}, // Layer II
1.123 + { 384, KBad, 384, 384} // Layer I
1.124 + };
1.125 +
1.126 +//
1.127 +// The various states the recognition process goes through.
1.128 +//
1.129 +typedef enum
1.130 + {
1.131 + ESearchFrame1,
1.132 + ESearchFrame2
1.133 + }
1.134 +TMP3State;
1.135 +
1.136 +//
1.137 +// This truth table maps the following flags to a confidence level.
1.138 +// -----------------------------------------------------------------
1.139 +// A: Frame2 found.
1.140 +// B: Frame1 found.
1.141 +// C: Extension recognised.
1.142 +//
1.143 +// A B C -> Confidence
1.144 +// ===================
1.145 +// 0 0 0 -> ENotRecognized
1.146 +// 0 0 1 -> EPossible
1.147 +// 0 1 0 -> ENotRecognized
1.148 +// 0 1 1 -> ECertain
1.149 +// 1 0 0 -> EPossible
1.150 +// 1 0 1 -> EProbable
1.151 +// 1 1 0 -> EProbable
1.152 +// 1 1 1 -> ECertain
1.153 +//
1.154 +// In the case where two consecutive mp3 frames
1.155 +// are found, ECertain is automatically returned.
1.156 +//
1.157 +static const TInt KMP3FlagsToConfidence[8] =
1.158 + {
1.159 + KConfNotRecognised,
1.160 + KConfPossible,
1.161 + KConfNotRecognised,
1.162 + KConfCertain,
1.163 + KConfPossible,
1.164 + KConfProbable,
1.165 + KConfProbable,
1.166 + KConfCertain
1.167 + };
1.168 +
1.169 +#define KMP3ConfidenceMask 0x07 // 00000111
1.170 +#define KMP3Frame1Bit KBit1
1.171 +#define KMP3Frame2Bit KBit2
1.172 +
1.173 +//
1.174 +//
1.175 +//
1.176 +TMP3Parser::TMP3Parser(CReader& aReader, TFlags& aFlags)
1.177 + : iReader(aReader),
1.178 + iFlags(aFlags)
1.179 + {
1.180 + }
1.181 +
1.182 +
1.183 +//
1.184 +// MP3 recogition function.
1.185 +//
1.186 +void TMP3Parser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
1.187 + {
1.188 + TFlags flags;
1.189 +
1.190 + // Try to match the extension.
1.191 + if (aExt.MatchF(TPtrC(KExtMP3)) != KErrNotFound)
1.192 + {
1.193 + flags.SetExtensionFlag();
1.194 + }
1.195 +
1.196 + // Parse the data.
1.197 + TMP3Parser parser(aReader, flags);
1.198 + TRAP_IGNORE(parser.ParseL());
1.199 +
1.200 + TInt confIndex = flags.GetBitField(KMP3ConfidenceMask);
1.201 + aMatch.iConfidence = KMP3FlagsToConfidence[confIndex];
1.202 + if (aMatch.iConfidence != KConfNotRecognised)
1.203 + {
1.204 + aMatch.iMime = KMimeMP3;
1.205 + }
1.206 + }
1.207 +
1.208 +
1.209 +//
1.210 +// Attempts to parse an mp3 file.
1.211 +// First of all it checks if there is an ID3 metadata header
1.212 +// present at the current reader position. Then it checks for up to
1.213 +// two consecutive mp3 audio frames.
1.214 +//
1.215 +void TMP3Parser::ParseL()
1.216 + {
1.217 + TInt length;
1.218 + TMP3State state = ESearchFrame1;
1.219 +
1.220 + FOREVER
1.221 + {
1.222 + TID3Parser::ReadAndSkipID3L(iReader);
1.223 +
1.224 + TInt err = CheckForFrameHeaderL(length);
1.225 + if (err == KErrNotFound)
1.226 + {
1.227 + return;
1.228 + }
1.229 +
1.230 + switch (state)
1.231 + {
1.232 + case ESearchFrame1:
1.233 + iFlags.SetBit(KMP3Frame1Bit);
1.234 + state = ESearchFrame2;
1.235 + break;
1.236 +
1.237 + case ESearchFrame2:
1.238 + iFlags.SetBit(KMP3Frame2Bit);
1.239 + return;
1.240 + }
1.241 +
1.242 + // Skip over the audio frame.
1.243 + // This should be done after flags have been set.
1.244 + iReader.SeekL(length - KMP3FrameHeaderSize);
1.245 + }
1.246 + }
1.247 +
1.248 +
1.249 +//
1.250 +// Checks for an MP3 frame header at the current reader position.
1.251 +// If one is not found KErrNotFound is returned and aFrameLength
1.252 +// remains unchanged. If one is found KErrNone is retured and
1.253 +// aFrameLength is set to the length of the frame.
1.254 +//
1.255 +TInt TMP3Parser::CheckForFrameHeaderL(TInt& aFrameLength)
1.256 + {
1.257 + TBuf8<KMP3FrameHeaderSize> data;
1.258 + TUint8 versionIndex;
1.259 + TUint8 layerIndex;
1.260 + TUint8 bitrateIndex;
1.261 + TUint8 sampleRateIndex;
1.262 + TUint8 padding;
1.263 + TUint8 sync;
1.264 +
1.265 + data.SetLength(KMP3FrameHeaderSize);
1.266 + iReader.ReadBytesL(data);
1.267 +
1.268 + do
1.269 + {
1.270 + sync = MP3_GET_SYNC1(data[0]);
1.271 + if (IS_BAD_MP3_FRAME_SYNC1(sync))
1.272 + {
1.273 + break;
1.274 + }
1.275 +
1.276 + sync = MP3_GET_SYNC2(data[1]);
1.277 + if (IS_BAD_MP3_FRAME_SYNC2(sync))
1.278 + {
1.279 + break;
1.280 + }
1.281 +
1.282 + versionIndex = MP3_GET_VERSION(data[1]);
1.283 + if (IS_BAD_MP3_VERSION(versionIndex))
1.284 + {
1.285 + break;
1.286 + }
1.287 +
1.288 + layerIndex = MP3_GET_LAYER(data[1]);
1.289 + if (IS_BAD_MP3_LAYER(layerIndex))
1.290 + {
1.291 + break;
1.292 + }
1.293 +
1.294 + bitrateIndex = MP3_GET_BITRATE(data[2]);
1.295 + if (IS_BAD_MP3_BITRATE(bitrateIndex))
1.296 + {
1.297 + break;
1.298 + }
1.299 +
1.300 + sampleRateIndex = MP3_GET_SAMPLE_RATE(data[2]);
1.301 + if (IS_BAD_MP3_SAMPLE_RATE(sampleRateIndex))
1.302 + {
1.303 + break;
1.304 + }
1.305 +
1.306 + padding = MP3_GET_PADDING(data[2]);
1.307 +
1.308 + // All the data is valid.
1.309 + // Compute the audio data length.
1.310 + TUint32 bitRate = KBad;
1.311 + TUint16 sampleRate = KBad;
1.312 + TUint16 samplesPerFrame = KBad;
1.313 +
1.314 + if (versionIndex == KMP3Version1)
1.315 + {
1.316 + bitRate = KBitrateVersion1[layerIndex][bitrateIndex];
1.317 + }
1.318 + else if (versionIndex == KMP3Version2)
1.319 + {
1.320 + bitRate = KBitrateVersion2[layerIndex][bitrateIndex];
1.321 + }
1.322 + else
1.323 + {
1.324 + // Version 2.5 is not supported.
1.325 + break;
1.326 + }
1.327 +
1.328 + sampleRate = KSampleRate[versionIndex][sampleRateIndex];
1.329 + samplesPerFrame = KSamplesPerFrame[layerIndex][versionIndex];
1.330 +
1.331 + // Check we have valid values.
1.332 + if ((bitRate == KBad) || (sampleRate == KBad) || (samplesPerFrame == KBad))
1.333 + {
1.334 + break;
1.335 + }
1.336 +
1.337 + bitRate *= 1000; // Convert to kilobits.
1.338 + aFrameLength = (((samplesPerFrame / KBitsPerByte) * bitRate) / sampleRate) + padding;
1.339 + return KErrNone;
1.340 + }
1.341 + while (EFalse);
1.342 +
1.343 + // No valid frame header was found.
1.344 + aFrameLength = 0;
1.345 + iReader.SeekL(-KMP3FrameHeaderSize);
1.346 + return KErrNotFound;
1.347 + }
1.348 +
1.349 +
1.350 +
1.351 +