--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmlibs/mmfw/Recogniser/src/mpeg2parser.cpp Thu Oct 07 22:34:12 2010 +0100
@@ -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<KMPEG2PackHeaderLen> 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;
+ }
+