sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "constants.h" sl@0: #include "parsers.h" sl@0: sl@0: #define KASFAudioMedia "\xF8\x69\x9E\x40\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B" sl@0: #define KASFVideoMedia "\xBC\x19\xEF\xC0\x5B\x4D\x11\xCF\xA8\xFD\x00\x80\x5F\x5C\x44\x2B" sl@0: #define KASFHeaderObject "\x75\xB2\x26\x30\x66\x8E\x11\xCF\xA6\xD9\x00\xAA\x00\x62\xCE\x6C" sl@0: #define KASFStreamPropertiesObject "\xB7\xDC\x07\x91\xA9\xB7\x11\xCF\x8E\xE6\x00\xC0\x0C\x20\x53\x65" sl@0: #define KASFCodecListObject "\x86\xD1\x52\x40\x31\x1D\x11\xD0\xA3\xA4\x00\xA0\xC9\x03\x48\xF6" sl@0: sl@0: sl@0: static const TInt KGUIDLen = 16; // 128-bit sl@0: static const TInt KObjectLen = KGUIDLen + 8; // GUID followed by 64-bit size. sl@0: static const TInt KMinObjectLen = 30; // From documentation sl@0: sl@0: sl@0: typedef struct sl@0: { sl@0: const TText* iExt; sl@0: const TText8* iVideoMime; sl@0: const TText8* iAudioMime; sl@0: } sl@0: TASFType; sl@0: sl@0: sl@0: // sl@0: // Various ASF container MIME-types. sl@0: // sl@0: static const TASFType KASFTypes[] = sl@0: { sl@0: {KExtWMA, KMimeWMA, KMimeWMA}, sl@0: {KExtWMV, KMimeWMV, KMimeWMV}, sl@0: {KExtASF, KMimeASF_V, KMimeASF_A} sl@0: }; sl@0: sl@0: #define KASFTypesCount sizeof(KASFTypes) / sizeof(TASFType) sl@0: sl@0: sl@0: #define KASFHeaderObjectBit KBit1 // 00000001 sl@0: #define KASFStreamHeaderBit KBit2 // 00000010 sl@0: #define KASFVideoBit KBit3 // 00000100 sl@0: #define KASFConfidenceMask 0x07 // 00000111 sl@0: sl@0: // sl@0: // Flags mapped to confidence levels. sl@0: // sl@0: // A: Extension identified. sl@0: // B: HeaderObject GUID sl@0: // C: StreamProperties GUID sl@0: // sl@0: // C B A -> Confidence sl@0: // ------------------- sl@0: // 0 0 0 -> ENotRecognised sl@0: // 0 0 1 -> EPossible sl@0: // 0 1 0 -> EPossible sl@0: // 0 1 1 -> EProbable sl@0: // 1 0 0 -> ENotRecognised (StreamProperties occurs within HeaderObject) sl@0: // 1 0 1 -> ENotRecognised (StreamProperties occurs within HeaderObject) sl@0: // 1 1 0 -> EProbable sl@0: // 1 1 1 -> ECertain sl@0: // sl@0: static const TInt KASFFlagsToConfidence[8] = sl@0: { sl@0: KConfNotRecognised, sl@0: KConfPossible, sl@0: KConfPossible, sl@0: KConfProbable, sl@0: KConfNotRecognised, sl@0: KConfNotRecognised, sl@0: KConfProbable, sl@0: KConfCertain sl@0: }; sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: TASFParser::TASFParser(CReader& aReader, TFlags& aFlags) sl@0: : iReader(aReader), sl@0: iFlags(aFlags) sl@0: { sl@0: } sl@0: sl@0: sl@0: // sl@0: // Sets the mime-type the file extension implies. sl@0: // sl@0: const TText8* TASFParser::MatchExtension(const TDesC& aExt, TBool aVideo) sl@0: { sl@0: for (TInt i = 0; i < KASFTypesCount; i++) sl@0: { sl@0: if (aExt.MatchF(TPtrC(KASFTypes[i].iExt)) != KErrNotFound) sl@0: { sl@0: return (aVideo ? KASFTypes[i].iVideoMime : KASFTypes[i].iAudioMime); sl@0: } sl@0: } sl@0: sl@0: return NULL; sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: void TASFParser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch) sl@0: { sl@0: TFlags flags; sl@0: TASFParser parser(aReader, flags); sl@0: sl@0: // We need to parse first to determine if there's video content present. sl@0: TRAPD(err, parser.ParseL()); sl@0: if (err == KErrCorrupt) sl@0: { sl@0: // Unrecognised content. However the extension may allow sl@0: // correct identification so assume there's video content. sl@0: flags.SetBit(KASFVideoBit); sl@0: } sl@0: sl@0: const TText8* extMime = parser.MatchExtension(aExt, flags.GetBitField(KASFVideoBit)); sl@0: if (extMime != NULL) sl@0: { sl@0: // The extension was recognised. sl@0: flags.SetExtensionFlag(); sl@0: } sl@0: sl@0: TInt confIndex = flags.GetBitField(KASFConfidenceMask); sl@0: aMatch.iConfidence = KASFFlagsToConfidence[confIndex]; sl@0: if (aMatch.iConfidence != KConfNotRecognised) sl@0: { sl@0: // Trust the mime-type the extension maps to. sl@0: // If the extension wasn't recognised, but the content was sl@0: // then return the generic ASF mime type. ASF format files sl@0: // can't be identified from their content; just whether they sl@0: // contain video or not. sl@0: aMatch.iMime = extMime; sl@0: if (aMatch.iMime == NULL) sl@0: { sl@0: aMatch.iMime = (flags.GetBitField(KASFVideoBit) ? KMimeASF_V : KMimeASF_A); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: void TASFParser::ParseL() sl@0: { sl@0: // ASF files are logically composed of three types of top-level objects: sl@0: // the Header Object, the Data Object, and the Index Object(s). sl@0: // The Header Object is mandatory and must be placed at the beginning of every sl@0: // ASF file. The Data Object is also mandatory and must follow the Header Object. sl@0: // The Index Object(s) are optional, but they are useful in providing time-based sl@0: // random access into ASF files. When present, the Index Object(s) must be the sl@0: // last object in the ASF file. sl@0: sl@0: TBuf8 guid; sl@0: TInt64 size; sl@0: const TBool useLittleEndian = ETrue; sl@0: sl@0: // Assume there's video content present if we only have buffer data. sl@0: if (iReader.Type() == CReader::EBuffer) sl@0: { sl@0: iFlags.SetBit(KASFVideoBit); sl@0: } sl@0: sl@0: ReadObjectL(guid, size); sl@0: if (guid == MAKE_TPtrC8(KASFHeaderObject)) sl@0: { sl@0: TUint32 objectCount; sl@0: sl@0: if (size < KMinObjectLen) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: sl@0: iFlags.SetBit(KASFHeaderObjectBit); sl@0: // We need to find out how many objects there are. sl@0: iReader.Read32L(objectCount, useLittleEndian); sl@0: iReader.SeekL(2); // Ignore reserved values (two bytes). sl@0: sl@0: const TDesC8& streamPropertiesGUID = MAKE_TPtrC8(KASFStreamPropertiesObject); sl@0: const TDesC8& videoMediaGUID = MAKE_TPtrC8(KASFVideoMedia); sl@0: sl@0: for (TInt i = 0; i < objectCount; i++) sl@0: { sl@0: ReadObjectL(guid, size); sl@0: sl@0: // We want the stream properties object. sl@0: if (guid == streamPropertiesGUID) sl@0: { sl@0: // There may be more than one present. sl@0: iFlags.SetBit(KASFStreamHeaderBit); sl@0: sl@0: ReadGUIDL(guid); sl@0: if (guid == videoMediaGUID) sl@0: { sl@0: iFlags.SetBit(KASFVideoBit); sl@0: } sl@0: iReader.SeekL(size - KObjectLen - KGUIDLen); sl@0: } sl@0: else sl@0: { sl@0: iReader.SeekL(size - KObjectLen); sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // sl@0: // sl@0: void TASFParser::ReadObjectL(TDes8& aGUID, TInt64& aSize) sl@0: { sl@0: //The base unit of organization for ASF files is called the ASF object. sl@0: //It consists of a 128-bit GUID for the object, a 64-bit integer object size, sl@0: //and the variable-length object data. The value of the object size field is sl@0: //the sum of 24 bytes plus the size of the object data in bytes. sl@0: sl@0: TUint32 word1; sl@0: TUint32 word2; sl@0: const TBool useLittleEndian = ETrue; sl@0: sl@0: aGUID.SetLength(KGUIDLen); sl@0: ReadGUIDL(aGUID); sl@0: sl@0: iReader.Read32L(word2, useLittleEndian); sl@0: iReader.Read32L(word1, useLittleEndian); sl@0: sl@0: aSize = MAKE_TINT64(word1, word2); sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: void TASFParser::ReadGUIDL(TDes8& aGUID) sl@0: { sl@0: TUint8 byte; sl@0: sl@0: if (aGUID.Length() != KGUIDLen) sl@0: { sl@0: User::Leave(KErrUnderflow); sl@0: } sl@0: sl@0: // Parts of the GUID are stored in big-endian order. sl@0: // They're converted to little-endian order here. sl@0: iReader.ReadByteL(byte); aGUID[3] = byte; sl@0: iReader.ReadByteL(byte); aGUID[2] = byte; sl@0: iReader.ReadByteL(byte); aGUID[1] = byte; sl@0: iReader.ReadByteL(byte); aGUID[0] = byte; sl@0: sl@0: iReader.ReadByteL(byte); aGUID[5] = byte; sl@0: iReader.ReadByteL(byte); aGUID[4] = byte; sl@0: sl@0: iReader.ReadByteL(byte); aGUID[7] = byte; sl@0: iReader.ReadByteL(byte); aGUID[6] = byte; sl@0: sl@0: for (TInt i = 8; i < KGUIDLen; i++) sl@0: { sl@0: iReader.ReadByteL(byte); sl@0: aGUID[i] = byte; sl@0: } sl@0: } sl@0: