mmlibs/mmfw/Recogniser/src/matparser.cpp
changeset 0 b8ed18f6c07b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/Recogniser/src/matparser.cpp	Thu Oct 07 22:34:12 2010 +0100
@@ -0,0 +1,352 @@
+// 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 "constants.h"
+#include "parsers.h"
+
+//
+// Matroska 'XML' tags.
+//
+static const TUint32 KEBML = 0x1A45DFA3;
+static const TUint32 KSegment = 0x18538067;
+static const TUint32 KTracks = 0x1654AE6B;
+static const TUint32 KTrackEntry = 0xAE;
+static const TUint32 KTrackType = 0x83;
+static const TUint32 KVoid = 0xEC;
+static const TUint32 KSeekHead = 0x114D9B74;
+static const TUint32 KSegmentInfo = 0x1549A966;
+static const TUint32 KCluster = 0x1F43B675;
+static const TUint32 KCues = 0x1C53BB6B;
+static const TUint32 KAttachments = 0x1941A469;
+static const TUint32 KChapters = 0x1043A770;
+static const TUint32 KTags = 0x1254C367;
+
+//
+// Matroska Track Types.
+//
+static const TUint8 KTrackTypeVideo = 0x01;
+
+#define KMatroskaConfidenceMask	0x07	// 00000111
+#define KMatroskaEBMLBit		KBit1
+#define KMatroskaSegmentBit		KBit2
+#define KMatroskaVideoBit		KBit3
+
+
+//
+// This truth table maps the following flags to confidence levels.
+//
+// A: Extension match.
+// B: EBML tag found.
+// C: Segment tag found.
+//
+// C B A -> Confidence
+// --------------------
+// 0 0 0 -> NotRecognised
+// 0 0 1 -> EPossible
+// 0 1 0 -> EPossible
+// 0 1 1 -> EProbable
+// 1 0 0 -> ENotRecognised (EBML should be present)
+// 1 0 1 -> ENotRecognised (EBML should be present)
+// 1 1 0 -> EProbable
+// 1 1 1 -> ECertain
+//
+static const TInt KMatroskaFlagsToConfidence[8] =
+	{
+	KConfNotRecognised,
+	KConfPossible,
+	KConfPossible,
+	KConfProbable,
+	KConfNotRecognised,
+	KConfNotRecognised,
+	KConfProbable,
+	KConfCertain
+	};
+	
+static const TInt KMatExtensionOnlyIndex = 1; // See truth table.
+
+
+typedef struct
+	{
+	const TText* iExt;
+	const TText8* iMime;
+	}
+TMatroskaExt;
+
+//
+// Known Matroska extensions and their corresponding MIME-types.
+//
+static const TMatroskaExt KMatroskaExt[] =
+	{
+		{KExtMAT_A, KMimeMAT_A },
+		{KExtMAT_V, KMimeMAT_V }
+	};
+
+static const TInt KMatroskaExtCount = sizeof(KMatroskaExt) / sizeof(TMatroskaExt);
+
+
+//
+//
+//
+TMatroskaParser::TMatroskaParser(CReader& aReader, TFlags& aFlags)
+ :	iReader(aReader),
+ 	iFlags(aFlags)
+	{
+	}
+
+
+//
+//
+//
+const TText8* TMatroskaParser::MatchExtension(const TDesC& aExt)
+	{
+	for (TInt i = 0; i < KMatroskaExtCount; i++)
+		{
+		if (aExt.MatchF(TPtrC(KMatroskaExt[i].iExt)) != KErrNotFound)
+			{
+			return KMatroskaExt[i].iMime;
+			}
+		}
+	
+	return NULL;
+	}
+
+
+//
+// This function calls the parser and turns the results
+// into a MIME-type.
+//
+void TMatroskaParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
+	{
+	TFlags flags;
+	TMatroskaParser parser(aReader, flags);
+	
+	// Try to match the extension.
+	const TText8* extMime = parser.MatchExtension(aExt);
+	if (extMime != NULL)
+		{
+		flags.SetExtensionFlag();
+		}
+
+	// Try to parse the content.
+	TRAP_IGNORE(parser.ParseL());
+	TInt confIndex = flags.GetBitField(KMatroskaConfidenceMask);
+	aMatch.iConfidence = KMatroskaFlagsToConfidence[confIndex];
+	if (aMatch.iConfidence != KConfNotRecognised)
+		{
+		// If any header data has been recognised trust that,
+		// otherwise go with the extension.
+		if (confIndex == KMatExtensionOnlyIndex)
+			{
+			aMatch.iMime = extMime;
+			}
+		else
+			{
+			aMatch.iMime = (flags.GetBitField(KMatroskaVideoBit) ? KMimeMAT_V : KMimeMAT_A);
+			}
+		}
+	}
+
+
+//
+// This function does the parsing.
+//
+void TMatroskaParser::ParseL()
+	{
+	TUint64 id;
+	TInt64 size;
+	TBool haveElement = EFalse;
+	
+	// Assume there's video content if we only have buffer data.
+	if (iReader.Type() == CReader::EBuffer)
+		{
+		iFlags.SetBit(KMatroskaVideoBit);
+		}
+		
+	FOREVER
+		{
+		if (!haveElement)
+			{
+			ReadElementL(id, size);
+			}
+		
+		switch (id)
+			{
+			case KEBML:
+				iFlags.SetBit(KMatroskaEBMLBit);
+				break;
+				
+			case KSegment:
+				haveElement = ReadSegmentL(id, size);
+				break;
+				
+			default:
+				// Skip it.
+				iReader.SeekL(size);
+			}
+		}
+	}
+
+
+//
+// This function returns ETrue if the aNextID and aNextSize parameters
+// contain valid values, EFalse otherwise.
+//
+TBool TMatroskaParser::ReadSegmentL(TUint64& aNextID, TInt64& aNextSize)
+	{
+	TUint64 id;
+	TInt64 size;
+	TBool videoContent = EFalse;
+	
+	aNextID = 0;
+	aNextSize = 0;
+	
+	iFlags.SetBit(KMatroskaSegmentBit);
+	
+	while (!videoContent)
+		{
+		ReadElementL(id, size);
+		
+		switch (id)
+			{
+			case KTracks:
+				videoContent = ReadTrackL(size);
+				break;
+			
+			case KSeekHead:
+			case KSegmentInfo:
+			case KCluster:
+			case KCues:
+			case KAttachments: 
+			case KChapters:
+			case KTags:
+				iReader.SeekL(size);
+				break;
+				
+			default:
+				// Unrecognised element id. Pass it back to the caller
+				aNextID = id;
+				aNextSize = size;
+				return ETrue;
+			}
+		}
+	
+	// Tell the caller they must read the next element themselves.
+	return EFalse;
+	}
+
+
+//
+// The Track. This lets us know if there's video content present.
+//
+TBool TMatroskaParser::ReadTrackL(TInt64 aTrackSize)
+	{
+	TUint64 id;
+	TInt64 size;
+	TInt startPos = iReader.Position();
+	
+	while (iReader.Position() - startPos < aTrackSize)
+		{
+		ReadElementL(id, size);
+
+		switch (id)
+			{
+			case KTrackEntry:
+				break;
+				
+			case KTrackType:
+				TUint8 trackType;
+				iReader.ReadByteL(trackType);
+				if (trackType == KTrackTypeVideo)
+					{
+					// We found video content so we can stop parsing.
+					iFlags.SetBit(KMatroskaVideoBit);
+					return ETrue;
+					}
+				break;
+				
+			default:
+				iReader.SeekL(size);
+			}
+		}
+		
+	return EFalse;
+	}
+
+
+//
+//
+//
+void TMatroskaParser::ReadElementL(TUint64& aElementID, TInt64& aSize)
+	{
+	do
+		{
+		aElementID = ReadDataL();
+		aSize = ReadDataL(ETrue);
+
+		// Void elements are used for padding and
+		// can be ignored.
+		if (aElementID == KVoid)
+			{
+			iReader.SeekL(aSize);
+			}
+		}
+	while (aElementID == KVoid);
+	}
+
+
+//
+//
+//
+TUint64 TMatroskaParser::ReadDataL(TBool aTurnOffHighestSetBit)
+	{
+	TUint64 retval;
+	TUint8 byte;
+	TUint8 mask = 0x80; // [1000 0000]. It will be shifted right 1 in each 'i' iteration.
+	TUint8 size = 1;	// It will be incremented in each 'i' iteration.
+	
+	iReader.ReadByteL(byte);
+	
+	for (TInt i = 0; i < sizeof(TUint64); i++)
+		{
+		if (byte & mask)
+			{
+			retval = byte;
+			if (aTurnOffHighestSetBit)
+				{
+				retval &= ~mask; // Turn off the highest set bit.
+				}
+			
+			// Now read the real data.
+			// Start from 1 because we've already read a byte.
+			for (TInt j = 1; j < size; j++)
+				{
+				iReader.ReadByteL(byte);
+				retval <<= 8;
+				retval |= byte;
+				}
+				
+			return retval;
+			}
+		else
+			{
+			mask >>= 1;
+			size++;
+			}
+		}
+
+	User::Leave(KErrCorrupt);
+	return 0; // Keep the compiler happy.
+	}
+