os/mm/mmlibs/mmfw/Recogniser/src/mpeg2parser.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
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
#include "parsers.h"
sl@0
    17
sl@0
    18
static const TUint8 KISOEndCode = 0xB9;
sl@0
    19
static const TUint8 KPackStartCode = 0xBA;
sl@0
    20
static const TUint8 KVideoElementaryStream = 0xE0;
sl@0
    21
sl@0
    22
#define KMPEG1PackHeaderLen		8
sl@0
    23
#define KMPEG2PackHeaderLen		10
sl@0
    24
sl@0
    25
#define KMPEG1PackHeaderID		0x21	// 0010xxx1. See Doc Link 2.
sl@0
    26
#define KMPEG2PackHeaderID		0x44	// 01xxx1xx. See Doc Link 2.
sl@0
    27
sl@0
    28
#define KStartCodeMask			0xffffff00
sl@0
    29
#define KStartCodeIntro			0x00000100
sl@0
    30
sl@0
    31
#define KMPEG2StartCode1Bit	KBit1
sl@0
    32
#define KMPEG2StartCode2Bit	KBit2
sl@0
    33
#define KMPEG2VideoBit		KBit3
sl@0
    34
#define KMPEG2MPEG1Bit		KBit4
sl@0
    35
sl@0
    36
//
sl@0
    37
// Mapping flags to a confidence level.
sl@0
    38
//
sl@0
    39
// A: extension match
sl@0
    40
// B: start-code1
sl@0
    41
// C: start-code2
sl@0
    42
//
sl@0
    43
// C B A -> Confidence
sl@0
    44
// -------------------
sl@0
    45
// 0 0 0 -> ENotRecognised
sl@0
    46
// 0 0 1 -> EPossible
sl@0
    47
// 0 1 0 -> EPossible
sl@0
    48
// 0 1 1 -> EProbable
sl@0
    49
// 1 0 0 -> ENotRecognised
sl@0
    50
// 1 0 1 -> ENotRecognised
sl@0
    51
// 1 1 0 -> EProbable
sl@0
    52
// 1 1 1 -> ECertain
sl@0
    53
//
sl@0
    54
static const TInt KMPEG2FlagsToConfidence[] =
sl@0
    55
	{
sl@0
    56
	KConfNotRecognised,
sl@0
    57
	KConfPossible,
sl@0
    58
	KConfPossible,
sl@0
    59
	KConfProbable,
sl@0
    60
	KConfNotRecognised,
sl@0
    61
	KConfNotRecognised,
sl@0
    62
	KConfProbable,
sl@0
    63
	KConfCertain
sl@0
    64
	};
sl@0
    65
sl@0
    66
#define KMPEG2ConfidenceMask	0x07	// 00000111
sl@0
    67
#define KMPEG2MimeMask	 		0x18	// 00011000
sl@0
    68
#define KMPEG2MimeShift			0x03	
sl@0
    69
sl@0
    70
static const TInt KMPEG2ExtOnlyIndex = 1;
sl@0
    71
	
sl@0
    72
//
sl@0
    73
// The 'ED' bits of the flags member are used as an index into
sl@0
    74
// this table of possible MIME-types.
sl@0
    75
//
sl@0
    76
// E: MPEG1 instead of MPEG2
sl@0
    77
// D: Video content present
sl@0
    78
//
sl@0
    79
// E D -> Mime
sl@0
    80
// -----------
sl@0
    81
// 0 0 -> audio/mpeg2
sl@0
    82
// 0 1 -> video/mpeg2
sl@0
    83
// 1 0 -> audio/mpeg1
sl@0
    84
// 1 1 -> video/mpeg1
sl@0
    85
//
sl@0
    86
static const TText8* const KMPEG2Mimes[] = 
sl@0
    87
	{
sl@0
    88
	KMimeMPEG2_A,
sl@0
    89
	KMimeMPEG2_V,
sl@0
    90
	KMimeMPEG1_A,
sl@0
    91
	KMimeMPEG1_V
sl@0
    92
	};
sl@0
    93
sl@0
    94
//
sl@0
    95
// A list of known MPEG2 file extensions.
sl@0
    96
// MPEG1 file extensions are also listed.
sl@0
    97
//
sl@0
    98
typedef struct
sl@0
    99
	{
sl@0
   100
	const TText* iExt;
sl@0
   101
	const TText8* iMime;
sl@0
   102
	}
sl@0
   103
TMPEG2Types;
sl@0
   104
sl@0
   105
static const TMPEG2Types KMPEG2Types[] = 
sl@0
   106
	{
sl@0
   107
		{ KExtMPEG_1, KMimeMPEG2_V },
sl@0
   108
		{ KExtMPEG_2, KMimeMPEG2_V },
sl@0
   109
		{ KExtMPEG_3, KMimeMPEG2_V },
sl@0
   110
		{ KExtMPEG_4, KMimeMPEG2_V },
sl@0
   111
		{ KExtMPEG_5, KMimeMPEG2_V },
sl@0
   112
		{ KExtMPEG_6, KMimeMPEG2_V },
sl@0
   113
		{ KExtMPEG_7, KMimeMPEG1_V },
sl@0
   114
		{ KExtMPEG_8, KMimeMPEG2_A }
sl@0
   115
	};
sl@0
   116
	
sl@0
   117
#define KMPEG2ExtCount sizeof(KMPEG2Types) / sizeof(TMPEG2Types)
sl@0
   118
	
sl@0
   119
sl@0
   120
//
sl@0
   121
//
sl@0
   122
//
sl@0
   123
TMPEG2Parser::TMPEG2Parser(CReader& aReader, TFlags& aFlags)
sl@0
   124
 :	iReader(aReader),
sl@0
   125
 	iFlags(aFlags)
sl@0
   126
	{
sl@0
   127
	}
sl@0
   128
sl@0
   129
sl@0
   130
//
sl@0
   131
// Match the file's extension to known MPEG2 file extensions.
sl@0
   132
//
sl@0
   133
const TText8* TMPEG2Parser::MatchExtension(const TDesC& aExt)
sl@0
   134
	{
sl@0
   135
	if (aExt.Length() > 0)
sl@0
   136
		{
sl@0
   137
		for (TInt i = 0; i < KMPEG2ExtCount; i++)
sl@0
   138
			{
sl@0
   139
			if (aExt.MatchF(TPtrC(KMPEG2Types[i].iExt)) != KErrNotFound)
sl@0
   140
				{
sl@0
   141
				iFlags.SetExtensionFlag();
sl@0
   142
				return KMPEG2Types[i].iMime;
sl@0
   143
				}
sl@0
   144
			}
sl@0
   145
		}
sl@0
   146
	
sl@0
   147
	return NULL;
sl@0
   148
	}
sl@0
   149
sl@0
   150
sl@0
   151
//
sl@0
   152
//
sl@0
   153
//
sl@0
   154
void TMPEG2Parser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
sl@0
   155
	{
sl@0
   156
	TFlags flags;
sl@0
   157
	TMPEG2Parser parser(aReader, flags);
sl@0
   158
	
sl@0
   159
	const TText8* extMime = parser.MatchExtension(aExt);
sl@0
   160
	TRAP_IGNORE(parser.ParseL());
sl@0
   161
	
sl@0
   162
	TInt confIndex = flags.GetBitField(KMPEG2ConfidenceMask);
sl@0
   163
	aMatch.iConfidence = KMPEG2FlagsToConfidence[confIndex];
sl@0
   164
	if (aMatch.iConfidence != KConfNotRecognised)
sl@0
   165
		{
sl@0
   166
		if (confIndex == KMPEG2ExtOnlyIndex)
sl@0
   167
			{
sl@0
   168
			// The content is corrupt, but the extension was recognised.
sl@0
   169
			aMatch.iMime = extMime;
sl@0
   170
			}
sl@0
   171
		else
sl@0
   172
			{
sl@0
   173
			TInt mimeIndex = flags.GetBitField(KMPEG2MimeMask, KMPEG2MimeShift);
sl@0
   174
			aMatch.iMime = KMPEG2Mimes[mimeIndex];
sl@0
   175
			}
sl@0
   176
		}
sl@0
   177
	}
sl@0
   178
sl@0
   179
sl@0
   180
//
sl@0
   181
// Attempts to parse an MPEG2 file by looking for start-codes.
sl@0
   182
//
sl@0
   183
void TMPEG2Parser::ParseL()
sl@0
   184
	{
sl@0
   185
	TBool finished;
sl@0
   186
	
sl@0
   187
	// Assume there's video content if we only have a buffer.
sl@0
   188
	if (iReader.Type() == CReader::EBuffer)
sl@0
   189
		{
sl@0
   190
		iFlags.SetBit(KMPEG2VideoBit);
sl@0
   191
		}
sl@0
   192
	
sl@0
   193
	do
sl@0
   194
		{
sl@0
   195
		finished = NextStartCodeL();
sl@0
   196
		}
sl@0
   197
	while (!finished);
sl@0
   198
	}
sl@0
   199
sl@0
   200
sl@0
   201
//
sl@0
   202
// Skips over the current start-code box.
sl@0
   203
//
sl@0
   204
void TMPEG2Parser::SkipL()
sl@0
   205
	{
sl@0
   206
	TUint16 size;
sl@0
   207
	
sl@0
   208
	iReader.Read16L(size);
sl@0
   209
	iReader.SeekL((TInt)size);
sl@0
   210
	}
sl@0
   211
sl@0
   212
sl@0
   213
/*
sl@0
   214
** Expects an MPEG2 Pack Header at the current location.
sl@0
   215
** The Pack Header is used to determine between MPEG1 and MPEG2.
sl@0
   216
*/
sl@0
   217
void TMPEG2Parser::ReadPackHeaderL()
sl@0
   218
	{
sl@0
   219
	TUint8 byte;
sl@0
   220
	TBuf8<KMPEG2PackHeaderLen> header;	// Size is of whichever is larger.
sl@0
   221
	
sl@0
   222
	iReader.ReadByteL(byte);
sl@0
   223
	
sl@0
   224
	if ((byte & KMPEG1PackHeaderID) == KMPEG1PackHeaderID)
sl@0
   225
		{
sl@0
   226
		iFlags.SetBit(KMPEG2MPEG1Bit);
sl@0
   227
		header.SetLength(KMPEG1PackHeaderLen - 1);	// We've already read a byte.
sl@0
   228
		iReader.ReadBytesL(header);
sl@0
   229
		}
sl@0
   230
	else if ((byte & KMPEG2PackHeaderID) == KMPEG2PackHeaderID)
sl@0
   231
		{
sl@0
   232
		header.SetLength(KMPEG2PackHeaderLen - 1);	// We've already read a byte.
sl@0
   233
		iReader.ReadBytesL(header);
sl@0
   234
		
sl@0
   235
		// The lowest 3 bits of the last byte say how much stuffing is present.
sl@0
   236
		TInt stuffing = header[8] & 0x07; // 00000111
sl@0
   237
		if (stuffing)
sl@0
   238
			{
sl@0
   239
			iReader.SeekL(stuffing);
sl@0
   240
			}
sl@0
   241
		}
sl@0
   242
	else
sl@0
   243
		{
sl@0
   244
		User::Leave(KErrCorrupt);
sl@0
   245
		}
sl@0
   246
		
sl@0
   247
	}
sl@0
   248
sl@0
   249
//
sl@0
   250
// Start codes are bit patterns that do not occur in the video stream.
sl@0
   251
// The start-code sequence is expected to be at the current CReader position.
sl@0
   252
//
sl@0
   253
TBool TMPEG2Parser::NextStartCodeL()
sl@0
   254
	{
sl@0
   255
	TUint32 data;
sl@0
   256
sl@0
   257
	iReader.Read32L(data);
sl@0
   258
	
sl@0
   259
	// Start codes must begin with 0x000001ss, where 'ss' is the start code.
sl@0
   260
	if ((data & KStartCodeMask) != KStartCodeIntro)
sl@0
   261
		{
sl@0
   262
		User::Leave(KErrCorrupt);
sl@0
   263
		}
sl@0
   264
		
sl@0
   265
	if (!iFlags.GetBitField(KMPEG2StartCode1Bit))
sl@0
   266
		{
sl@0
   267
		iFlags.SetBit(KMPEG2StartCode1Bit);
sl@0
   268
		}
sl@0
   269
	else
sl@0
   270
		{
sl@0
   271
		if (!iFlags.GetBitField(KMPEG2StartCode2Bit))
sl@0
   272
			{
sl@0
   273
			iFlags.SetBit(KMPEG2StartCode2Bit);
sl@0
   274
			}
sl@0
   275
		}
sl@0
   276
		
sl@0
   277
	// Try to identify the start code.
sl@0
   278
	switch (LOW_BYTE(data))
sl@0
   279
		{
sl@0
   280
		case KPackStartCode:
sl@0
   281
			ReadPackHeaderL();
sl@0
   282
			break;
sl@0
   283
			
sl@0
   284
		case KVideoElementaryStream:
sl@0
   285
			iFlags.SetBit(KMPEG2VideoBit);
sl@0
   286
			return ETrue;
sl@0
   287
			
sl@0
   288
		case KISOEndCode:
sl@0
   289
			// This code should occur at the end of the file and
sl@0
   290
			// it cannot be skipped over.
sl@0
   291
			return ETrue;
sl@0
   292
			
sl@0
   293
		default:
sl@0
   294
			SkipL();
sl@0
   295
		}
sl@0
   296
		
sl@0
   297
	return EFalse;
sl@0
   298
	}
sl@0
   299