os/mm/mmlibs/mmfw/Recogniser/src/matparser.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/matparser.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,352 @@
     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 +//
    1.23 +// Matroska 'XML' tags.
    1.24 +//
    1.25 +static const TUint32 KEBML = 0x1A45DFA3;
    1.26 +static const TUint32 KSegment = 0x18538067;
    1.27 +static const TUint32 KTracks = 0x1654AE6B;
    1.28 +static const TUint32 KTrackEntry = 0xAE;
    1.29 +static const TUint32 KTrackType = 0x83;
    1.30 +static const TUint32 KVoid = 0xEC;
    1.31 +static const TUint32 KSeekHead = 0x114D9B74;
    1.32 +static const TUint32 KSegmentInfo = 0x1549A966;
    1.33 +static const TUint32 KCluster = 0x1F43B675;
    1.34 +static const TUint32 KCues = 0x1C53BB6B;
    1.35 +static const TUint32 KAttachments = 0x1941A469;
    1.36 +static const TUint32 KChapters = 0x1043A770;
    1.37 +static const TUint32 KTags = 0x1254C367;
    1.38 +
    1.39 +//
    1.40 +// Matroska Track Types.
    1.41 +//
    1.42 +static const TUint8 KTrackTypeVideo = 0x01;
    1.43 +
    1.44 +#define KMatroskaConfidenceMask	0x07	// 00000111
    1.45 +#define KMatroskaEBMLBit		KBit1
    1.46 +#define KMatroskaSegmentBit		KBit2
    1.47 +#define KMatroskaVideoBit		KBit3
    1.48 +
    1.49 +
    1.50 +//
    1.51 +// This truth table maps the following flags to confidence levels.
    1.52 +//
    1.53 +// A: Extension match.
    1.54 +// B: EBML tag found.
    1.55 +// C: Segment tag found.
    1.56 +//
    1.57 +// C B A -> Confidence
    1.58 +// --------------------
    1.59 +// 0 0 0 -> NotRecognised
    1.60 +// 0 0 1 -> EPossible
    1.61 +// 0 1 0 -> EPossible
    1.62 +// 0 1 1 -> EProbable
    1.63 +// 1 0 0 -> ENotRecognised (EBML should be present)
    1.64 +// 1 0 1 -> ENotRecognised (EBML should be present)
    1.65 +// 1 1 0 -> EProbable
    1.66 +// 1 1 1 -> ECertain
    1.67 +//
    1.68 +static const TInt KMatroskaFlagsToConfidence[8] =
    1.69 +	{
    1.70 +	KConfNotRecognised,
    1.71 +	KConfPossible,
    1.72 +	KConfPossible,
    1.73 +	KConfProbable,
    1.74 +	KConfNotRecognised,
    1.75 +	KConfNotRecognised,
    1.76 +	KConfProbable,
    1.77 +	KConfCertain
    1.78 +	};
    1.79 +	
    1.80 +static const TInt KMatExtensionOnlyIndex = 1; // See truth table.
    1.81 +
    1.82 +
    1.83 +typedef struct
    1.84 +	{
    1.85 +	const TText* iExt;
    1.86 +	const TText8* iMime;
    1.87 +	}
    1.88 +TMatroskaExt;
    1.89 +
    1.90 +//
    1.91 +// Known Matroska extensions and their corresponding MIME-types.
    1.92 +//
    1.93 +static const TMatroskaExt KMatroskaExt[] =
    1.94 +	{
    1.95 +		{KExtMAT_A, KMimeMAT_A },
    1.96 +		{KExtMAT_V, KMimeMAT_V }
    1.97 +	};
    1.98 +
    1.99 +static const TInt KMatroskaExtCount = sizeof(KMatroskaExt) / sizeof(TMatroskaExt);
   1.100 +
   1.101 +
   1.102 +//
   1.103 +//
   1.104 +//
   1.105 +TMatroskaParser::TMatroskaParser(CReader& aReader, TFlags& aFlags)
   1.106 + :	iReader(aReader),
   1.107 + 	iFlags(aFlags)
   1.108 +	{
   1.109 +	}
   1.110 +
   1.111 +
   1.112 +//
   1.113 +//
   1.114 +//
   1.115 +const TText8* TMatroskaParser::MatchExtension(const TDesC& aExt)
   1.116 +	{
   1.117 +	for (TInt i = 0; i < KMatroskaExtCount; i++)
   1.118 +		{
   1.119 +		if (aExt.MatchF(TPtrC(KMatroskaExt[i].iExt)) != KErrNotFound)
   1.120 +			{
   1.121 +			return KMatroskaExt[i].iMime;
   1.122 +			}
   1.123 +		}
   1.124 +	
   1.125 +	return NULL;
   1.126 +	}
   1.127 +
   1.128 +
   1.129 +//
   1.130 +// This function calls the parser and turns the results
   1.131 +// into a MIME-type.
   1.132 +//
   1.133 +void TMatroskaParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
   1.134 +	{
   1.135 +	TFlags flags;
   1.136 +	TMatroskaParser parser(aReader, flags);
   1.137 +	
   1.138 +	// Try to match the extension.
   1.139 +	const TText8* extMime = parser.MatchExtension(aExt);
   1.140 +	if (extMime != NULL)
   1.141 +		{
   1.142 +		flags.SetExtensionFlag();
   1.143 +		}
   1.144 +
   1.145 +	// Try to parse the content.
   1.146 +	TRAP_IGNORE(parser.ParseL());
   1.147 +	TInt confIndex = flags.GetBitField(KMatroskaConfidenceMask);
   1.148 +	aMatch.iConfidence = KMatroskaFlagsToConfidence[confIndex];
   1.149 +	if (aMatch.iConfidence != KConfNotRecognised)
   1.150 +		{
   1.151 +		// If any header data has been recognised trust that,
   1.152 +		// otherwise go with the extension.
   1.153 +		if (confIndex == KMatExtensionOnlyIndex)
   1.154 +			{
   1.155 +			aMatch.iMime = extMime;
   1.156 +			}
   1.157 +		else
   1.158 +			{
   1.159 +			aMatch.iMime = (flags.GetBitField(KMatroskaVideoBit) ? KMimeMAT_V : KMimeMAT_A);
   1.160 +			}
   1.161 +		}
   1.162 +	}
   1.163 +
   1.164 +
   1.165 +//
   1.166 +// This function does the parsing.
   1.167 +//
   1.168 +void TMatroskaParser::ParseL()
   1.169 +	{
   1.170 +	TUint64 id;
   1.171 +	TInt64 size;
   1.172 +	TBool haveElement = EFalse;
   1.173 +	
   1.174 +	// Assume there's video content if we only have buffer data.
   1.175 +	if (iReader.Type() == CReader::EBuffer)
   1.176 +		{
   1.177 +		iFlags.SetBit(KMatroskaVideoBit);
   1.178 +		}
   1.179 +		
   1.180 +	FOREVER
   1.181 +		{
   1.182 +		if (!haveElement)
   1.183 +			{
   1.184 +			ReadElementL(id, size);
   1.185 +			}
   1.186 +		
   1.187 +		switch (id)
   1.188 +			{
   1.189 +			case KEBML:
   1.190 +				iFlags.SetBit(KMatroskaEBMLBit);
   1.191 +				break;
   1.192 +				
   1.193 +			case KSegment:
   1.194 +				haveElement = ReadSegmentL(id, size);
   1.195 +				break;
   1.196 +				
   1.197 +			default:
   1.198 +				// Skip it.
   1.199 +				iReader.SeekL(size);
   1.200 +			}
   1.201 +		}
   1.202 +	}
   1.203 +
   1.204 +
   1.205 +//
   1.206 +// This function returns ETrue if the aNextID and aNextSize parameters
   1.207 +// contain valid values, EFalse otherwise.
   1.208 +//
   1.209 +TBool TMatroskaParser::ReadSegmentL(TUint64& aNextID, TInt64& aNextSize)
   1.210 +	{
   1.211 +	TUint64 id;
   1.212 +	TInt64 size;
   1.213 +	TBool videoContent = EFalse;
   1.214 +	
   1.215 +	aNextID = 0;
   1.216 +	aNextSize = 0;
   1.217 +	
   1.218 +	iFlags.SetBit(KMatroskaSegmentBit);
   1.219 +	
   1.220 +	while (!videoContent)
   1.221 +		{
   1.222 +		ReadElementL(id, size);
   1.223 +		
   1.224 +		switch (id)
   1.225 +			{
   1.226 +			case KTracks:
   1.227 +				videoContent = ReadTrackL(size);
   1.228 +				break;
   1.229 +			
   1.230 +			case KSeekHead:
   1.231 +			case KSegmentInfo:
   1.232 +			case KCluster:
   1.233 +			case KCues:
   1.234 +			case KAttachments: 
   1.235 +			case KChapters:
   1.236 +			case KTags:
   1.237 +				iReader.SeekL(size);
   1.238 +				break;
   1.239 +				
   1.240 +			default:
   1.241 +				// Unrecognised element id. Pass it back to the caller
   1.242 +				aNextID = id;
   1.243 +				aNextSize = size;
   1.244 +				return ETrue;
   1.245 +			}
   1.246 +		}
   1.247 +	
   1.248 +	// Tell the caller they must read the next element themselves.
   1.249 +	return EFalse;
   1.250 +	}
   1.251 +
   1.252 +
   1.253 +//
   1.254 +// The Track. This lets us know if there's video content present.
   1.255 +//
   1.256 +TBool TMatroskaParser::ReadTrackL(TInt64 aTrackSize)
   1.257 +	{
   1.258 +	TUint64 id;
   1.259 +	TInt64 size;
   1.260 +	TInt startPos = iReader.Position();
   1.261 +	
   1.262 +	while (iReader.Position() - startPos < aTrackSize)
   1.263 +		{
   1.264 +		ReadElementL(id, size);
   1.265 +
   1.266 +		switch (id)
   1.267 +			{
   1.268 +			case KTrackEntry:
   1.269 +				break;
   1.270 +				
   1.271 +			case KTrackType:
   1.272 +				TUint8 trackType;
   1.273 +				iReader.ReadByteL(trackType);
   1.274 +				if (trackType == KTrackTypeVideo)
   1.275 +					{
   1.276 +					// We found video content so we can stop parsing.
   1.277 +					iFlags.SetBit(KMatroskaVideoBit);
   1.278 +					return ETrue;
   1.279 +					}
   1.280 +				break;
   1.281 +				
   1.282 +			default:
   1.283 +				iReader.SeekL(size);
   1.284 +			}
   1.285 +		}
   1.286 +		
   1.287 +	return EFalse;
   1.288 +	}
   1.289 +
   1.290 +
   1.291 +//
   1.292 +//
   1.293 +//
   1.294 +void TMatroskaParser::ReadElementL(TUint64& aElementID, TInt64& aSize)
   1.295 +	{
   1.296 +	do
   1.297 +		{
   1.298 +		aElementID = ReadDataL();
   1.299 +		aSize = ReadDataL(ETrue);
   1.300 +
   1.301 +		// Void elements are used for padding and
   1.302 +		// can be ignored.
   1.303 +		if (aElementID == KVoid)
   1.304 +			{
   1.305 +			iReader.SeekL(aSize);
   1.306 +			}
   1.307 +		}
   1.308 +	while (aElementID == KVoid);
   1.309 +	}
   1.310 +
   1.311 +
   1.312 +//
   1.313 +//
   1.314 +//
   1.315 +TUint64 TMatroskaParser::ReadDataL(TBool aTurnOffHighestSetBit)
   1.316 +	{
   1.317 +	TUint64 retval;
   1.318 +	TUint8 byte;
   1.319 +	TUint8 mask = 0x80; // [1000 0000]. It will be shifted right 1 in each 'i' iteration.
   1.320 +	TUint8 size = 1;	// It will be incremented in each 'i' iteration.
   1.321 +	
   1.322 +	iReader.ReadByteL(byte);
   1.323 +	
   1.324 +	for (TInt i = 0; i < sizeof(TUint64); i++)
   1.325 +		{
   1.326 +		if (byte & mask)
   1.327 +			{
   1.328 +			retval = byte;
   1.329 +			if (aTurnOffHighestSetBit)
   1.330 +				{
   1.331 +				retval &= ~mask; // Turn off the highest set bit.
   1.332 +				}
   1.333 +			
   1.334 +			// Now read the real data.
   1.335 +			// Start from 1 because we've already read a byte.
   1.336 +			for (TInt j = 1; j < size; j++)
   1.337 +				{
   1.338 +				iReader.ReadByteL(byte);
   1.339 +				retval <<= 8;
   1.340 +				retval |= byte;
   1.341 +				}
   1.342 +				
   1.343 +			return retval;
   1.344 +			}
   1.345 +		else
   1.346 +			{
   1.347 +			mask >>= 1;
   1.348 +			size++;
   1.349 +			}
   1.350 +		}
   1.351 +
   1.352 +	User::Leave(KErrCorrupt);
   1.353 +	return 0; // Keep the compiler happy.
   1.354 +	}
   1.355 +