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 +