diff -r 000000000000 -r bde4ae8d615e os/mm/mmlibs/mmfw/Recogniser/src/mpeg2parser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/mm/mmlibs/mmfw/Recogniser/src/mpeg2parser.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,299 @@ +// 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 "parsers.h" + +static const TUint8 KISOEndCode = 0xB9; +static const TUint8 KPackStartCode = 0xBA; +static const TUint8 KVideoElementaryStream = 0xE0; + +#define KMPEG1PackHeaderLen 8 +#define KMPEG2PackHeaderLen 10 + +#define KMPEG1PackHeaderID 0x21 // 0010xxx1. See Doc Link 2. +#define KMPEG2PackHeaderID 0x44 // 01xxx1xx. See Doc Link 2. + +#define KStartCodeMask 0xffffff00 +#define KStartCodeIntro 0x00000100 + +#define KMPEG2StartCode1Bit KBit1 +#define KMPEG2StartCode2Bit KBit2 +#define KMPEG2VideoBit KBit3 +#define KMPEG2MPEG1Bit KBit4 + +// +// Mapping flags to a confidence level. +// +// A: extension match +// B: start-code1 +// C: start-code2 +// +// C B A -> Confidence +// ------------------- +// 0 0 0 -> ENotRecognised +// 0 0 1 -> EPossible +// 0 1 0 -> EPossible +// 0 1 1 -> EProbable +// 1 0 0 -> ENotRecognised +// 1 0 1 -> ENotRecognised +// 1 1 0 -> EProbable +// 1 1 1 -> ECertain +// +static const TInt KMPEG2FlagsToConfidence[] = + { + KConfNotRecognised, + KConfPossible, + KConfPossible, + KConfProbable, + KConfNotRecognised, + KConfNotRecognised, + KConfProbable, + KConfCertain + }; + +#define KMPEG2ConfidenceMask 0x07 // 00000111 +#define KMPEG2MimeMask 0x18 // 00011000 +#define KMPEG2MimeShift 0x03 + +static const TInt KMPEG2ExtOnlyIndex = 1; + +// +// The 'ED' bits of the flags member are used as an index into +// this table of possible MIME-types. +// +// E: MPEG1 instead of MPEG2 +// D: Video content present +// +// E D -> Mime +// ----------- +// 0 0 -> audio/mpeg2 +// 0 1 -> video/mpeg2 +// 1 0 -> audio/mpeg1 +// 1 1 -> video/mpeg1 +// +static const TText8* const KMPEG2Mimes[] = + { + KMimeMPEG2_A, + KMimeMPEG2_V, + KMimeMPEG1_A, + KMimeMPEG1_V + }; + +// +// A list of known MPEG2 file extensions. +// MPEG1 file extensions are also listed. +// +typedef struct + { + const TText* iExt; + const TText8* iMime; + } +TMPEG2Types; + +static const TMPEG2Types KMPEG2Types[] = + { + { KExtMPEG_1, KMimeMPEG2_V }, + { KExtMPEG_2, KMimeMPEG2_V }, + { KExtMPEG_3, KMimeMPEG2_V }, + { KExtMPEG_4, KMimeMPEG2_V }, + { KExtMPEG_5, KMimeMPEG2_V }, + { KExtMPEG_6, KMimeMPEG2_V }, + { KExtMPEG_7, KMimeMPEG1_V }, + { KExtMPEG_8, KMimeMPEG2_A } + }; + +#define KMPEG2ExtCount sizeof(KMPEG2Types) / sizeof(TMPEG2Types) + + +// +// +// +TMPEG2Parser::TMPEG2Parser(CReader& aReader, TFlags& aFlags) + : iReader(aReader), + iFlags(aFlags) + { + } + + +// +// Match the file's extension to known MPEG2 file extensions. +// +const TText8* TMPEG2Parser::MatchExtension(const TDesC& aExt) + { + if (aExt.Length() > 0) + { + for (TInt i = 0; i < KMPEG2ExtCount; i++) + { + if (aExt.MatchF(TPtrC(KMPEG2Types[i].iExt)) != KErrNotFound) + { + iFlags.SetExtensionFlag(); + return KMPEG2Types[i].iMime; + } + } + } + + return NULL; + } + + +// +// +// +void TMPEG2Parser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch) + { + TFlags flags; + TMPEG2Parser parser(aReader, flags); + + const TText8* extMime = parser.MatchExtension(aExt); + TRAP_IGNORE(parser.ParseL()); + + TInt confIndex = flags.GetBitField(KMPEG2ConfidenceMask); + aMatch.iConfidence = KMPEG2FlagsToConfidence[confIndex]; + if (aMatch.iConfidence != KConfNotRecognised) + { + if (confIndex == KMPEG2ExtOnlyIndex) + { + // The content is corrupt, but the extension was recognised. + aMatch.iMime = extMime; + } + else + { + TInt mimeIndex = flags.GetBitField(KMPEG2MimeMask, KMPEG2MimeShift); + aMatch.iMime = KMPEG2Mimes[mimeIndex]; + } + } + } + + +// +// Attempts to parse an MPEG2 file by looking for start-codes. +// +void TMPEG2Parser::ParseL() + { + TBool finished; + + // Assume there's video content if we only have a buffer. + if (iReader.Type() == CReader::EBuffer) + { + iFlags.SetBit(KMPEG2VideoBit); + } + + do + { + finished = NextStartCodeL(); + } + while (!finished); + } + + +// +// Skips over the current start-code box. +// +void TMPEG2Parser::SkipL() + { + TUint16 size; + + iReader.Read16L(size); + iReader.SeekL((TInt)size); + } + + +/* +** Expects an MPEG2 Pack Header at the current location. +** The Pack Header is used to determine between MPEG1 and MPEG2. +*/ +void TMPEG2Parser::ReadPackHeaderL() + { + TUint8 byte; + TBuf8 header; // Size is of whichever is larger. + + iReader.ReadByteL(byte); + + if ((byte & KMPEG1PackHeaderID) == KMPEG1PackHeaderID) + { + iFlags.SetBit(KMPEG2MPEG1Bit); + header.SetLength(KMPEG1PackHeaderLen - 1); // We've already read a byte. + iReader.ReadBytesL(header); + } + else if ((byte & KMPEG2PackHeaderID) == KMPEG2PackHeaderID) + { + header.SetLength(KMPEG2PackHeaderLen - 1); // We've already read a byte. + iReader.ReadBytesL(header); + + // The lowest 3 bits of the last byte say how much stuffing is present. + TInt stuffing = header[8] & 0x07; // 00000111 + if (stuffing) + { + iReader.SeekL(stuffing); + } + } + else + { + User::Leave(KErrCorrupt); + } + + } + +// +// Start codes are bit patterns that do not occur in the video stream. +// The start-code sequence is expected to be at the current CReader position. +// +TBool TMPEG2Parser::NextStartCodeL() + { + TUint32 data; + + iReader.Read32L(data); + + // Start codes must begin with 0x000001ss, where 'ss' is the start code. + if ((data & KStartCodeMask) != KStartCodeIntro) + { + User::Leave(KErrCorrupt); + } + + if (!iFlags.GetBitField(KMPEG2StartCode1Bit)) + { + iFlags.SetBit(KMPEG2StartCode1Bit); + } + else + { + if (!iFlags.GetBitField(KMPEG2StartCode2Bit)) + { + iFlags.SetBit(KMPEG2StartCode2Bit); + } + } + + // Try to identify the start code. + switch (LOW_BYTE(data)) + { + case KPackStartCode: + ReadPackHeaderL(); + break; + + case KVideoElementaryStream: + iFlags.SetBit(KMPEG2VideoBit); + return ETrue; + + case KISOEndCode: + // This code should occur at the end of the file and + // it cannot be skipped over. + return ETrue; + + default: + SkipL(); + } + + return EFalse; + } +