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