os/mm/mmlibs/mmfw/Recogniser/src/asfparser.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "constants.h"
    17 #include "parsers.h"
    18 
    19 #define KASFAudioMedia				"\xF8\x69\x9E\x40\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B"
    20 #define KASFVideoMedia				"\xBC\x19\xEF\xC0\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B"
    21 #define KASFHeaderObject 			"\x75\xB2\x26\x30\x66\x8E\x11\xCF\xA6\xD9\x00\xAA\x00\x62\xCE\x6C"
    22 #define KASFStreamPropertiesObject	"\xB7\xDC\x07\x91\xA9\xB7\x11\xCF\x8E\xE6\x00\xC0\x0C\x20\x53\x65"
    23 #define KASFCodecListObject			"\x86\xD1\x52\x40\x31\x1D\x11\xD0\xA3\xA4\x00\xA0\xC9\x03\x48\xF6"
    24 
    25 
    26 static const TInt KGUIDLen = 16; 				// 128-bit
    27 static const TInt KObjectLen = KGUIDLen + 8; 	// GUID followed by 64-bit size.
    28 static const TInt KMinObjectLen = 30; 			// From documentation
    29 
    30 
    31 typedef struct
    32 	{
    33 	const TText* iExt;
    34 	const TText8* iVideoMime;
    35 	const TText8* iAudioMime;
    36 	}
    37 TASFType;
    38 
    39 
    40 //
    41 // Various ASF container MIME-types.
    42 //
    43 static const TASFType KASFTypes[] =
    44 	{
    45 		{KExtWMA,	KMimeWMA,	KMimeWMA},
    46 		{KExtWMV,	KMimeWMV,	KMimeWMV},
    47 		{KExtASF,	KMimeASF_V,	KMimeASF_A}
    48 	};
    49 
    50 #define KASFTypesCount	sizeof(KASFTypes) / sizeof(TASFType)
    51 
    52 
    53 #define KASFHeaderObjectBit		KBit1	// 00000001
    54 #define KASFStreamHeaderBit		KBit2	// 00000010
    55 #define KASFVideoBit			KBit3	// 00000100
    56 #define KASFConfidenceMask		0x07	// 00000111
    57 
    58 //
    59 // Flags mapped to confidence levels.
    60 //
    61 // A: Extension identified.
    62 // B: HeaderObject GUID
    63 // C: StreamProperties GUID
    64 //
    65 // C B A -> Confidence
    66 // -------------------
    67 // 0 0 0 -> ENotRecognised
    68 // 0 0 1 -> EPossible
    69 // 0 1 0 -> EPossible
    70 // 0 1 1 -> EProbable
    71 // 1 0 0 -> ENotRecognised (StreamProperties occurs within HeaderObject)
    72 // 1 0 1 -> ENotRecognised (StreamProperties occurs within HeaderObject)
    73 // 1 1 0 -> EProbable
    74 // 1 1 1 -> ECertain
    75 //
    76 static const TInt KASFFlagsToConfidence[8] = 
    77 	{
    78 	KConfNotRecognised,
    79 	KConfPossible,
    80 	KConfPossible,
    81 	KConfProbable,
    82 	KConfNotRecognised,
    83 	KConfNotRecognised,
    84 	KConfProbable,
    85 	KConfCertain
    86 	};
    87 
    88 
    89 //
    90 //
    91 //
    92 TASFParser::TASFParser(CReader& aReader, TFlags& aFlags)
    93  :	iReader(aReader),
    94  	iFlags(aFlags)
    95 	{
    96 	}
    97 
    98 
    99 //
   100 // Sets the mime-type the file extension implies.
   101 //
   102 const TText8* TASFParser::MatchExtension(const TDesC& aExt, TBool aVideo)
   103 	{
   104 	for (TInt i = 0; i < KASFTypesCount; i++)
   105 		{
   106 		if (aExt.MatchF(TPtrC(KASFTypes[i].iExt)) != KErrNotFound)
   107 			{
   108 			return (aVideo ? KASFTypes[i].iVideoMime : KASFTypes[i].iAudioMime);
   109 			}
   110 		}
   111 		
   112 	return NULL;
   113 	}
   114 
   115 
   116 //
   117 //
   118 //
   119 void TASFParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
   120 	{
   121 	TFlags flags;
   122 	TASFParser parser(aReader, flags);
   123 	
   124 	// We need to parse first to determine if there's video content present.
   125 	TRAPD(err, parser.ParseL());
   126 	if (err == KErrCorrupt)
   127 		{
   128 		// Unrecognised content. However the extension may allow
   129 		// correct identification so assume there's video content.
   130 		flags.SetBit(KASFVideoBit);
   131 		}
   132 		
   133 	const TText8* extMime = parser.MatchExtension(aExt, flags.GetBitField(KASFVideoBit));
   134 	if (extMime != NULL)
   135 		{
   136 		// The extension was recognised.
   137 		flags.SetExtensionFlag();
   138 		}
   139 		
   140 	TInt confIndex = flags.GetBitField(KASFConfidenceMask);
   141 	aMatch.iConfidence = KASFFlagsToConfidence[confIndex];
   142 	if (aMatch.iConfidence != KConfNotRecognised)
   143 		{
   144 		// Trust the mime-type the extension maps to.
   145 		// If the extension wasn't recognised, but the content was
   146 		// then return the generic ASF mime type. ASF format files
   147 		// can't be identified from their content; just whether they
   148 		// contain video or not.
   149 		aMatch.iMime = extMime;
   150 		if (aMatch.iMime == NULL)
   151 			{
   152 			aMatch.iMime = (flags.GetBitField(KASFVideoBit) ? KMimeASF_V : KMimeASF_A);
   153 			}
   154 		}
   155 	}
   156 
   157 
   158 //
   159 //
   160 //
   161 void TASFParser::ParseL()
   162 	{
   163 	// ASF files are logically composed of three types of top-level objects:
   164 	// the Header Object, the Data Object, and the Index Object(s).
   165 	// The Header Object is mandatory and must be placed at the beginning of every
   166 	// ASF file. The Data Object is also mandatory and must follow the Header Object.
   167 	// The Index Object(s) are optional, but they are useful in providing time-based
   168 	// random access into ASF files. When present, the Index Object(s) must be the
   169 	// last object in the ASF file. 
   170 	
   171 	TBuf8<KGUIDLen> guid;
   172 	TInt64 size;
   173 	const TBool useLittleEndian = ETrue;
   174 	
   175 	// Assume there's video content present if we only have buffer data.
   176 	if (iReader.Type() == CReader::EBuffer)
   177 		{
   178 		iFlags.SetBit(KASFVideoBit);
   179 		}
   180 		
   181 	ReadObjectL(guid, size);
   182 	if (guid == MAKE_TPtrC8(KASFHeaderObject))
   183 		{
   184 		TUint32 objectCount;
   185 		
   186 		if (size < KMinObjectLen)
   187 			{
   188 			User::Leave(KErrCorrupt);
   189 			}
   190 			
   191 		iFlags.SetBit(KASFHeaderObjectBit);
   192 		// We need to find out how many objects there are.
   193 		iReader.Read32L(objectCount, useLittleEndian);
   194 		iReader.SeekL(2); // Ignore reserved values (two bytes).
   195 		
   196 		const TDesC8& streamPropertiesGUID = MAKE_TPtrC8(KASFStreamPropertiesObject);
   197 		const TDesC8& videoMediaGUID = MAKE_TPtrC8(KASFVideoMedia);
   198 		
   199 		for (TInt i = 0; i < objectCount; i++)
   200 			{
   201 			ReadObjectL(guid, size);
   202 			
   203 			// We want the stream properties object.
   204 			if (guid == streamPropertiesGUID)
   205 				{
   206 				// There may be more than one present.
   207 				iFlags.SetBit(KASFStreamHeaderBit);
   208 				
   209 				ReadGUIDL(guid);
   210 				if (guid == videoMediaGUID)
   211 					{
   212 					iFlags.SetBit(KASFVideoBit);
   213 					}
   214 				iReader.SeekL(size - KObjectLen - KGUIDLen);
   215 				}
   216 			else
   217 				{
   218 				iReader.SeekL(size - KObjectLen);
   219 				}
   220 			}
   221 		}
   222 	else
   223 		{
   224 		User::Leave(KErrCorrupt);
   225 		}
   226 	}
   227 	
   228 //
   229 //
   230 //
   231 void TASFParser::ReadObjectL(TDes8& aGUID, TInt64& aSize)
   232 	{
   233 	//The base unit of organization for ASF files is called the ASF object.
   234 	//It consists of a 128-bit GUID for the object, a 64-bit integer object size,
   235 	//and the variable-length object data. The value of the object size field is
   236 	//the sum of 24 bytes plus the size of the object data in bytes.
   237 	
   238 	TUint32 word1;
   239 	TUint32 word2;
   240 	const TBool useLittleEndian = ETrue;
   241 	
   242 	aGUID.SetLength(KGUIDLen);
   243 	ReadGUIDL(aGUID);
   244 	
   245 	iReader.Read32L(word2, useLittleEndian);
   246 	iReader.Read32L(word1, useLittleEndian);
   247 	
   248 	aSize = MAKE_TINT64(word1, word2);
   249 	}
   250 
   251 
   252 //
   253 //
   254 //
   255 void TASFParser::ReadGUIDL(TDes8& aGUID)
   256 	{
   257 	TUint8 byte;
   258 	
   259 	if (aGUID.Length() != KGUIDLen)
   260 		{
   261 		User::Leave(KErrUnderflow);
   262 		}
   263 	
   264 	// Parts of the GUID are stored in big-endian order.
   265 	// They're converted to little-endian order here.
   266 	iReader.ReadByteL(byte);	aGUID[3] = byte;
   267 	iReader.ReadByteL(byte);	aGUID[2] = byte;
   268 	iReader.ReadByteL(byte);	aGUID[1] = byte;
   269 	iReader.ReadByteL(byte);	aGUID[0] = byte;
   270 	
   271 	iReader.ReadByteL(byte);	aGUID[5] = byte;
   272 	iReader.ReadByteL(byte);	aGUID[4] = byte;
   273 	
   274 	iReader.ReadByteL(byte);	aGUID[7] = byte;
   275 	iReader.ReadByteL(byte);	aGUID[6] = byte;
   276 	
   277 	for (TInt i = 8; i < KGUIDLen; i++)
   278 		{
   279 		iReader.ReadByteL(byte);
   280 		aGUID[i] = byte; 
   281 		}
   282 	}
   283