sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "constants.h" sl@0: #include "parsers.h" sl@0: sl@0: // The length of the frame in written directly into the header. sl@0: // It is 13 bits in length and spans 3 bytes. sl@0: sl@0: #define AAC_SYNC1_MASK 0xff // 11111111 sl@0: #define AAC_SYNC2_MASK 0xf0 // 11110000 sl@0: #define AAC_FRAME_LENGTH_MASK1 0x03 // 00000011 sl@0: #define AAC_FRAME_LENGTH_MASK2 0xff // 11111111 sl@0: #define AAC_FRAME_LENGTH_MASK3 0xe0 // 11100000 sl@0: #define AAC_LAYER_MASK 0x06 // 00000110 sl@0: sl@0: #define AAC_GET_SYNC1(d) (d) sl@0: #define AAC_GET_SYNC2(d) ((d & AAC_SYNC2_MASK) >> 4) sl@0: #define AAC_GET_LAYER(d) (((d) & AAC_LAYER_MASK) >> 1) sl@0: #define AAC_GET_FRAME_LENGTH(a, b, c) \ sl@0: (((a) & AAC_FRAME_LENGTH_MASK1) << 11) | \ sl@0: (((b) & AAC_FRAME_LENGTH_MASK2) << 03) | \ sl@0: (((c) & AAC_FRAME_LENGTH_MASK3) >> 05) sl@0: sl@0: sl@0: #define AAC_IS_BAD_SYNC1(s) ((s) != 0xff) sl@0: #define AAC_IS_BAD_SYNC2(s) ((s) != 0x0f) sl@0: #define AAC_IS_BAD_LAYER(l) ((l) != 0x00) sl@0: #define AAC_IS_BAD_FRAME_LENGTH(l) ((l) < KAACFrameHeaderSize) sl@0: sl@0: // sl@0: // The various states the recognition process goes through. sl@0: // sl@0: typedef enum sl@0: { sl@0: ESearchFrame1, sl@0: ESearchFrame2 sl@0: } sl@0: TAACState; sl@0: sl@0: // sl@0: // This truth table maps the following flags to a confidence level. sl@0: // sl@0: // A: Extension identified. sl@0: // B: Frame1 found. sl@0: // C: Frame2 found. sl@0: // sl@0: // C B A -> Confidence sl@0: // =================== sl@0: // 0 0 0 -> ENotRecognised sl@0: // 0 0 1 -> EPossible sl@0: // 0 1 0 -> EProbable sl@0: // 0 1 1 -> ECertain sl@0: // 1 0 0 -> ENotRecognised (Can't have f2 without f1) sl@0: // 1 0 1 -> ENotRecognised (Can't have f2 without f1) sl@0: // 1 1 0 -> EProbable sl@0: // 1 1 1 -> ECertain sl@0: // sl@0: static const TInt KAACFlagsToConfidence[8] = sl@0: { sl@0: KConfNotRecognised, sl@0: KConfPossible, sl@0: KConfProbable, sl@0: KConfCertain, sl@0: KConfNotRecognised, sl@0: KConfNotRecognised, sl@0: KConfProbable, sl@0: KConfCertain sl@0: }; sl@0: sl@0: #define KAACConfidenceMask 0x07 // [0000 0111] sl@0: #define KAACFrame1Bit KBit1 sl@0: #define KAACFrame2Bit KBit2 sl@0: sl@0: sl@0: sl@0: // sl@0: // Constructs a TAACParser on the stack. sl@0: // sl@0: TAACParser::TAACParser(CReader& aReader, TFlags& aFlags) sl@0: : iReader(aReader), sl@0: iFlags(aFlags) sl@0: { sl@0: } sl@0: sl@0: sl@0: // sl@0: // sl@0: // sl@0: void TAACParser::DoRecognise(const TDesC& aFileExt, CReader& aReader, TMatch& aMatch) sl@0: { sl@0: TFlags flags; sl@0: TBool extMatch; sl@0: sl@0: // See if the extension is recognised. sl@0: extMatch = (aFileExt.MatchF(TPtrC(KExtAAC)) != KErrNotFound); sl@0: sl@0: // Try to match a known header. sl@0: if (aReader.Match(TPtrC8(_S8("ADIF*")))) sl@0: { sl@0: aMatch.iConfidence = (extMatch ? KConfCertain : KConfProbable); sl@0: aMatch.iMime = KMimeAAC; sl@0: return; sl@0: } sl@0: sl@0: // No known header so try to parse it. sl@0: // Parsing uses flags to track what has been identified. sl@0: if (extMatch) sl@0: { sl@0: flags.SetExtensionFlag(); sl@0: } sl@0: sl@0: TAACParser parser(aReader, flags); sl@0: TRAP_IGNORE(parser.ParseL()); sl@0: sl@0: TInt confIndex = flags.GetBitField(KAACConfidenceMask); sl@0: aMatch.iConfidence = KAACFlagsToConfidence[confIndex]; sl@0: if (aMatch.iConfidence != KConfNotRecognised) sl@0: { sl@0: aMatch.iMime = KMimeAAC; sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // Looks for valid AAC frame headers; at the current position sl@0: // and immediately after (if one found). sl@0: // sl@0: void TAACParser::ParseL() sl@0: { sl@0: TInt frameLength; sl@0: TAACState state = ESearchFrame1; sl@0: sl@0: // Check if it's an ADTS (raw) format AAC file. sl@0: // There's no known metadata tag for AAC so the sl@0: // first frame header should be at the start of the buffer. sl@0: sl@0: FOREVER sl@0: { sl@0: TID3Parser::ReadAndSkipID3L(iReader); sl@0: sl@0: TInt err = CheckForFrameHeaderL(frameLength); sl@0: if (err == KErrNotFound) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: switch (state) sl@0: { sl@0: case ESearchFrame1: sl@0: iFlags.SetBit(KAACFrame1Bit); sl@0: state = ESearchFrame2; sl@0: break; sl@0: sl@0: case ESearchFrame2: sl@0: iFlags.SetBit(KAACFrame2Bit); sl@0: return; sl@0: } sl@0: sl@0: // Skip over the audio frame. sl@0: // This should be done after flags have been set. sl@0: iReader.SeekL(frameLength - KAACFrameHeaderSize); sl@0: }; sl@0: } sl@0: sl@0: sl@0: // sl@0: // Looks for valid AAC frame header bit patterns. sl@0: // If one is not found KErrNotFound is returned and aFrameLength sl@0: // remains unchanged. If one is found KErrNone is retured and sl@0: // aFrameLength is set to the length of the frame. sl@0: // sl@0: TInt TAACParser::CheckForFrameHeaderL(TInt& aFrameLength) sl@0: { sl@0: TBuf8 header; sl@0: sl@0: header.SetLength(KAACFrameHeaderSize); sl@0: iReader.ReadBytesL(header); sl@0: sl@0: do sl@0: { sl@0: if (AAC_IS_BAD_SYNC1(AAC_GET_SYNC1(header[0]))) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: if (AAC_IS_BAD_SYNC2(AAC_GET_SYNC2(header[1]))) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: if (AAC_IS_BAD_LAYER(AAC_GET_LAYER(header[1]))) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: TInt frameLength = AAC_GET_FRAME_LENGTH(header[3], header[4], header[5]); sl@0: if (AAC_IS_BAD_FRAME_LENGTH(frameLength)) sl@0: { sl@0: break; sl@0: } sl@0: // All is ok. sl@0: aFrameLength = frameLength; sl@0: return KErrNone; sl@0: } sl@0: while (EFalse); sl@0: sl@0: // No frame header was found. sl@0: aFrameLength = 0; sl@0: iReader.SeekL(-KAACFrameHeaderSize); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: