mmlibs/mmfw/Recogniser/src/asfparser.cpp
changeset 0 b8ed18f6c07b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/Recogniser/src/asfparser.cpp	Thu Oct 07 22:34:12 2010 +0100
@@ -0,0 +1,283 @@
+// 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"
+
+#define KASFAudioMedia				"\xF8\x69\x9E\x40\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B"
+#define KASFVideoMedia				"\xBC\x19\xEF\xC0\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B"
+#define KASFHeaderObject 			"\x75\xB2\x26\x30\x66\x8E\x11\xCF\xA6\xD9\x00\xAA\x00\x62\xCE\x6C"
+#define KASFStreamPropertiesObject	"\xB7\xDC\x07\x91\xA9\xB7\x11\xCF\x8E\xE6\x00\xC0\x0C\x20\x53\x65"
+#define KASFCodecListObject			"\x86\xD1\x52\x40\x31\x1D\x11\xD0\xA3\xA4\x00\xA0\xC9\x03\x48\xF6"
+
+
+static const TInt KGUIDLen = 16; 				// 128-bit
+static const TInt KObjectLen = KGUIDLen + 8; 	// GUID followed by 64-bit size.
+static const TInt KMinObjectLen = 30; 			// From documentation
+
+
+typedef struct
+	{
+	const TText* iExt;
+	const TText8* iVideoMime;
+	const TText8* iAudioMime;
+	}
+TASFType;
+
+
+//
+// Various ASF container MIME-types.
+//
+static const TASFType KASFTypes[] =
+	{
+		{KExtWMA,	KMimeWMA,	KMimeWMA},
+		{KExtWMV,	KMimeWMV,	KMimeWMV},
+		{KExtASF,	KMimeASF_V,	KMimeASF_A}
+	};
+
+#define KASFTypesCount	sizeof(KASFTypes) / sizeof(TASFType)
+
+
+#define KASFHeaderObjectBit		KBit1	// 00000001
+#define KASFStreamHeaderBit		KBit2	// 00000010
+#define KASFVideoBit			KBit3	// 00000100
+#define KASFConfidenceMask		0x07	// 00000111
+
+//
+// Flags mapped to confidence levels.
+//
+// A: Extension identified.
+// B: HeaderObject GUID
+// C: StreamProperties GUID
+//
+// C B A -> Confidence
+// -------------------
+// 0 0 0 -> ENotRecognised
+// 0 0 1 -> EPossible
+// 0 1 0 -> EPossible
+// 0 1 1 -> EProbable
+// 1 0 0 -> ENotRecognised (StreamProperties occurs within HeaderObject)
+// 1 0 1 -> ENotRecognised (StreamProperties occurs within HeaderObject)
+// 1 1 0 -> EProbable
+// 1 1 1 -> ECertain
+//
+static const TInt KASFFlagsToConfidence[8] = 
+	{
+	KConfNotRecognised,
+	KConfPossible,
+	KConfPossible,
+	KConfProbable,
+	KConfNotRecognised,
+	KConfNotRecognised,
+	KConfProbable,
+	KConfCertain
+	};
+
+
+//
+//
+//
+TASFParser::TASFParser(CReader& aReader, TFlags& aFlags)
+ :	iReader(aReader),
+ 	iFlags(aFlags)
+	{
+	}
+
+
+//
+// Sets the mime-type the file extension implies.
+//
+const TText8* TASFParser::MatchExtension(const TDesC& aExt, TBool aVideo)
+	{
+	for (TInt i = 0; i < KASFTypesCount; i++)
+		{
+		if (aExt.MatchF(TPtrC(KASFTypes[i].iExt)) != KErrNotFound)
+			{
+			return (aVideo ? KASFTypes[i].iVideoMime : KASFTypes[i].iAudioMime);
+			}
+		}
+		
+	return NULL;
+	}
+
+
+//
+//
+//
+void TASFParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
+	{
+	TFlags flags;
+	TASFParser parser(aReader, flags);
+	
+	// We need to parse first to determine if there's video content present.
+	TRAPD(err, parser.ParseL());
+	if (err == KErrCorrupt)
+		{
+		// Unrecognised content. However the extension may allow
+		// correct identification so assume there's video content.
+		flags.SetBit(KASFVideoBit);
+		}
+		
+	const TText8* extMime = parser.MatchExtension(aExt, flags.GetBitField(KASFVideoBit));
+	if (extMime != NULL)
+		{
+		// The extension was recognised.
+		flags.SetExtensionFlag();
+		}
+		
+	TInt confIndex = flags.GetBitField(KASFConfidenceMask);
+	aMatch.iConfidence = KASFFlagsToConfidence[confIndex];
+	if (aMatch.iConfidence != KConfNotRecognised)
+		{
+		// Trust the mime-type the extension maps to.
+		// If the extension wasn't recognised, but the content was
+		// then return the generic ASF mime type. ASF format files
+		// can't be identified from their content; just whether they
+		// contain video or not.
+		aMatch.iMime = extMime;
+		if (aMatch.iMime == NULL)
+			{
+			aMatch.iMime = (flags.GetBitField(KASFVideoBit) ? KMimeASF_V : KMimeASF_A);
+			}
+		}
+	}
+
+
+//
+//
+//
+void TASFParser::ParseL()
+	{
+	// ASF files are logically composed of three types of top-level objects:
+	// the Header Object, the Data Object, and the Index Object(s).
+	// The Header Object is mandatory and must be placed at the beginning of every
+	// ASF file. The Data Object is also mandatory and must follow the Header Object.
+	// The Index Object(s) are optional, but they are useful in providing time-based
+	// random access into ASF files. When present, the Index Object(s) must be the
+	// last object in the ASF file. 
+	
+	TBuf8<KGUIDLen> guid;
+	TInt64 size;
+	const TBool useLittleEndian = ETrue;
+	
+	// Assume there's video content present if we only have buffer data.
+	if (iReader.Type() == CReader::EBuffer)
+		{
+		iFlags.SetBit(KASFVideoBit);
+		}
+		
+	ReadObjectL(guid, size);
+	if (guid == MAKE_TPtrC8(KASFHeaderObject))
+		{
+		TUint32 objectCount;
+		
+		if (size < KMinObjectLen)
+			{
+			User::Leave(KErrCorrupt);
+			}
+			
+		iFlags.SetBit(KASFHeaderObjectBit);
+		// We need to find out how many objects there are.
+		iReader.Read32L(objectCount, useLittleEndian);
+		iReader.SeekL(2); // Ignore reserved values (two bytes).
+		
+		const TDesC8& streamPropertiesGUID = MAKE_TPtrC8(KASFStreamPropertiesObject);
+		const TDesC8& videoMediaGUID = MAKE_TPtrC8(KASFVideoMedia);
+		
+		for (TInt i = 0; i < objectCount; i++)
+			{
+			ReadObjectL(guid, size);
+			
+			// We want the stream properties object.
+			if (guid == streamPropertiesGUID)
+				{
+				// There may be more than one present.
+				iFlags.SetBit(KASFStreamHeaderBit);
+				
+				ReadGUIDL(guid);
+				if (guid == videoMediaGUID)
+					{
+					iFlags.SetBit(KASFVideoBit);
+					}
+				iReader.SeekL(size - KObjectLen - KGUIDLen);
+				}
+			else
+				{
+				iReader.SeekL(size - KObjectLen);
+				}
+			}
+		}
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
+	}
+	
+//
+//
+//
+void TASFParser::ReadObjectL(TDes8& aGUID, TInt64& aSize)
+	{
+	//The base unit of organization for ASF files is called the ASF object.
+	//It consists of a 128-bit GUID for the object, a 64-bit integer object size,
+	//and the variable-length object data. The value of the object size field is
+	//the sum of 24 bytes plus the size of the object data in bytes.
+	
+	TUint32 word1;
+	TUint32 word2;
+	const TBool useLittleEndian = ETrue;
+	
+	aGUID.SetLength(KGUIDLen);
+	ReadGUIDL(aGUID);
+	
+	iReader.Read32L(word2, useLittleEndian);
+	iReader.Read32L(word1, useLittleEndian);
+	
+	aSize = MAKE_TINT64(word1, word2);
+	}
+
+
+//
+//
+//
+void TASFParser::ReadGUIDL(TDes8& aGUID)
+	{
+	TUint8 byte;
+	
+	if (aGUID.Length() != KGUIDLen)
+		{
+		User::Leave(KErrUnderflow);
+		}
+	
+	// Parts of the GUID are stored in big-endian order.
+	// They're converted to little-endian order here.
+	iReader.ReadByteL(byte);	aGUID[3] = byte;
+	iReader.ReadByteL(byte);	aGUID[2] = byte;
+	iReader.ReadByteL(byte);	aGUID[1] = byte;
+	iReader.ReadByteL(byte);	aGUID[0] = byte;
+	
+	iReader.ReadByteL(byte);	aGUID[5] = byte;
+	iReader.ReadByteL(byte);	aGUID[4] = byte;
+	
+	iReader.ReadByteL(byte);	aGUID[7] = byte;
+	iReader.ReadByteL(byte);	aGUID[6] = byte;
+	
+	for (TInt i = 8; i < KGUIDLen; i++)
+		{
+		iReader.ReadByteL(byte);
+		aGUID[i] = byte; 
+		}
+	}
+