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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 #include "constants.h"
21 // Some (most) brands have Release information - e.g. 3gp6, 3gp5 etc.
22 // Therefore, to match the brand, we only look at the characters that don't
23 // represent Release information (in the above case, the 4th character).
24 // The Release character is set to zero.
26 static const TUint32 KMP4Brand = MAKE_INT32('m', 'p', '4', 0);
27 static const TUint32 K3GPBrand = MAKE_INT32('3', 'g', 'p', 0);
28 static const TUint32 K3G2Brand = MAKE_INT32('3', 'g', '2', 0);
29 static const TUint32 K3GSBrand = MAKE_INT32('3', 'g', 's', 0); // Streaming servers.
30 static const TUint32 K3GRBrand = MAKE_INT32('3', 'g', 'r', 0); // Progresive download and MMS.
31 static const TUint32 KQTBrand = MAKE_INT32('q', 't', ' ', ' '); // for quicktime
35 static const TUint32 KFtyp = MAKE_INT32('f', 't', 'y', 'p');
36 static const TUint32 KMoov = MAKE_INT32('m', 'o', 'o', 'v');
37 static const TUint32 KTrak = MAKE_INT32('t', 'r', 'a', 'k');
38 static const TUint32 KTkhd = MAKE_INT32('t', 'k', 'h', 'd');
39 static const TUint32 KMdia = MAKE_INT32('m', 'd', 'i', 'a');
40 static const TUint32 KHdlr = MAKE_INT32('h', 'd', 'l', 'r');
41 static const TUint32 KVide = MAKE_INT32('v', 'i', 'd', 'e');
42 static const TUint32 KUuid = MAKE_INT32('u', 'u', 'i', 'd');
46 // This truth table maps the following flags to a confidence level.
48 // A - trak box present
49 // B - moov box present
58 static const TInt KMPEG4FlagsToConfidence[] =
67 #define KMPEG4ConfidenceMask 0x03 // 00000011
68 #define KMPEG4BoxTitleLen 4
69 #define KMPEG4TRAKBit KBit0 // 00000001
70 #define KMPEG4MOOVBit KBit1 // 00000010
71 #define KMPEG4VideoBit KBit2 // 00000100
73 static const TInt KMPEG4BoxIntroLen = 8;
74 static const TInt KMPEG4Box64BitIntroLen = 16;
77 // In order to find out the type of MPEG4 file it is
78 // we need to be able to map known extensions, expected
79 // ftyp expressions with MIME-types.
85 const TText8* iAudioMime;
86 const TText8* iVideoMime;
92 // A table of ftyp's, extensions and mime-types.
94 // .mp4 - can contain either audio or video.
95 // .m4a - should contain (unprotected) audio only.
96 // .m4p - should contain protected audio only.
97 // .3gp - can contain either audio or video.
99 static const TMPEG4File KMPEG4Files[] =
101 {KExtMP4, KMP4Brand, KMimeMP4_A, KMimeMP4_V},
102 {KExt3GP, K3GPBrand, KMime3GP_A, KMime3GP_V},
103 {KExtM4A, KMP4Brand, KMimeMP4_A, NULL},
104 {KExt3G2, K3G2Brand, KMime3G2_A, KMime3G2_V},
105 {KExt3GP, K3GSBrand, KMime3GP_A, KMime3GP_V},
106 {KExt3GP, K3GRBrand, KMime3GP_A, KMime3GP_V},
107 {KExt3GA, K3GPBrand, KMime3GA, NULL},
108 {KExtMOV, KQTBrand, NULL, KMimeQuickV} // this entry is for .mov files
111 static const TInt KMPEG4FileTypeCount = sizeof(KMPEG4Files) / sizeof(TMPEG4File);
117 TMPEG4Parser::TMPEG4Parser(CReader& aReader, TFlags& aFlags)
118 : iBrandIndex(KErrNotFound),
122 iVideoAssumed(EFalse)
128 // Compare a brand with the ones this recogniser knows about.
130 TInt TMPEG4Parser::IsCompatibleBrand(TUint32 aBrand, TInt aStartPos)
132 for (TInt i = aStartPos; i < KMPEG4FileTypeCount; i++)
134 TUint32 knownBrand = KMPEG4Files[i].iBrand;
135 if ((aBrand & knownBrand) == knownBrand)
146 // Try to determine the mime-type from the extension, and
147 // if that isn't matched, from the FTYP field if present.
148 // If none of these are matched, NULL is returned and the
149 // file isn't a valid MPEG4 file.
151 const TText8* TMPEG4Parser::MatchFileType(const TDesC& aExt)
153 TBool videoFound = iFlags.GetBitField(KMPEG4VideoBit);
154 TBool video = (videoFound || iVideoAssumed);
156 // Try to match the extension.
157 if (aExt.Length() > 0)
159 for (TInt i = 0; i < KMPEG4FileTypeCount; i++)
161 TPtrC ext(KMPEG4Files[i].iExt);
162 if (aExt.MatchF(ext) != KErrNotFound)
164 // Extension match. If the extension is for an audio-only format
165 // we must make sure there is no video content in the file. If
166 // video content is present then ignore the extension match.
167 if (KMPEG4Files[i].iVideoMime == NULL)
171 // Try to match another extension.
175 return KMPEG4Files[i].iAudioMime;
178 return (video ? KMPEG4Files[i].iVideoMime : KMPEG4Files[i].iAudioMime);
183 // Unknown or no extension. Try to match the brand
184 while (iBrandIndex != KErrNotFound)
186 if (KMPEG4Files[iBrandIndex].iVideoMime == NULL)
190 // Try to match another brand.
191 TUint32 brand = KMPEG4Files[iBrandIndex].iBrand;
192 iBrandIndex = TMPEG4Parser::IsCompatibleBrand(brand, iBrandIndex + 1);
196 return KMPEG4Files[iBrandIndex].iAudioMime;
199 return (video ? KMPEG4Files[iBrandIndex].iVideoMime : KMPEG4Files[iBrandIndex].iAudioMime);
202 // If there is no brand and an unknown extension look at the flags.
203 // (There are some files that have no ftyp).
204 // Only return a potential mime-type if all flag bits have been set.
205 if (iFlags.GetBitField(KMPEG4ConfidenceMask) == KMPEG4ConfidenceMask)
207 return (video ? KMimeMP4_V : KMimeMP4_A);
217 void TMPEG4Parser::DoRecognise(const TDesC& aFileExt, CReader& aReader, TMatch& aMatch)
220 TMPEG4Parser parser(aReader, flags);
222 TRAP_IGNORE(parser.ParseL());
224 // The extension determines the mime-type.
225 // The flags say if it's a valid MPEG4 file and if video is present.
226 const TText8* extMime = parser.MatchFileType(aFileExt);
229 TInt confIndex = flags.GetBitField(KMPEG4ConfidenceMask);
230 aMatch.iConfidence = KMPEG4FlagsToConfidence[confIndex];
231 if (aMatch.iConfidence != KConfNotRecognised)
233 aMatch.iMime = extMime;
242 void TMPEG4Parser::ParseL()
244 // If we have only buffer data, we must assume the video
245 // content (if any) has been missed. This is because an
246 // audio-only file recognised as video should play in a
247 // video application, but a video file recognised as audio
248 // will not play in a audio application.
249 if (iReader.Type() == CReader::EBuffer)
251 iVideoAssumed = ETrue;
261 else if (iTitle == KMoov)
263 iFlags.SetBit(KMPEG4MOOVBit);
271 while (!iIsFinished);
278 void TMPEG4Parser::SkipCurrentBoxL()
280 // Intro: [size][title] = 8 bytes.
284 // The current box extends to the end of file.
290 iReader.SeekL(iSize - KMPEG4BoxIntroLen);
294 iReader.SeekL(iSize - KMPEG4Box64BitIntroLen);
300 // Parses the 'moov' box.
301 // This box contains sub-boxes we're interested in.
303 void TMPEG4Parser::ReadMovieL()
305 // This box holds no information.
306 // It contains 'trak' boxes, which we want.
308 TInt64 dataInBox = iSize - KMPEG4BoxIntroLen;
310 while ((dataInBox > 0) && !iIsFinished)
317 iFlags.SetBit(KMPEG4TRAKBit);
329 // Parses the 'trak' box.
330 // This box contains sub-boxes we're interested in.
332 void TMPEG4Parser::ReadTrackL()
334 // This box holds no information.
335 // It contains 'tkhd' boxes, which we want.
337 TInt64 dataInBox = iSize - KMPEG4BoxIntroLen;
339 while ((dataInBox > 0) && !iIsFinished)
348 else if (iTitle == KMdia)
360 // Parses a 'mdia' box.
361 // This box contains sub-boxes we're interested in.
363 void TMPEG4Parser::ReadMediaL()
365 TInt64 dataInBox = iSize - KMPEG4BoxIntroLen;
367 while ((dataInBox > 0) && !iIsFinished)
385 // Parses a 'hdlr' box.
386 // This is a stand-alone box.
388 void TMPEG4Parser::ReadHandlerL()
390 // Intro: [size][title][versionFlags][predefined][handler_type] = 20 bytes.
391 const TInt KMPEG4HandlerIntroLen = 20;
392 TUint32 versionFlags;
396 iReader.Read32L(versionFlags);
397 iReader.Read32L(predefined);
400 User::Leave(KErrCorrupt);
403 iReader.Read32L(handler);
404 if (handler == KVide)
406 iFlags.SetBit(KMPEG4VideoBit);
409 iReader.SeekL(iSize - KMPEG4HandlerIntroLen);
416 void TMPEG4Parser::ReadTrackHeaderL()
418 const TUint8 KMPEG4TrackVersion0 = 0;
419 const TUint8 KMPEG4TrackVersion1 = 1;
420 const TInt KMPEG4Version0ToVolume = 32; // Distance to volume field from version=0 field.
421 const TInt KMPEG4Version1ToVolume = 44; // Distance to volume field from version=1 field.
422 const TInt KMPEG4VolumeToWidth = 38; // Distance to width field from volume field.
424 TUint32 versionFlags;
429 // This box contains information about a single track.
430 iReader.Read32L(versionFlags);
432 // The highest 8 bits contains the version.
433 switch (HIGH_BYTE32(versionFlags))
435 case KMPEG4TrackVersion0:
436 iReader.SeekL(KMPEG4Version0ToVolume);
439 case KMPEG4TrackVersion1:
440 iReader.SeekL(KMPEG4Version1ToVolume);
444 User::Leave(KErrCorrupt);
447 // Volume can not be used to distinguish between audio and video anymore.
448 iReader.Read16L(volume);
450 // We want to seek ahead to read the 'width' and 'height' fields.
451 iReader.SeekL(KMPEG4VolumeToWidth);
453 iReader.Read32L(width); // 16.16 fixed-point
454 iReader.Read32L(height); // 16.16 fixed-point
455 if ((width != 0) && (height != 0))
457 iFlags.SetBit(KMPEG4VideoBit);
463 // Parses the 'ftyp' box.
464 // Records the first recognised brand that helps to
465 // identify the mime-type.
467 void TMPEG4Parser::ReadFileTypeL()
469 // Intro = [size][title][majorBrand] = 12 bytes.
470 const TInt KMPEG4FtypIntroLen = 12;
473 // If the majorBrand isn't recognised we should also
474 // search the compatible brand list.
475 TInt64 bytesRemaining = iSize - KMPEG4FtypIntroLen;
476 //here there should be bytes remaining. Otherwise we cant read.
477 if( bytesRemaining <0 )
479 User::Leave(KErrCorrupt);
482 iReader.Read32L(brand);
483 iBrandIndex = TMPEG4Parser::IsCompatibleBrand(brand);
484 if (iBrandIndex != KErrNotFound)
486 // The major brand was recognised.
487 // Skip to the end of the ftyp box.
488 iReader.SeekL(bytesRemaining);
492 // The major brand wasn't recognised.
493 // Skip over the version info (32 bit) to the start of the
494 // compatible brands list.
495 TInt skip = sizeof(TUint32);
497 bytesRemaining -= skip;
499 while ((iBrandIndex == KErrNotFound) && (bytesRemaining > 0))
501 iReader.Read32L(brand);
502 bytesRemaining -= skip;
503 iBrandIndex = TMPEG4Parser::IsCompatibleBrand(brand);
506 iReader.SeekL(bytesRemaining);
511 // Reads the first few bytes of a box.
512 // The exact amount read depends on the box.
514 void TMPEG4Parser::ReadBoxHeaderL()
516 const TInt KMPEG4ExtendedTypeLen = 16;
520 iReader.Read32L(word1);
521 iReader.Read32L(iTitle);
526 // Box extends to the end of file.
527 iSize = MAKE_TINT64(0, 0);
531 // Size is specified in a 64-bit field.
532 iSizeIn32bit = EFalse;
533 iReader.Read64L(iSize);
537 // It's an actual 32-bit size.
538 iSizeIn32bit = ETrue;
539 iSize = MAKE_TINT64(0, word1);
544 // Skip the extended type.
545 iReader.SeekL(KMPEG4ExtendedTypeLen);