os/mm/mmlibs/mmfw/Recogniser/src/asfparser.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/mm/mmlibs/mmfw/Recogniser/src/asfparser.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,283 @@
     1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "constants.h"
    1.20 +#include "parsers.h"
    1.21 +
    1.22 +#define KASFAudioMedia				"\xF8\x69\x9E\x40\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B"
    1.23 +#define KASFVideoMedia				"\xBC\x19\xEF\xC0\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B"
    1.24 +#define KASFHeaderObject 			"\x75\xB2\x26\x30\x66\x8E\x11\xCF\xA6\xD9\x00\xAA\x00\x62\xCE\x6C"
    1.25 +#define KASFStreamPropertiesObject	"\xB7\xDC\x07\x91\xA9\xB7\x11\xCF\x8E\xE6\x00\xC0\x0C\x20\x53\x65"
    1.26 +#define KASFCodecListObject			"\x86\xD1\x52\x40\x31\x1D\x11\xD0\xA3\xA4\x00\xA0\xC9\x03\x48\xF6"
    1.27 +
    1.28 +
    1.29 +static const TInt KGUIDLen = 16; 				// 128-bit
    1.30 +static const TInt KObjectLen = KGUIDLen + 8; 	// GUID followed by 64-bit size.
    1.31 +static const TInt KMinObjectLen = 30; 			// From documentation
    1.32 +
    1.33 +
    1.34 +typedef struct
    1.35 +	{
    1.36 +	const TText* iExt;
    1.37 +	const TText8* iVideoMime;
    1.38 +	const TText8* iAudioMime;
    1.39 +	}
    1.40 +TASFType;
    1.41 +
    1.42 +
    1.43 +//
    1.44 +// Various ASF container MIME-types.
    1.45 +//
    1.46 +static const TASFType KASFTypes[] =
    1.47 +	{
    1.48 +		{KExtWMA,	KMimeWMA,	KMimeWMA},
    1.49 +		{KExtWMV,	KMimeWMV,	KMimeWMV},
    1.50 +		{KExtASF,	KMimeASF_V,	KMimeASF_A}
    1.51 +	};
    1.52 +
    1.53 +#define KASFTypesCount	sizeof(KASFTypes) / sizeof(TASFType)
    1.54 +
    1.55 +
    1.56 +#define KASFHeaderObjectBit		KBit1	// 00000001
    1.57 +#define KASFStreamHeaderBit		KBit2	// 00000010
    1.58 +#define KASFVideoBit			KBit3	// 00000100
    1.59 +#define KASFConfidenceMask		0x07	// 00000111
    1.60 +
    1.61 +//
    1.62 +// Flags mapped to confidence levels.
    1.63 +//
    1.64 +// A: Extension identified.
    1.65 +// B: HeaderObject GUID
    1.66 +// C: StreamProperties GUID
    1.67 +//
    1.68 +// C B A -> Confidence
    1.69 +// -------------------
    1.70 +// 0 0 0 -> ENotRecognised
    1.71 +// 0 0 1 -> EPossible
    1.72 +// 0 1 0 -> EPossible
    1.73 +// 0 1 1 -> EProbable
    1.74 +// 1 0 0 -> ENotRecognised (StreamProperties occurs within HeaderObject)
    1.75 +// 1 0 1 -> ENotRecognised (StreamProperties occurs within HeaderObject)
    1.76 +// 1 1 0 -> EProbable
    1.77 +// 1 1 1 -> ECertain
    1.78 +//
    1.79 +static const TInt KASFFlagsToConfidence[8] = 
    1.80 +	{
    1.81 +	KConfNotRecognised,
    1.82 +	KConfPossible,
    1.83 +	KConfPossible,
    1.84 +	KConfProbable,
    1.85 +	KConfNotRecognised,
    1.86 +	KConfNotRecognised,
    1.87 +	KConfProbable,
    1.88 +	KConfCertain
    1.89 +	};
    1.90 +
    1.91 +
    1.92 +//
    1.93 +//
    1.94 +//
    1.95 +TASFParser::TASFParser(CReader& aReader, TFlags& aFlags)
    1.96 + :	iReader(aReader),
    1.97 + 	iFlags(aFlags)
    1.98 +	{
    1.99 +	}
   1.100 +
   1.101 +
   1.102 +//
   1.103 +// Sets the mime-type the file extension implies.
   1.104 +//
   1.105 +const TText8* TASFParser::MatchExtension(const TDesC& aExt, TBool aVideo)
   1.106 +	{
   1.107 +	for (TInt i = 0; i < KASFTypesCount; i++)
   1.108 +		{
   1.109 +		if (aExt.MatchF(TPtrC(KASFTypes[i].iExt)) != KErrNotFound)
   1.110 +			{
   1.111 +			return (aVideo ? KASFTypes[i].iVideoMime : KASFTypes[i].iAudioMime);
   1.112 +			}
   1.113 +		}
   1.114 +		
   1.115 +	return NULL;
   1.116 +	}
   1.117 +
   1.118 +
   1.119 +//
   1.120 +//
   1.121 +//
   1.122 +void TASFParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
   1.123 +	{
   1.124 +	TFlags flags;
   1.125 +	TASFParser parser(aReader, flags);
   1.126 +	
   1.127 +	// We need to parse first to determine if there's video content present.
   1.128 +	TRAPD(err, parser.ParseL());
   1.129 +	if (err == KErrCorrupt)
   1.130 +		{
   1.131 +		// Unrecognised content. However the extension may allow
   1.132 +		// correct identification so assume there's video content.
   1.133 +		flags.SetBit(KASFVideoBit);
   1.134 +		}
   1.135 +		
   1.136 +	const TText8* extMime = parser.MatchExtension(aExt, flags.GetBitField(KASFVideoBit));
   1.137 +	if (extMime != NULL)
   1.138 +		{
   1.139 +		// The extension was recognised.
   1.140 +		flags.SetExtensionFlag();
   1.141 +		}
   1.142 +		
   1.143 +	TInt confIndex = flags.GetBitField(KASFConfidenceMask);
   1.144 +	aMatch.iConfidence = KASFFlagsToConfidence[confIndex];
   1.145 +	if (aMatch.iConfidence != KConfNotRecognised)
   1.146 +		{
   1.147 +		// Trust the mime-type the extension maps to.
   1.148 +		// If the extension wasn't recognised, but the content was
   1.149 +		// then return the generic ASF mime type. ASF format files
   1.150 +		// can't be identified from their content; just whether they
   1.151 +		// contain video or not.
   1.152 +		aMatch.iMime = extMime;
   1.153 +		if (aMatch.iMime == NULL)
   1.154 +			{
   1.155 +			aMatch.iMime = (flags.GetBitField(KASFVideoBit) ? KMimeASF_V : KMimeASF_A);
   1.156 +			}
   1.157 +		}
   1.158 +	}
   1.159 +
   1.160 +
   1.161 +//
   1.162 +//
   1.163 +//
   1.164 +void TASFParser::ParseL()
   1.165 +	{
   1.166 +	// ASF files are logically composed of three types of top-level objects:
   1.167 +	// the Header Object, the Data Object, and the Index Object(s).
   1.168 +	// The Header Object is mandatory and must be placed at the beginning of every
   1.169 +	// ASF file. The Data Object is also mandatory and must follow the Header Object.
   1.170 +	// The Index Object(s) are optional, but they are useful in providing time-based
   1.171 +	// random access into ASF files. When present, the Index Object(s) must be the
   1.172 +	// last object in the ASF file. 
   1.173 +	
   1.174 +	TBuf8<KGUIDLen> guid;
   1.175 +	TInt64 size;
   1.176 +	const TBool useLittleEndian = ETrue;
   1.177 +	
   1.178 +	// Assume there's video content present if we only have buffer data.
   1.179 +	if (iReader.Type() == CReader::EBuffer)
   1.180 +		{
   1.181 +		iFlags.SetBit(KASFVideoBit);
   1.182 +		}
   1.183 +		
   1.184 +	ReadObjectL(guid, size);
   1.185 +	if (guid == MAKE_TPtrC8(KASFHeaderObject))
   1.186 +		{
   1.187 +		TUint32 objectCount;
   1.188 +		
   1.189 +		if (size < KMinObjectLen)
   1.190 +			{
   1.191 +			User::Leave(KErrCorrupt);
   1.192 +			}
   1.193 +			
   1.194 +		iFlags.SetBit(KASFHeaderObjectBit);
   1.195 +		// We need to find out how many objects there are.
   1.196 +		iReader.Read32L(objectCount, useLittleEndian);
   1.197 +		iReader.SeekL(2); // Ignore reserved values (two bytes).
   1.198 +		
   1.199 +		const TDesC8& streamPropertiesGUID = MAKE_TPtrC8(KASFStreamPropertiesObject);
   1.200 +		const TDesC8& videoMediaGUID = MAKE_TPtrC8(KASFVideoMedia);
   1.201 +		
   1.202 +		for (TInt i = 0; i < objectCount; i++)
   1.203 +			{
   1.204 +			ReadObjectL(guid, size);
   1.205 +			
   1.206 +			// We want the stream properties object.
   1.207 +			if (guid == streamPropertiesGUID)
   1.208 +				{
   1.209 +				// There may be more than one present.
   1.210 +				iFlags.SetBit(KASFStreamHeaderBit);
   1.211 +				
   1.212 +				ReadGUIDL(guid);
   1.213 +				if (guid == videoMediaGUID)
   1.214 +					{
   1.215 +					iFlags.SetBit(KASFVideoBit);
   1.216 +					}
   1.217 +				iReader.SeekL(size - KObjectLen - KGUIDLen);
   1.218 +				}
   1.219 +			else
   1.220 +				{
   1.221 +				iReader.SeekL(size - KObjectLen);
   1.222 +				}
   1.223 +			}
   1.224 +		}
   1.225 +	else
   1.226 +		{
   1.227 +		User::Leave(KErrCorrupt);
   1.228 +		}
   1.229 +	}
   1.230 +	
   1.231 +//
   1.232 +//
   1.233 +//
   1.234 +void TASFParser::ReadObjectL(TDes8& aGUID, TInt64& aSize)
   1.235 +	{
   1.236 +	//The base unit of organization for ASF files is called the ASF object.
   1.237 +	//It consists of a 128-bit GUID for the object, a 64-bit integer object size,
   1.238 +	//and the variable-length object data. The value of the object size field is
   1.239 +	//the sum of 24 bytes plus the size of the object data in bytes.
   1.240 +	
   1.241 +	TUint32 word1;
   1.242 +	TUint32 word2;
   1.243 +	const TBool useLittleEndian = ETrue;
   1.244 +	
   1.245 +	aGUID.SetLength(KGUIDLen);
   1.246 +	ReadGUIDL(aGUID);
   1.247 +	
   1.248 +	iReader.Read32L(word2, useLittleEndian);
   1.249 +	iReader.Read32L(word1, useLittleEndian);
   1.250 +	
   1.251 +	aSize = MAKE_TINT64(word1, word2);
   1.252 +	}
   1.253 +
   1.254 +
   1.255 +//
   1.256 +//
   1.257 +//
   1.258 +void TASFParser::ReadGUIDL(TDes8& aGUID)
   1.259 +	{
   1.260 +	TUint8 byte;
   1.261 +	
   1.262 +	if (aGUID.Length() != KGUIDLen)
   1.263 +		{
   1.264 +		User::Leave(KErrUnderflow);
   1.265 +		}
   1.266 +	
   1.267 +	// Parts of the GUID are stored in big-endian order.
   1.268 +	// They're converted to little-endian order here.
   1.269 +	iReader.ReadByteL(byte);	aGUID[3] = byte;
   1.270 +	iReader.ReadByteL(byte);	aGUID[2] = byte;
   1.271 +	iReader.ReadByteL(byte);	aGUID[1] = byte;
   1.272 +	iReader.ReadByteL(byte);	aGUID[0] = byte;
   1.273 +	
   1.274 +	iReader.ReadByteL(byte);	aGUID[5] = byte;
   1.275 +	iReader.ReadByteL(byte);	aGUID[4] = byte;
   1.276 +	
   1.277 +	iReader.ReadByteL(byte);	aGUID[7] = byte;
   1.278 +	iReader.ReadByteL(byte);	aGUID[6] = byte;
   1.279 +	
   1.280 +	for (TInt i = 8; i < KGUIDLen; i++)
   1.281 +		{
   1.282 +		iReader.ReadByteL(byte);
   1.283 +		aGUID[i] = byte; 
   1.284 +		}
   1.285 +	}
   1.286 +