os/mm/mmlibs/mmfw/Recogniser/src/mpeg2parser.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "parsers.h"
    17 
    18 static const TUint8 KISOEndCode = 0xB9;
    19 static const TUint8 KPackStartCode = 0xBA;
    20 static const TUint8 KVideoElementaryStream = 0xE0;
    21 
    22 #define KMPEG1PackHeaderLen		8
    23 #define KMPEG2PackHeaderLen		10
    24 
    25 #define KMPEG1PackHeaderID		0x21	// 0010xxx1. See Doc Link 2.
    26 #define KMPEG2PackHeaderID		0x44	// 01xxx1xx. See Doc Link 2.
    27 
    28 #define KStartCodeMask			0xffffff00
    29 #define KStartCodeIntro			0x00000100
    30 
    31 #define KMPEG2StartCode1Bit	KBit1
    32 #define KMPEG2StartCode2Bit	KBit2
    33 #define KMPEG2VideoBit		KBit3
    34 #define KMPEG2MPEG1Bit		KBit4
    35 
    36 //
    37 // Mapping flags to a confidence level.
    38 //
    39 // A: extension match
    40 // B: start-code1
    41 // C: start-code2
    42 //
    43 // C B A -> Confidence
    44 // -------------------
    45 // 0 0 0 -> ENotRecognised
    46 // 0 0 1 -> EPossible
    47 // 0 1 0 -> EPossible
    48 // 0 1 1 -> EProbable
    49 // 1 0 0 -> ENotRecognised
    50 // 1 0 1 -> ENotRecognised
    51 // 1 1 0 -> EProbable
    52 // 1 1 1 -> ECertain
    53 //
    54 static const TInt KMPEG2FlagsToConfidence[] =
    55 	{
    56 	KConfNotRecognised,
    57 	KConfPossible,
    58 	KConfPossible,
    59 	KConfProbable,
    60 	KConfNotRecognised,
    61 	KConfNotRecognised,
    62 	KConfProbable,
    63 	KConfCertain
    64 	};
    65 
    66 #define KMPEG2ConfidenceMask	0x07	// 00000111
    67 #define KMPEG2MimeMask	 		0x18	// 00011000
    68 #define KMPEG2MimeShift			0x03	
    69 
    70 static const TInt KMPEG2ExtOnlyIndex = 1;
    71 	
    72 //
    73 // The 'ED' bits of the flags member are used as an index into
    74 // this table of possible MIME-types.
    75 //
    76 // E: MPEG1 instead of MPEG2
    77 // D: Video content present
    78 //
    79 // E D -> Mime
    80 // -----------
    81 // 0 0 -> audio/mpeg2
    82 // 0 1 -> video/mpeg2
    83 // 1 0 -> audio/mpeg1
    84 // 1 1 -> video/mpeg1
    85 //
    86 static const TText8* const KMPEG2Mimes[] = 
    87 	{
    88 	KMimeMPEG2_A,
    89 	KMimeMPEG2_V,
    90 	KMimeMPEG1_A,
    91 	KMimeMPEG1_V
    92 	};
    93 
    94 //
    95 // A list of known MPEG2 file extensions.
    96 // MPEG1 file extensions are also listed.
    97 //
    98 typedef struct
    99 	{
   100 	const TText* iExt;
   101 	const TText8* iMime;
   102 	}
   103 TMPEG2Types;
   104 
   105 static const TMPEG2Types KMPEG2Types[] = 
   106 	{
   107 		{ KExtMPEG_1, KMimeMPEG2_V },
   108 		{ KExtMPEG_2, KMimeMPEG2_V },
   109 		{ KExtMPEG_3, KMimeMPEG2_V },
   110 		{ KExtMPEG_4, KMimeMPEG2_V },
   111 		{ KExtMPEG_5, KMimeMPEG2_V },
   112 		{ KExtMPEG_6, KMimeMPEG2_V },
   113 		{ KExtMPEG_7, KMimeMPEG1_V },
   114 		{ KExtMPEG_8, KMimeMPEG2_A }
   115 	};
   116 	
   117 #define KMPEG2ExtCount sizeof(KMPEG2Types) / sizeof(TMPEG2Types)
   118 	
   119 
   120 //
   121 //
   122 //
   123 TMPEG2Parser::TMPEG2Parser(CReader& aReader, TFlags& aFlags)
   124  :	iReader(aReader),
   125  	iFlags(aFlags)
   126 	{
   127 	}
   128 
   129 
   130 //
   131 // Match the file's extension to known MPEG2 file extensions.
   132 //
   133 const TText8* TMPEG2Parser::MatchExtension(const TDesC& aExt)
   134 	{
   135 	if (aExt.Length() > 0)
   136 		{
   137 		for (TInt i = 0; i < KMPEG2ExtCount; i++)
   138 			{
   139 			if (aExt.MatchF(TPtrC(KMPEG2Types[i].iExt)) != KErrNotFound)
   140 				{
   141 				iFlags.SetExtensionFlag();
   142 				return KMPEG2Types[i].iMime;
   143 				}
   144 			}
   145 		}
   146 	
   147 	return NULL;
   148 	}
   149 
   150 
   151 //
   152 //
   153 //
   154 void TMPEG2Parser::DoRecognise(const TDesC& aExt, CReader& aReader, TMatch& aMatch)
   155 	{
   156 	TFlags flags;
   157 	TMPEG2Parser parser(aReader, flags);
   158 	
   159 	const TText8* extMime = parser.MatchExtension(aExt);
   160 	TRAP_IGNORE(parser.ParseL());
   161 	
   162 	TInt confIndex = flags.GetBitField(KMPEG2ConfidenceMask);
   163 	aMatch.iConfidence = KMPEG2FlagsToConfidence[confIndex];
   164 	if (aMatch.iConfidence != KConfNotRecognised)
   165 		{
   166 		if (confIndex == KMPEG2ExtOnlyIndex)
   167 			{
   168 			// The content is corrupt, but the extension was recognised.
   169 			aMatch.iMime = extMime;
   170 			}
   171 		else
   172 			{
   173 			TInt mimeIndex = flags.GetBitField(KMPEG2MimeMask, KMPEG2MimeShift);
   174 			aMatch.iMime = KMPEG2Mimes[mimeIndex];
   175 			}
   176 		}
   177 	}
   178 
   179 
   180 //
   181 // Attempts to parse an MPEG2 file by looking for start-codes.
   182 //
   183 void TMPEG2Parser::ParseL()
   184 	{
   185 	TBool finished;
   186 	
   187 	// Assume there's video content if we only have a buffer.
   188 	if (iReader.Type() == CReader::EBuffer)
   189 		{
   190 		iFlags.SetBit(KMPEG2VideoBit);
   191 		}
   192 	
   193 	do
   194 		{
   195 		finished = NextStartCodeL();
   196 		}
   197 	while (!finished);
   198 	}
   199 
   200 
   201 //
   202 // Skips over the current start-code box.
   203 //
   204 void TMPEG2Parser::SkipL()
   205 	{
   206 	TUint16 size;
   207 	
   208 	iReader.Read16L(size);
   209 	iReader.SeekL((TInt)size);
   210 	}
   211 
   212 
   213 /*
   214 ** Expects an MPEG2 Pack Header at the current location.
   215 ** The Pack Header is used to determine between MPEG1 and MPEG2.
   216 */
   217 void TMPEG2Parser::ReadPackHeaderL()
   218 	{
   219 	TUint8 byte;
   220 	TBuf8<KMPEG2PackHeaderLen> header;	// Size is of whichever is larger.
   221 	
   222 	iReader.ReadByteL(byte);
   223 	
   224 	if ((byte & KMPEG1PackHeaderID) == KMPEG1PackHeaderID)
   225 		{
   226 		iFlags.SetBit(KMPEG2MPEG1Bit);
   227 		header.SetLength(KMPEG1PackHeaderLen - 1);	// We've already read a byte.
   228 		iReader.ReadBytesL(header);
   229 		}
   230 	else if ((byte & KMPEG2PackHeaderID) == KMPEG2PackHeaderID)
   231 		{
   232 		header.SetLength(KMPEG2PackHeaderLen - 1);	// We've already read a byte.
   233 		iReader.ReadBytesL(header);
   234 		
   235 		// The lowest 3 bits of the last byte say how much stuffing is present.
   236 		TInt stuffing = header[8] & 0x07; // 00000111
   237 		if (stuffing)
   238 			{
   239 			iReader.SeekL(stuffing);
   240 			}
   241 		}
   242 	else
   243 		{
   244 		User::Leave(KErrCorrupt);
   245 		}
   246 		
   247 	}
   248 
   249 //
   250 // Start codes are bit patterns that do not occur in the video stream.
   251 // The start-code sequence is expected to be at the current CReader position.
   252 //
   253 TBool TMPEG2Parser::NextStartCodeL()
   254 	{
   255 	TUint32 data;
   256 
   257 	iReader.Read32L(data);
   258 	
   259 	// Start codes must begin with 0x000001ss, where 'ss' is the start code.
   260 	if ((data & KStartCodeMask) != KStartCodeIntro)
   261 		{
   262 		User::Leave(KErrCorrupt);
   263 		}
   264 		
   265 	if (!iFlags.GetBitField(KMPEG2StartCode1Bit))
   266 		{
   267 		iFlags.SetBit(KMPEG2StartCode1Bit);
   268 		}
   269 	else
   270 		{
   271 		if (!iFlags.GetBitField(KMPEG2StartCode2Bit))
   272 			{
   273 			iFlags.SetBit(KMPEG2StartCode2Bit);
   274 			}
   275 		}
   276 		
   277 	// Try to identify the start code.
   278 	switch (LOW_BYTE(data))
   279 		{
   280 		case KPackStartCode:
   281 			ReadPackHeaderL();
   282 			break;
   283 			
   284 		case KVideoElementaryStream:
   285 			iFlags.SetBit(KMPEG2VideoBit);
   286 			return ETrue;
   287 			
   288 		case KISOEndCode:
   289 			// This code should occur at the end of the file and
   290 			// it cannot be skipped over.
   291 			return ETrue;
   292 			
   293 		default:
   294 			SkipL();
   295 		}
   296 		
   297 	return EFalse;
   298 	}
   299