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 +