os/mm/mmlibs/mmfw/Recogniser/src/mp3parser.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
sl@0
    17
#include "parsers.h"
sl@0
    18
sl@0
    19
//
sl@0
    20
// Masks used for reading bits.
sl@0
    21
//
sl@0
    22
static const TInt KMP3Sync1Mask = 0xff;			// 11111111
sl@0
    23
static const TInt KMP3Sync2Mask = 0xe0;			// 11100000
sl@0
    24
static const TInt KMP3VersionMask = 0x18;		// 00011000
sl@0
    25
static const TInt KMP3LayerMask = 0x06;			// 00000110
sl@0
    26
static const TInt KMP3BitrateMask = 0xf0;		// 11110000
sl@0
    27
static const TInt KMP3SampleRateMask = 0x0c;	// 00001100
sl@0
    28
static const TInt KMP3PaddingMask = 0x02;		// 00000010
sl@0
    29
sl@0
    30
static const TInt KBitsPerByte = 8;
sl@0
    31
sl@0
    32
//
sl@0
    33
// Macros for retrieving the values.
sl@0
    34
//
sl@0
    35
#define MP3_GET_SYNC1(d)				(d & KMP3Sync1Mask)
sl@0
    36
#define MP3_GET_SYNC2(d)				((d & KMP3Sync2Mask) >> 5)
sl@0
    37
#define MP3_GET_VERSION(d)				((d & KMP3VersionMask) >> 3)
sl@0
    38
#define MP3_GET_LAYER(d)				((d & KMP3LayerMask) >> 1)
sl@0
    39
#define MP3_GET_BITRATE(d)				((d & KMP3BitrateMask) >> 4)
sl@0
    40
#define MP3_GET_SAMPLE_RATE(d)			((d & KMP3SampleRateMask) >> 2)
sl@0
    41
#define MP3_GET_PADDING(d)				((d & KMP3PaddingMask) >> 1)
sl@0
    42
sl@0
    43
sl@0
    44
//
sl@0
    45
// Macros used for checking various bitfields.
sl@0
    46
//
sl@0
    47
#define IS_BAD_MP3_FRAME_SYNC1(s)		((s) != 0xff)
sl@0
    48
#define IS_BAD_MP3_FRAME_SYNC2(s)		((s) != 0x07)	
sl@0
    49
#define IS_BAD_MP3_VERSION(v)			((v) <  0x02)
sl@0
    50
#define IS_BAD_MP3_LAYER(l)				((l) == 0x00) 
sl@0
    51
#define IS_BAD_MP3_BITRATE(b)			((b) == 0x0f)	
sl@0
    52
#define IS_BAD_MP3_SAMPLE_RATE(s)		((s) == 0x03)
sl@0
    53
sl@0
    54
sl@0
    55
// 
sl@0
    56
// Meanings of the 'Version' field.
sl@0
    57
// --------------------------------
sl@0
    58
// 00 - MPEG Version 2.5 (Unofficial standard. We don't support it.)
sl@0
    59
// 01 - Reserved
sl@0
    60
// 10 - MPEG Version 2
sl@0
    61
// 11 - MPEG Version 1
sl@0
    62
//
sl@0
    63
static const TInt8 KMP3Version2 = 2;
sl@0
    64
static const TInt8 KMP3Version1 = 3;
sl@0
    65
sl@0
    66
sl@0
    67
// 
sl@0
    68
// Meanings of the 'Layer' field.
sl@0
    69
// ------------------------------
sl@0
    70
// 00 - Reserved
sl@0
    71
// 01 - Layer III
sl@0
    72
// 10 - Layer II
sl@0
    73
// 11 - Layer I
sl@0
    74
//
sl@0
    75
sl@0
    76
static const TUint16 KBad = 0;
sl@0
    77
static const TUint16 KFree = 0;
sl@0
    78
sl@0
    79
//
sl@0
    80
// MPEG Version 1 bitrates. Measured in kilobits per second.
sl@0
    81
//
sl@0
    82
static const TUint16 KBitrateVersion1[4][16] =
sl@0
    83
	{
sl@0
    84
	{ KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad}, // Reserved layer
sl@0
    85
	{KFree,   32,   40,   48,   56,   64,   80,   96,  112,  128,  160,  192,  224,  256,  320, KBad}, // Layer III
sl@0
    86
	{KFree,   32,   48,   56,   64,   80,   96,  112,  128,  160,  192,  224,  256,  320,  384, KBad}, // Layer II
sl@0
    87
	{KFree,   32,   64,   96,  128,  160,  192,  224,  256,  288,  320,  352,  384,  416,  448, KBad}  // Layer I
sl@0
    88
	};
sl@0
    89
sl@0
    90
//
sl@0
    91
// MPEG Version 2 bitrates. Measured in kilobits per second.
sl@0
    92
//
sl@0
    93
static const TUint16 KBitrateVersion2[4][16] =
sl@0
    94
	{
sl@0
    95
	{ KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad, KBad}, // Reserved layer
sl@0
    96
	{KFree,    8,   16,   24,   32,   40,   48,   56,   64,   80,   96,  112,  128,  144,  160, KBad}, // Layer III 
sl@0
    97
	{KFree,    8,   16,   24,   32,   40,   48,   56,   64,   80,   96,  112,  128,  144,  160, KBad}, // Layer II
sl@0
    98
	{KFree,   32,   48,   56,   64,   80,   96,  112,  128,  144,  160,  176,  192,  224,  256, KBad}  // Layer I
sl@0
    99
	};
sl@0
   100
sl@0
   101
//
sl@0
   102
// Sample rates for the MPEG versions.
sl@0
   103
//
sl@0
   104
static const TUint16 KSampleRate[4][4] = 
sl@0
   105
	{
sl@0
   106
		{11025, 12000,  8000, KBad}, // Version 2.5
sl@0
   107
		{ KBad,  KBad,  KBad, KBad}, // Reserved
sl@0
   108
		{22050, 24000, 16000, KBad}, // Version 2
sl@0
   109
		{44100, 48000, 32000, KBad}  // Version 1
sl@0
   110
	};
sl@0
   111
sl@0
   112
//
sl@0
   113
// Sample rates per frame for the MPEG layers.
sl@0
   114
//
sl@0
   115
static const TUint16 KSamplesPerFrame[4][4] = 
sl@0
   116
	{
sl@0
   117
		{KBad, KBad, KBad, KBad}, // Reserved layer
sl@0
   118
		{ 576, KBad,  576, 1152}, // Layer III
sl@0
   119
		{1152, KBad, 1152, 1152}, // Layer II
sl@0
   120
		{ 384, KBad,  384,  384}  // Layer I
sl@0
   121
	};
sl@0
   122
sl@0
   123
//
sl@0
   124
// The various states the recognition process goes through.
sl@0
   125
//
sl@0
   126
typedef enum
sl@0
   127
	{
sl@0
   128
	ESearchFrame1,
sl@0
   129
	ESearchFrame2
sl@0
   130
	}
sl@0
   131
TMP3State;
sl@0
   132
sl@0
   133
//
sl@0
   134
// This truth table maps the following flags to a confidence level.
sl@0
   135
// -----------------------------------------------------------------
sl@0
   136
// A: Frame2 found.
sl@0
   137
// B: Frame1 found.
sl@0
   138
// C: Extension recognised.
sl@0
   139
//
sl@0
   140
// A B C -> Confidence
sl@0
   141
// ===================
sl@0
   142
// 0 0 0 -> ENotRecognized
sl@0
   143
// 0 0 1 -> EPossible
sl@0
   144
// 0 1 0 -> ENotRecognized
sl@0
   145
// 0 1 1 -> ECertain
sl@0
   146
// 1 0 0 -> EPossible
sl@0
   147
// 1 0 1 -> EProbable
sl@0
   148
// 1 1 0 -> EProbable
sl@0
   149
// 1 1 1 -> ECertain
sl@0
   150
//
sl@0
   151
// In the case where two consecutive mp3 frames
sl@0
   152
// are found, ECertain is automatically returned.
sl@0
   153
//
sl@0
   154
static const TInt KMP3FlagsToConfidence[8] = 
sl@0
   155
	{
sl@0
   156
	KConfNotRecognised,
sl@0
   157
	KConfPossible,
sl@0
   158
	KConfNotRecognised,
sl@0
   159
	KConfCertain,
sl@0
   160
	KConfPossible,
sl@0
   161
	KConfProbable,
sl@0
   162
	KConfProbable,
sl@0
   163
	KConfCertain
sl@0
   164
	};
sl@0
   165
sl@0
   166
#define KMP3ConfidenceMask	0x07	// 00000111
sl@0
   167
#define KMP3Frame1Bit		KBit1
sl@0
   168
#define KMP3Frame2Bit		KBit2
sl@0
   169
sl@0
   170
//
sl@0
   171
//
sl@0
   172
//
sl@0
   173
TMP3Parser::TMP3Parser(CReader& aReader, TFlags& aFlags)
sl@0
   174
 : 	iReader(aReader),
sl@0
   175
 	iFlags(aFlags)
sl@0
   176
	{
sl@0
   177
	}
sl@0
   178
sl@0
   179
sl@0
   180
//
sl@0
   181
// MP3 recogition function.
sl@0
   182
//
sl@0
   183
void TMP3Parser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
sl@0
   184
	{
sl@0
   185
	TFlags flags;
sl@0
   186
	
sl@0
   187
	// Try to match the extension.
sl@0
   188
	if (aExt.MatchF(TPtrC(KExtMP3)) != KErrNotFound)
sl@0
   189
		{
sl@0
   190
		flags.SetExtensionFlag();
sl@0
   191
		}
sl@0
   192
sl@0
   193
	// Parse the data.
sl@0
   194
	TMP3Parser parser(aReader, flags);
sl@0
   195
	TRAP_IGNORE(parser.ParseL());
sl@0
   196
	
sl@0
   197
	TInt confIndex = flags.GetBitField(KMP3ConfidenceMask);
sl@0
   198
	aMatch.iConfidence = KMP3FlagsToConfidence[confIndex];
sl@0
   199
	if (aMatch.iConfidence != KConfNotRecognised)
sl@0
   200
		{
sl@0
   201
		aMatch.iMime = KMimeMP3;
sl@0
   202
		}
sl@0
   203
	}
sl@0
   204
sl@0
   205
sl@0
   206
//
sl@0
   207
// Attempts to parse an mp3 file.
sl@0
   208
// First of all it checks if there is an ID3 metadata header
sl@0
   209
// present at the current reader position. Then it checks for up to
sl@0
   210
// two consecutive mp3 audio frames.
sl@0
   211
//
sl@0
   212
void TMP3Parser::ParseL()
sl@0
   213
	{
sl@0
   214
	TInt length;
sl@0
   215
	TMP3State state = ESearchFrame1;
sl@0
   216
sl@0
   217
	FOREVER
sl@0
   218
		{
sl@0
   219
		TID3Parser::ReadAndSkipID3L(iReader);
sl@0
   220
		
sl@0
   221
		TInt err = CheckForFrameHeaderL(length);
sl@0
   222
		if (err == KErrNotFound)
sl@0
   223
			{
sl@0
   224
			return;
sl@0
   225
			}
sl@0
   226
			
sl@0
   227
		switch (state)
sl@0
   228
			{
sl@0
   229
			case ESearchFrame1:
sl@0
   230
				iFlags.SetBit(KMP3Frame1Bit);
sl@0
   231
				state = ESearchFrame2;
sl@0
   232
				break;
sl@0
   233
					
sl@0
   234
			case ESearchFrame2:
sl@0
   235
				iFlags.SetBit(KMP3Frame2Bit);
sl@0
   236
				return;
sl@0
   237
			}
sl@0
   238
				
sl@0
   239
		// Skip over the audio frame.
sl@0
   240
		// This should be done after flags have been set.
sl@0
   241
		iReader.SeekL(length - KMP3FrameHeaderSize);
sl@0
   242
		}
sl@0
   243
	}
sl@0
   244
	
sl@0
   245
sl@0
   246
//
sl@0
   247
// Checks for an MP3 frame header at the current reader position.
sl@0
   248
// If one is not found KErrNotFound is returned and aFrameLength
sl@0
   249
// remains unchanged. If one is found KErrNone is retured and
sl@0
   250
// aFrameLength is set to the length of the frame.
sl@0
   251
//
sl@0
   252
TInt TMP3Parser::CheckForFrameHeaderL(TInt& aFrameLength)
sl@0
   253
	{
sl@0
   254
	TBuf8<KMP3FrameHeaderSize> data;
sl@0
   255
	TUint8 versionIndex;
sl@0
   256
	TUint8 layerIndex;
sl@0
   257
	TUint8 bitrateIndex;
sl@0
   258
	TUint8 sampleRateIndex;
sl@0
   259
	TUint8 padding;
sl@0
   260
	TUint8 sync;
sl@0
   261
	
sl@0
   262
	data.SetLength(KMP3FrameHeaderSize);
sl@0
   263
	iReader.ReadBytesL(data);
sl@0
   264
	
sl@0
   265
	do
sl@0
   266
		{
sl@0
   267
		sync = MP3_GET_SYNC1(data[0]);
sl@0
   268
		if (IS_BAD_MP3_FRAME_SYNC1(sync))
sl@0
   269
			{
sl@0
   270
			break;
sl@0
   271
			}
sl@0
   272
			
sl@0
   273
		sync = MP3_GET_SYNC2(data[1]);
sl@0
   274
		if (IS_BAD_MP3_FRAME_SYNC2(sync))
sl@0
   275
			{
sl@0
   276
			break;
sl@0
   277
			}
sl@0
   278
		
sl@0
   279
		versionIndex = MP3_GET_VERSION(data[1]);
sl@0
   280
		if (IS_BAD_MP3_VERSION(versionIndex))
sl@0
   281
			{
sl@0
   282
			break;
sl@0
   283
			}
sl@0
   284
			
sl@0
   285
		layerIndex = MP3_GET_LAYER(data[1]);
sl@0
   286
		if (IS_BAD_MP3_LAYER(layerIndex))
sl@0
   287
			{
sl@0
   288
			break;
sl@0
   289
			}
sl@0
   290
			
sl@0
   291
		bitrateIndex = MP3_GET_BITRATE(data[2]);
sl@0
   292
		if (IS_BAD_MP3_BITRATE(bitrateIndex))
sl@0
   293
			{
sl@0
   294
			break;
sl@0
   295
			}
sl@0
   296
			
sl@0
   297
		sampleRateIndex = MP3_GET_SAMPLE_RATE(data[2]);
sl@0
   298
		if (IS_BAD_MP3_SAMPLE_RATE(sampleRateIndex))
sl@0
   299
			{
sl@0
   300
			break;
sl@0
   301
			}
sl@0
   302
			
sl@0
   303
		padding = MP3_GET_PADDING(data[2]);
sl@0
   304
		
sl@0
   305
		// All the data is valid.
sl@0
   306
		// Compute the audio data length.
sl@0
   307
		TUint32 bitRate = KBad;
sl@0
   308
		TUint16 sampleRate = KBad;
sl@0
   309
		TUint16 samplesPerFrame = KBad;
sl@0
   310
		
sl@0
   311
		if (versionIndex == KMP3Version1)
sl@0
   312
			{
sl@0
   313
			bitRate = KBitrateVersion1[layerIndex][bitrateIndex];
sl@0
   314
			}
sl@0
   315
		else if (versionIndex == KMP3Version2)
sl@0
   316
			{
sl@0
   317
			bitRate = KBitrateVersion2[layerIndex][bitrateIndex];
sl@0
   318
			}
sl@0
   319
		else 
sl@0
   320
			{
sl@0
   321
			// Version 2.5 is not supported.
sl@0
   322
			break;
sl@0
   323
			}
sl@0
   324
sl@0
   325
		sampleRate = KSampleRate[versionIndex][sampleRateIndex];
sl@0
   326
		samplesPerFrame = KSamplesPerFrame[layerIndex][versionIndex];
sl@0
   327
		
sl@0
   328
		// Check we have valid values.
sl@0
   329
		if ((bitRate == KBad) || (sampleRate == KBad) || (samplesPerFrame == KBad))
sl@0
   330
			{
sl@0
   331
			break;
sl@0
   332
			}
sl@0
   333
sl@0
   334
		bitRate *= 1000; // Convert to kilobits.
sl@0
   335
		aFrameLength = (((samplesPerFrame / KBitsPerByte) * bitRate) / sampleRate) + padding;
sl@0
   336
		return KErrNone;
sl@0
   337
		}
sl@0
   338
	while (EFalse);
sl@0
   339
	
sl@0
   340
	// No valid frame header was found.
sl@0
   341
	aFrameLength = 0;
sl@0
   342
	iReader.SeekL(-KMP3FrameHeaderSize);
sl@0
   343
	return KErrNotFound;
sl@0
   344
	}
sl@0
   345
	
sl@0
   346
sl@0
   347
sl@0
   348