os/mm/mmlibs/mmfw/Recogniser/src/matparser.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 "constants.h"
sl@0
    17
#include "parsers.h"
sl@0
    18
sl@0
    19
//
sl@0
    20
// Matroska 'XML' tags.
sl@0
    21
//
sl@0
    22
static const TUint32 KEBML = 0x1A45DFA3;
sl@0
    23
static const TUint32 KSegment = 0x18538067;
sl@0
    24
static const TUint32 KTracks = 0x1654AE6B;
sl@0
    25
static const TUint32 KTrackEntry = 0xAE;
sl@0
    26
static const TUint32 KTrackType = 0x83;
sl@0
    27
static const TUint32 KVoid = 0xEC;
sl@0
    28
static const TUint32 KSeekHead = 0x114D9B74;
sl@0
    29
static const TUint32 KSegmentInfo = 0x1549A966;
sl@0
    30
static const TUint32 KCluster = 0x1F43B675;
sl@0
    31
static const TUint32 KCues = 0x1C53BB6B;
sl@0
    32
static const TUint32 KAttachments = 0x1941A469;
sl@0
    33
static const TUint32 KChapters = 0x1043A770;
sl@0
    34
static const TUint32 KTags = 0x1254C367;
sl@0
    35
sl@0
    36
//
sl@0
    37
// Matroska Track Types.
sl@0
    38
//
sl@0
    39
static const TUint8 KTrackTypeVideo = 0x01;
sl@0
    40
sl@0
    41
#define KMatroskaConfidenceMask	0x07	// 00000111
sl@0
    42
#define KMatroskaEBMLBit		KBit1
sl@0
    43
#define KMatroskaSegmentBit		KBit2
sl@0
    44
#define KMatroskaVideoBit		KBit3
sl@0
    45
sl@0
    46
sl@0
    47
//
sl@0
    48
// This truth table maps the following flags to confidence levels.
sl@0
    49
//
sl@0
    50
// A: Extension match.
sl@0
    51
// B: EBML tag found.
sl@0
    52
// C: Segment tag found.
sl@0
    53
//
sl@0
    54
// C B A -> Confidence
sl@0
    55
// --------------------
sl@0
    56
// 0 0 0 -> NotRecognised
sl@0
    57
// 0 0 1 -> EPossible
sl@0
    58
// 0 1 0 -> EPossible
sl@0
    59
// 0 1 1 -> EProbable
sl@0
    60
// 1 0 0 -> ENotRecognised (EBML should be present)
sl@0
    61
// 1 0 1 -> ENotRecognised (EBML should be present)
sl@0
    62
// 1 1 0 -> EProbable
sl@0
    63
// 1 1 1 -> ECertain
sl@0
    64
//
sl@0
    65
static const TInt KMatroskaFlagsToConfidence[8] =
sl@0
    66
	{
sl@0
    67
	KConfNotRecognised,
sl@0
    68
	KConfPossible,
sl@0
    69
	KConfPossible,
sl@0
    70
	KConfProbable,
sl@0
    71
	KConfNotRecognised,
sl@0
    72
	KConfNotRecognised,
sl@0
    73
	KConfProbable,
sl@0
    74
	KConfCertain
sl@0
    75
	};
sl@0
    76
	
sl@0
    77
static const TInt KMatExtensionOnlyIndex = 1; // See truth table.
sl@0
    78
sl@0
    79
sl@0
    80
typedef struct
sl@0
    81
	{
sl@0
    82
	const TText* iExt;
sl@0
    83
	const TText8* iMime;
sl@0
    84
	}
sl@0
    85
TMatroskaExt;
sl@0
    86
sl@0
    87
//
sl@0
    88
// Known Matroska extensions and their corresponding MIME-types.
sl@0
    89
//
sl@0
    90
static const TMatroskaExt KMatroskaExt[] =
sl@0
    91
	{
sl@0
    92
		{KExtMAT_A, KMimeMAT_A },
sl@0
    93
		{KExtMAT_V, KMimeMAT_V }
sl@0
    94
	};
sl@0
    95
sl@0
    96
static const TInt KMatroskaExtCount = sizeof(KMatroskaExt) / sizeof(TMatroskaExt);
sl@0
    97
sl@0
    98
sl@0
    99
//
sl@0
   100
//
sl@0
   101
//
sl@0
   102
TMatroskaParser::TMatroskaParser(CReader& aReader, TFlags& aFlags)
sl@0
   103
 :	iReader(aReader),
sl@0
   104
 	iFlags(aFlags)
sl@0
   105
	{
sl@0
   106
	}
sl@0
   107
sl@0
   108
sl@0
   109
//
sl@0
   110
//
sl@0
   111
//
sl@0
   112
const TText8* TMatroskaParser::MatchExtension(const TDesC& aExt)
sl@0
   113
	{
sl@0
   114
	for (TInt i = 0; i < KMatroskaExtCount; i++)
sl@0
   115
		{
sl@0
   116
		if (aExt.MatchF(TPtrC(KMatroskaExt[i].iExt)) != KErrNotFound)
sl@0
   117
			{
sl@0
   118
			return KMatroskaExt[i].iMime;
sl@0
   119
			}
sl@0
   120
		}
sl@0
   121
	
sl@0
   122
	return NULL;
sl@0
   123
	}
sl@0
   124
sl@0
   125
sl@0
   126
//
sl@0
   127
// This function calls the parser and turns the results
sl@0
   128
// into a MIME-type.
sl@0
   129
//
sl@0
   130
void TMatroskaParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
sl@0
   131
	{
sl@0
   132
	TFlags flags;
sl@0
   133
	TMatroskaParser parser(aReader, flags);
sl@0
   134
	
sl@0
   135
	// Try to match the extension.
sl@0
   136
	const TText8* extMime = parser.MatchExtension(aExt);
sl@0
   137
	if (extMime != NULL)
sl@0
   138
		{
sl@0
   139
		flags.SetExtensionFlag();
sl@0
   140
		}
sl@0
   141
sl@0
   142
	// Try to parse the content.
sl@0
   143
	TRAP_IGNORE(parser.ParseL());
sl@0
   144
	TInt confIndex = flags.GetBitField(KMatroskaConfidenceMask);
sl@0
   145
	aMatch.iConfidence = KMatroskaFlagsToConfidence[confIndex];
sl@0
   146
	if (aMatch.iConfidence != KConfNotRecognised)
sl@0
   147
		{
sl@0
   148
		// If any header data has been recognised trust that,
sl@0
   149
		// otherwise go with the extension.
sl@0
   150
		if (confIndex == KMatExtensionOnlyIndex)
sl@0
   151
			{
sl@0
   152
			aMatch.iMime = extMime;
sl@0
   153
			}
sl@0
   154
		else
sl@0
   155
			{
sl@0
   156
			aMatch.iMime = (flags.GetBitField(KMatroskaVideoBit) ? KMimeMAT_V : KMimeMAT_A);
sl@0
   157
			}
sl@0
   158
		}
sl@0
   159
	}
sl@0
   160
sl@0
   161
sl@0
   162
//
sl@0
   163
// This function does the parsing.
sl@0
   164
//
sl@0
   165
void TMatroskaParser::ParseL()
sl@0
   166
	{
sl@0
   167
	TUint64 id;
sl@0
   168
	TInt64 size;
sl@0
   169
	TBool haveElement = EFalse;
sl@0
   170
	
sl@0
   171
	// Assume there's video content if we only have buffer data.
sl@0
   172
	if (iReader.Type() == CReader::EBuffer)
sl@0
   173
		{
sl@0
   174
		iFlags.SetBit(KMatroskaVideoBit);
sl@0
   175
		}
sl@0
   176
		
sl@0
   177
	FOREVER
sl@0
   178
		{
sl@0
   179
		if (!haveElement)
sl@0
   180
			{
sl@0
   181
			ReadElementL(id, size);
sl@0
   182
			}
sl@0
   183
		
sl@0
   184
		switch (id)
sl@0
   185
			{
sl@0
   186
			case KEBML:
sl@0
   187
				iFlags.SetBit(KMatroskaEBMLBit);
sl@0
   188
				break;
sl@0
   189
				
sl@0
   190
			case KSegment:
sl@0
   191
				haveElement = ReadSegmentL(id, size);
sl@0
   192
				break;
sl@0
   193
				
sl@0
   194
			default:
sl@0
   195
				// Skip it.
sl@0
   196
				iReader.SeekL(size);
sl@0
   197
			}
sl@0
   198
		}
sl@0
   199
	}
sl@0
   200
sl@0
   201
sl@0
   202
//
sl@0
   203
// This function returns ETrue if the aNextID and aNextSize parameters
sl@0
   204
// contain valid values, EFalse otherwise.
sl@0
   205
//
sl@0
   206
TBool TMatroskaParser::ReadSegmentL(TUint64& aNextID, TInt64& aNextSize)
sl@0
   207
	{
sl@0
   208
	TUint64 id;
sl@0
   209
	TInt64 size;
sl@0
   210
	TBool videoContent = EFalse;
sl@0
   211
	
sl@0
   212
	aNextID = 0;
sl@0
   213
	aNextSize = 0;
sl@0
   214
	
sl@0
   215
	iFlags.SetBit(KMatroskaSegmentBit);
sl@0
   216
	
sl@0
   217
	while (!videoContent)
sl@0
   218
		{
sl@0
   219
		ReadElementL(id, size);
sl@0
   220
		
sl@0
   221
		switch (id)
sl@0
   222
			{
sl@0
   223
			case KTracks:
sl@0
   224
				videoContent = ReadTrackL(size);
sl@0
   225
				break;
sl@0
   226
			
sl@0
   227
			case KSeekHead:
sl@0
   228
			case KSegmentInfo:
sl@0
   229
			case KCluster:
sl@0
   230
			case KCues:
sl@0
   231
			case KAttachments: 
sl@0
   232
			case KChapters:
sl@0
   233
			case KTags:
sl@0
   234
				iReader.SeekL(size);
sl@0
   235
				break;
sl@0
   236
				
sl@0
   237
			default:
sl@0
   238
				// Unrecognised element id. Pass it back to the caller
sl@0
   239
				aNextID = id;
sl@0
   240
				aNextSize = size;
sl@0
   241
				return ETrue;
sl@0
   242
			}
sl@0
   243
		}
sl@0
   244
	
sl@0
   245
	// Tell the caller they must read the next element themselves.
sl@0
   246
	return EFalse;
sl@0
   247
	}
sl@0
   248
sl@0
   249
sl@0
   250
//
sl@0
   251
// The Track. This lets us know if there's video content present.
sl@0
   252
//
sl@0
   253
TBool TMatroskaParser::ReadTrackL(TInt64 aTrackSize)
sl@0
   254
	{
sl@0
   255
	TUint64 id;
sl@0
   256
	TInt64 size;
sl@0
   257
	TInt startPos = iReader.Position();
sl@0
   258
	
sl@0
   259
	while (iReader.Position() - startPos < aTrackSize)
sl@0
   260
		{
sl@0
   261
		ReadElementL(id, size);
sl@0
   262
sl@0
   263
		switch (id)
sl@0
   264
			{
sl@0
   265
			case KTrackEntry:
sl@0
   266
				break;
sl@0
   267
				
sl@0
   268
			case KTrackType:
sl@0
   269
				TUint8 trackType;
sl@0
   270
				iReader.ReadByteL(trackType);
sl@0
   271
				if (trackType == KTrackTypeVideo)
sl@0
   272
					{
sl@0
   273
					// We found video content so we can stop parsing.
sl@0
   274
					iFlags.SetBit(KMatroskaVideoBit);
sl@0
   275
					return ETrue;
sl@0
   276
					}
sl@0
   277
				break;
sl@0
   278
				
sl@0
   279
			default:
sl@0
   280
				iReader.SeekL(size);
sl@0
   281
			}
sl@0
   282
		}
sl@0
   283
		
sl@0
   284
	return EFalse;
sl@0
   285
	}
sl@0
   286
sl@0
   287
sl@0
   288
//
sl@0
   289
//
sl@0
   290
//
sl@0
   291
void TMatroskaParser::ReadElementL(TUint64& aElementID, TInt64& aSize)
sl@0
   292
	{
sl@0
   293
	do
sl@0
   294
		{
sl@0
   295
		aElementID = ReadDataL();
sl@0
   296
		aSize = ReadDataL(ETrue);
sl@0
   297
sl@0
   298
		// Void elements are used for padding and
sl@0
   299
		// can be ignored.
sl@0
   300
		if (aElementID == KVoid)
sl@0
   301
			{
sl@0
   302
			iReader.SeekL(aSize);
sl@0
   303
			}
sl@0
   304
		}
sl@0
   305
	while (aElementID == KVoid);
sl@0
   306
	}
sl@0
   307
sl@0
   308
sl@0
   309
//
sl@0
   310
//
sl@0
   311
//
sl@0
   312
TUint64 TMatroskaParser::ReadDataL(TBool aTurnOffHighestSetBit)
sl@0
   313
	{
sl@0
   314
	TUint64 retval;
sl@0
   315
	TUint8 byte;
sl@0
   316
	TUint8 mask = 0x80; // [1000 0000]. It will be shifted right 1 in each 'i' iteration.
sl@0
   317
	TUint8 size = 1;	// It will be incremented in each 'i' iteration.
sl@0
   318
	
sl@0
   319
	iReader.ReadByteL(byte);
sl@0
   320
	
sl@0
   321
	for (TInt i = 0; i < sizeof(TUint64); i++)
sl@0
   322
		{
sl@0
   323
		if (byte & mask)
sl@0
   324
			{
sl@0
   325
			retval = byte;
sl@0
   326
			if (aTurnOffHighestSetBit)
sl@0
   327
				{
sl@0
   328
				retval &= ~mask; // Turn off the highest set bit.
sl@0
   329
				}
sl@0
   330
			
sl@0
   331
			// Now read the real data.
sl@0
   332
			// Start from 1 because we've already read a byte.
sl@0
   333
			for (TInt j = 1; j < size; j++)
sl@0
   334
				{
sl@0
   335
				iReader.ReadByteL(byte);
sl@0
   336
				retval <<= 8;
sl@0
   337
				retval |= byte;
sl@0
   338
				}
sl@0
   339
				
sl@0
   340
			return retval;
sl@0
   341
			}
sl@0
   342
		else
sl@0
   343
			{
sl@0
   344
			mask >>= 1;
sl@0
   345
			size++;
sl@0
   346
			}
sl@0
   347
		}
sl@0
   348
sl@0
   349
	User::Leave(KErrCorrupt);
sl@0
   350
	return 0; // Keep the compiler happy.
sl@0
   351
	}
sl@0
   352