--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gpunittest/src/tsu_3gplibrary_parse_compose.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,1410 @@
+// Copyright (c) 2008-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 "tsu_3gplibrary_parse_compose.h"
+
+const TUint16 KAudioModeSet = 0x81ff;
+const TReal KMillisecondsInSecond = 1000;
+const TReal KOneHalf = 0.5;
+const TInt KLargeFileWriteBufferSize = 16384; // 16K
+const TInt KLargeFileWriteBufferMaxCount = 15;
+
+_LIT( KAvcBaseline, "Baseline" );
+_LIT( KAvcMain, "Main" );
+_LIT( KAvcExtended, "Extended" );
+_LIT( KAvcHigh, "High" );
+
+const static TDesC* KAvcProfileNames[] = {
+ &KAvcBaseline,
+ &KAvcMain,
+ &KAvcExtended,
+ &KAvcHigh
+ };
+
+
+C3GPLibParseComposeFile::C3GPLibParseComposeFile() :
+ iCompareOriginal(EFalse),
+ iLargeFile(EFalse)
+ {
+ }
+
+TVerdict C3GPLibParseComposeFile::doTestStepPreambleL()
+ {
+ #ifdef __WINSCW__
+ _LIT(KInputDir, "inputDirEmul");
+ _LIT(KOutputDir, "outputDirEmul");
+ #else
+ _LIT(KInputDir, "inputDirHw");
+ _LIT(KOutputDir, "outputDirHw");
+ #endif
+ // ensure test always starts with clean results
+ SetTestStepResult(EPass);
+ SetTestStepError(KErrNone);
+
+ // ensure there's always a Active Scheduler for the Composer
+ if (!CActiveScheduler::Current())
+ {
+ iScheduler = new (ELeave) CActiveScheduler;
+ CActiveScheduler::Install(iScheduler);
+ }
+
+ User::LeaveIfError(iFs.Connect());
+ // retrieve the input files' directory
+ TPtrC inputFileDir;
+ TBool composeFile = EFalse;
+ TPtrC outputFileDir;
+ if (GetStringFromConfig(ConfigSection(), KInputDir, inputFileDir))
+ {
+ if (inputFileDir.Length() == 0)
+ {
+ ERR_PRINTF1(_L("Ensure input directory is specified."));
+ SetTestStepResult(EInconclusive);
+ return TestStepResult();
+ }
+ else
+ {
+ iInputDir.CreateL(inputFileDir);
+ }
+
+ GetIntFromConfig(ConfigSection(), _L("expectedFailure"), iExpectedNumberOfFailure);
+
+ if (GetBoolFromConfig(ConfigSection(), _L("composeFile"), composeFile))
+ {
+ if (composeFile)
+ {
+ if (GetStringFromConfig(ConfigSection(), KOutputDir, outputFileDir))
+ {
+ if (outputFileDir.Length() == 0)
+ {
+ ERR_PRINTF1(_L("Ensure output directory is specified."));
+ SetTestStepResult(EInconclusive);
+ return TestStepResult();
+ }
+ else if (outputFileDir == inputFileDir)
+ {
+ ERR_PRINTF1(_L("Ensure output directory is not the same as input directory."));
+ SetTestStepResult(EInconclusive);
+ return TestStepResult();
+ }
+ else if (!GetIntFromConfig(ConfigSection(), _L("fileFormat"), iFileFormat))
+ {
+ ERR_PRINTF1(_L("Ensure a output file format is specified."));
+ SetTestStepResult(EInconclusive);
+ return TestStepResult();
+ }
+
+ GetIntFromConfig(ConfigSection(), _L("composeFlag"), iComposeFlag);
+ GetBoolFromConfig(ConfigSection(), _L("compareOriginal"), iCompareOriginal);
+ GetBoolFromConfig(ConfigSection(), _L("largeFile"), iLargeFile);
+ }
+ else
+ {
+ ERR_PRINTF1(_L("Ensure output directory is specified."));
+ SetTestStepResult(EInconclusive);
+ }
+ }
+ }
+ }
+ else
+ {
+ ERR_PRINTF1(_L("Ensure input directory is specified."));
+ SetTestStepResult(EInconclusive);
+ }
+
+ if (TestStepResult() == EPass)
+ {
+ // Create a list of all files contained in the input directory
+ User::LeaveIfError(iFs.GetDir(inputFileDir, KEntryAttNormal, ESortNone, iDirList));
+
+ if (!iDirList || iDirList->Count() == 0)
+ {
+ ERR_PRINTF1(_L("Input directory is empty."));
+ SetTestStepResult(EInconclusive);
+ }
+ }
+
+ if (TestStepResult() == EPass)
+ {
+ iParser = C3GPParse::NewL();
+ if (composeFile)
+ {
+ if (iLargeFile)
+ {
+ iComposer = C3GPCompose::NewL(KLargeFileWriteBufferSize, KLargeFileWriteBufferMaxCount);
+ }
+ else
+ {
+ iComposer = C3GPCompose::NewL();
+ }
+
+ iOutputDir.CreateL(outputFileDir);
+ TInt err = iFs.MkDirAll(iOutputDir);
+ if (err != KErrNone && err != KErrAlreadyExists)
+ {
+ User::Leave(err);
+ }
+ }
+ }
+
+ return TestStepResult();
+ }
+
+TVerdict C3GPLibParseComposeFile::doTestStepL()
+ {
+ if( TestStepResult() == EPass)
+ {
+ TInt failCount = 0;
+ TInt fileCount = 0;
+ RBuf filePath;
+ CleanupClosePushL(filePath);
+ filePath.CreateL(KMaxFileName);
+
+ for (TInt i = 0; i < iDirList->Count(); i++)
+ {
+ const TEntry& entry = (*iDirList)[i];
+ if (!entry.IsDir())
+ {
+ fileCount++;
+
+ filePath.Copy(iInputDir);
+ filePath.Append(entry.iName);
+
+ INFO_PRINTF2(_L("ParseAndComposeL: file=%S"), &filePath);
+ TRAPD(err, ParseFileL(filePath));
+ INFO_PRINTF2(_L("ParseAndComposeL returns: err = %d"), err);
+ if( err != KErrNone )
+ {
+ iParser->Complete();
+ if (iComposer)
+ {
+ iComposer->Complete();
+ }
+ failCount++;
+ }
+ else
+ {
+ if (iCompareOriginal && iComposer)
+ {
+ if (!CompareInputOuputFileL(filePath))
+ {
+ ERR_PRINTF1(_L("Input & output file is not the same"));
+ failCount ++;
+ }
+ else
+ {
+ INFO_PRINTF1(_L("Input & output file is the same."));
+ }
+ }
+ }
+ }
+ }
+
+ // clean up
+ CleanupStack::PopAndDestroy(&filePath);
+
+ INFO_PRINTF3(_L("%d of %d files failed"), failCount, fileCount);
+ if (failCount != iExpectedNumberOfFailure)
+ {
+ ERR_PRINTF2(_L("Expected failure: %d - Test Failed"), iExpectedNumberOfFailure);
+ SetTestStepResult(EFail);
+ }
+ }
+
+ return TestStepResult();
+ }
+
+TVerdict C3GPLibParseComposeFile::doTestStepPostambleL()
+ {
+ if( iScheduler )
+ {
+ CActiveScheduler::Install(NULL);
+ delete iScheduler;
+ }
+
+ iOutputDir.Close();
+ iInputDir.Close();
+ iComposedFile.Close();
+
+ delete iDirList;
+
+ iParsedFileHandle64.Close();
+ iComposedFileHandle64.Close();
+ iFs.Close();
+
+ delete iParser;
+ if (iComposer)
+ {
+ delete iComposer;
+ }
+
+ return TestStepResult();
+ }
+
+void C3GPLibParseComposeFile::ParseFileL(const TDesC& aInputFile)
+ {
+ ASSERT(iParser);
+ TInt err = 0;
+
+ if (iLargeFile)
+ {
+ iParsedFileHandle64.Close();
+ err = iParsedFileHandle64.Open(iFs, aInputFile, EFileShareReadersOrWriters);
+ if (err == KErrNone)
+ {
+ err = iParser->Open(iParsedFileHandle64);
+ }
+ }
+ else
+ {
+ err = iParser->Open(aInputFile);
+ }
+
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("C3GPParse::Open() returns %d"), err);
+ User::Leave(err);
+ }
+
+ //
+ // Retrieve Video Properties
+ //
+ T3GPVideoPropertiesBase* videoProperties = NULL;
+ CleanupStack::PushL(videoProperties);
+
+ RBuf8 videoDecoderSpecificInfo;
+ CleanupClosePushL(videoDecoderSpecificInfo);
+
+ TUint videoLengthInMs = 0;
+
+ err = ParseVideoProperties(*iParser, videoDecoderSpecificInfo, videoProperties, videoLengthInMs);
+ if (err != KErrNone && err != KErrNotSupported)
+ {
+ ERR_PRINTF2(_L("ParseVideoProperties failed: err = %d"), err);
+ User::Leave(err);
+ }
+
+ //
+ // Retrieve Audio Properties
+ //
+ T3GPAudioPropertiesBase* audioProperties = NULL;
+ CleanupStack::PushL(audioProperties);
+
+ RBuf8 audioDecoderSpecificInfo;
+ CleanupClosePushL(audioDecoderSpecificInfo);
+
+ TUint audioLengthInMs = 0;
+ err = ParseAudioProperties(*iParser, audioDecoderSpecificInfo, audioProperties, audioLengthInMs);
+ if( err != KErrNone && err != KErrNotSupported)
+ {
+ ERR_PRINTF2(_L("ParseAudioProperties failed: err = %d"), err);
+ User::Leave(err);
+ }
+
+ if (!videoProperties && !audioProperties)
+ {
+ ERR_PRINTF1(_L("File contains neither video nor audio data"));
+ User::Leave(KErrNotFound);
+ }
+
+ //
+ // Prepare for the Composer if file output is expected
+ //
+ if (iComposer)
+ {
+ RBuf outputFile;
+ CleanupClosePushL(outputFile);
+
+ outputFile.CreateL(KMaxFileName);
+ outputFile.Copy(iOutputDir);
+
+ TParsePtrC parsePtr(aInputFile);
+ TPtrC name = parsePtr.NameAndExt();
+
+ outputFile.Append(parsePtr.NameAndExt());
+
+ if (iLargeFile)
+ {
+ iComposedFileHandle64.Close();
+ err = iComposedFileHandle64.Create(iFs, outputFile, EFileShareAny|EFileStream|EFileWrite);
+ if (err == KErrAlreadyExists)
+ {
+ err = iComposedFileHandle64.Replace(iFs, outputFile, EFileShareAny|EFileStream|EFileWrite);
+ }
+
+ if (err == KErrNone)
+ {
+ err = iComposer->Open((T3GPFileFormatType)iFileFormat, videoProperties, audioProperties, iComposedFileHandle64, iComposeFlag);
+ }
+ }
+ else
+ {
+ err = iComposer->Open((T3GPFileFormatType)iFileFormat, videoProperties, audioProperties, outputFile, iComposeFlag);
+ }
+
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("C3GPCompose::Open failed: err = %d"), err);
+ User::Leave(err);
+ }
+
+ CleanupStack::PopAndDestroy(&outputFile);
+ }
+
+ //
+ // Parse and compose (if specified) video / audio frame data
+ //
+ ReadWriteAudioVideoFramesL(videoProperties, audioProperties, videoLengthInMs, audioLengthInMs);
+
+ //
+ // Clean up
+ //
+ CleanupStack::PopAndDestroy(4);
+ // audioDecoderSpecificInfo
+ // audioProperties
+ // videoDecoderSpecificInfo
+ // videoProperties
+
+ if (iComposer)
+ {
+ err = iComposer->Complete();
+ if (err != KErrNone)
+ {
+ ERR_PRINTF1(_L("aComposer->Complete() failed"));
+ User::Leave(err);
+ }
+
+ if (iLargeFile)
+ {
+ iComposedFileHandle64.Close();
+ }
+ }
+
+ err = iParser->Complete();
+ if (err != KErrNone)
+ {
+ ERR_PRINTF1(_L("aParser->Complete() failed"));
+ User::Leave(err);
+ }
+
+ if (iLargeFile)
+ {
+ iParsedFileHandle64.Close();
+ }
+
+ INFO_PRINTF1(_L("C3GPLibParseComposeFile::ParseAndComposeL OUT"));
+ }
+
+void C3GPLibParseComposeFile::ReadWriteAudioVideoFramesL(const T3GPVideoPropertiesBase* aVideoProperties,
+ const T3GPAudioPropertiesBase* aAudioProperties,
+ TUint aVideoLengthInMs,
+ TUint aAudioLengthInMs)
+ {
+ ASSERT(iParser);
+
+ TUint videoLengthInTS = 0;
+ TUint audioLengthInTS = 0;
+ if (aVideoProperties)
+ {
+ // The "+KOneHalf" in the following calculation has the effect of rounding
+ // to the nearest integer instead of just flooring it when converting from
+ // TReal to TUint.
+ // This is to avoid videoLengthInTS being off by one and leading to false
+ // positives when the video properties are compared later on.
+ videoLengthInTS = (TUint) ((TReal)(aVideoLengthInMs * aVideoProperties->iTimescale) / KMillisecondsInSecond + KOneHalf );
+ }
+ if (aAudioProperties)
+ {
+ // The "+KOneHalf" in the following calculation has the effect of rounding
+ // to the nearest integer instead of just flooring it when converting from
+ // TReal to TUint.
+ // This is to avoid audioLengthInTS being off by one and leading to false
+ // positives when the audio properties are compared later on.
+ audioLengthInTS = (TUint) ((TReal)(aAudioLengthInMs * aAudioProperties->iTimescale) / KMillisecondsInSecond + KOneHalf );
+ }
+
+ TInt framePerSample1 = 0;
+ TInt framePerSample2 = 0;
+ TUint audioTS1 = 0;
+ TUint audioTS2 = 0;
+ RBuf8 audioBuf1;
+ RBuf8 audioBuf2;
+ CleanupClosePushL(audioBuf1);
+ CleanupClosePushL(audioBuf2);
+
+ TUint videoTS1;
+ TUint videoTS2;
+ TBool keyFrame1;
+ TBool keyFrame2;
+ T3GPFrameDependencies dep1;
+ T3GPFrameDependencies dep2;
+ RBuf8 videoBuf1;
+ RBuf8 videoBuf2;
+ CleanupClosePushL(videoBuf1);
+ CleanupClosePushL(videoBuf2);
+
+ TInt err = KErrNone;
+ T3GPFrameType frameType;
+
+ RArray<T3GPFrameType> frameTypeArray(10);
+ CleanupClosePushL(frameTypeArray);
+
+ TInt videoFrameCount = 0;
+ TInt audioFrameCount = 0;
+
+ while (err == KErrNone)
+ {
+ err = iParser->GetFrameType(frameType);
+ if (err == KErrNone)
+ {
+ switch(frameType)
+ {
+ case E3GPAudio:
+ audioFrameCount++;
+ frameTypeArray.AppendL(frameType);
+ err = ReadAudioFrames(*iParser, audioBuf1, framePerSample1, audioTS1);
+ audioBuf1.Close();
+ break;
+
+ case E3GPVideo:
+ videoFrameCount++;
+ frameTypeArray.AppendL(frameType);
+ err = ReadVideoFrame(*iParser, videoBuf1, keyFrame1, videoTS1, dep1);
+ videoBuf1.Close();
+ break;
+
+ default:
+ ERR_PRINTF1(_L("GetFrameType retrieves an unsupported frame type"));
+ User::Leave(KErrUnknown);
+ break;
+ }
+
+ // if there's anything wrong w/ retrieving the frame, exit the function now
+ User::LeaveIfError(err);
+ }
+ }
+
+ INFO_PRINTF2(_L("ReadWriteAudioVideoFramesL read %d video frames."), videoFrameCount);
+ INFO_PRINTF2(_L("ReadWriteAudioVideoFramesL read %d audio frames."), audioFrameCount);
+
+ // reset the video and audio cursor at the beginning of the clip
+ TUint videoPos = 0;
+ TUint audioPos = 0;
+ iParser->Seek(0, EFalse, videoPos, audioPos);
+
+ videoFrameCount = 0;
+ audioFrameCount = 0;
+
+ if (iComposer)
+ {
+ // if the data should be supplied into a composer to construct an output file
+ TInt index = 0;
+ while (index < frameTypeArray.Count())
+ {
+ frameType = frameTypeArray[index++];
+ switch (frameType)
+ {
+ case E3GPAudio:
+ if (audioBuf1.Length() == 0)
+ {
+ User::LeaveIfError(ReadAudioFrames(*iParser, audioBuf1, framePerSample1, audioTS1));
+ }
+ err = ReadAudioFrames(*iParser, audioBuf2, framePerSample2, audioTS2);
+
+ if (audioBuf1.Length() > 0 && audioBuf2.Length() > 0 ||
+ audioBuf1.Length() > 0 && err == KErrNotFound)
+ {
+ TUint duration = 0;
+ if (audioBuf2.Length() == 0)
+ {
+ // duration for the last batch of audio frames = total audio length - the 2nd last audio frame
+ duration = audioLengthInTS - audioTS1;
+ }
+ else
+ {
+ duration = audioTS2 - audioTS1;
+ }
+
+ User::LeaveIfError(iComposer->WriteAudioFrames(audioBuf1, duration));
+ audioFrameCount++;
+
+ audioBuf1.Close();
+ audioBuf1.Swap(audioBuf2);
+ framePerSample1 = framePerSample2;
+ audioTS1 = audioTS2;
+ }
+ break;
+
+ case E3GPVideo:
+ if (videoBuf1.Length() == 0)
+ {
+ User::LeaveIfError(ReadVideoFrame(*iParser, videoBuf1, keyFrame1, videoTS1, dep1));
+ }
+ err = ReadVideoFrame(*iParser, videoBuf2, keyFrame2, videoTS2, dep2);
+
+ if (videoBuf1.Length() > 0 && videoBuf2.Length() > 0 ||
+ videoBuf1.Length() > 0 && err == KErrNotFound)
+ {
+ TUint duration = 0;
+ if (videoBuf2.Length() == 0)
+ {
+ // duration for the last batch of audio frames = total audio length - the 2nd last audio frame
+ duration = videoLengthInTS - videoTS1;
+ }
+ else
+ {
+ duration = videoTS2 - videoTS1;
+ }
+
+ User::LeaveIfError(iComposer->WriteVideoFrame(videoBuf1, duration, keyFrame1, dep1));
+ videoFrameCount++;
+
+ videoBuf1.Close();
+ videoBuf1.Swap(videoBuf2);
+ keyFrame1 = keyFrame2;
+ videoTS1 = videoTS2;
+ dep1.iDependsOn = dep2.iDependsOn;
+ dep1.iIsDependedOn = dep2.iIsDependedOn;
+ dep1.iHasRedundancy = dep2.iHasRedundancy;
+ }
+ break;
+
+ default:
+ ERR_PRINTF1(_L("Unknown frame type detected."));
+ User::Leave(KErrUnknown);
+ break;
+ }
+ } // end of while loop
+ } // if (iComposer)
+
+ CleanupStack::PopAndDestroy(5);
+
+ INFO_PRINTF2(_L("ReadWriteAudioVideoFramesL wrote %d video frames."), videoFrameCount);
+ INFO_PRINTF2(_L("ReadWriteAudioVideoFramesL wrote %d audio frames."), audioFrameCount);
+ }
+
+TInt C3GPLibParseComposeFile::GetAudioDecoderSpecificInfo(RBuf8& aBuffer)
+ {
+ ASSERT(iParser);
+
+ TInt size;
+ TInt err = iParser->GetAudioDecoderSpecificInfoSize(size);
+ if( err != KErrNone )
+ {
+ ERR_PRINTF2(_L("GetAudioDecoderSpecificInfoSize() failed: %d"), err);
+ return err;
+ }
+
+ err = aBuffer.Create(size);
+ if( err != KErrNone )
+ {
+ ERR_PRINTF1(_L("Create buffer failed"));
+ return err;
+ }
+
+ err = iParser->GetAudioDecoderSpecificInfo(aBuffer);
+ if( err != KErrNone )
+ {
+ ERR_PRINTF2(_L("GetAudioDecoderSpecificInfo() failed: %d"), err);
+ }
+
+ return err;
+ }
+
+TInt C3GPLibParseComposeFile::ParseVideoProperties(C3GPParse& aParser,
+ RBuf8& aDecoderSpecificInfo,
+ T3GPVideoPropertiesBase*& aProperties,
+ TUint& aLengthInMs)
+ {
+ ASSERT(iParser);
+
+ T3GPVideoType type;
+ TReal frameRate;
+ TUint avgBitRate;
+ TSize size;
+ TUint timeScale;
+
+ TInt err = aParser.GetVideoProperties(type, aLengthInMs, frameRate, avgBitRate, size, timeScale);
+ if ((err != KErrNone) && (err != KErrNotSupported))
+ {
+ ERR_PRINTF2(_L("aParser->GetVideoProperties failed: %d"), err);
+ return err;
+ }
+
+ switch(type)
+ {
+ case E3GPMpeg4Video:
+ {
+ INFO_PRINTF1(_L("Video Type: Mpeg4"));
+ err = GetVideoDecoderSpecificInfo(aDecoderSpecificInfo);
+ if (err == KErrNone)
+ {
+ aProperties = new T3GPVideoPropertiesMpeg4Video(timeScale, size,
+ 64000, avgBitRate, aDecoderSpecificInfo);
+ if (!aProperties)
+ {
+ ERR_PRINTF1(_L("T3GPVideoPropertiesMpeg4Video allocation failed"));
+ err = KErrNoMemory;
+ }
+ }
+ break;
+ }
+
+ case E3GPAvcProfileBaseline:
+ case E3GPAvcProfileMain:
+ case E3GPAvcProfileExtended:
+ case E3GPAvcProfileHigh:
+ {
+ err = GetVideoDecoderSpecificInfo(aDecoderSpecificInfo);
+ if (err == KErrNone)
+ {
+ INFO_PRINTF2(_L("Video Type: Avc Profile %S"), KAvcProfileNames[type-E3GPAvcProfileBaseline] );
+ aProperties = new T3GPVideoPropertiesAvc(timeScale, size, aDecoderSpecificInfo);
+ if (!aProperties)
+ {
+ ERR_PRINTF1(_L("T3GPVideoPropertiesAvc allocation failed"));
+ err = KErrNoMemory;
+ }
+ else
+ {
+ // T3GPVideoPropertiesAvc defaults the video type to AVC baseline profile.
+ // Need to override that here because we want to check for the specific
+ // profile in this test.
+ aProperties->iType = type;
+ }
+ }
+ break;
+ }
+
+ case E3GPH263Profile0:
+ case E3GPH263Profile3:
+ {
+ INFO_PRINTF1(_L("Video Type: H263"));
+ T3GPVideoPropertiesH263::TProfile profile = T3GPVideoPropertiesH263::EProfile0;
+ if (type == E3GPH263Profile3)
+ {
+ profile = T3GPVideoPropertiesH263::EProfile3;
+ }
+
+ TInt videoLevel;
+ err = iParser->GetH263VideoLevel(videoLevel);
+ if( err != KErrNone )
+ {
+ ERR_PRINTF1(_L("aParser->GetH263VideoLevel() failed"));
+ }
+ else
+ {
+ aProperties = new T3GPVideoPropertiesH263(timeScale, size, videoLevel, profile);
+ if( !aProperties )
+ {
+ ERR_PRINTF1(_L("T3GPVideoPropertiesH263 allocation failed"));
+ err = KErrNoMemory;
+ }
+ }
+ break;
+ }
+
+ case E3GPNoVideo:
+ INFO_PRINTF1(_L("Video Type: None"));
+ break;
+
+ default:
+ err = KErrNotSupported;
+ break;
+ }
+
+ return err;
+ }
+
+TInt C3GPLibParseComposeFile::GetVideoDecoderSpecificInfo(RBuf8& aBuffer)
+ {
+ TInt size;
+ TInt err = iParser->GetVideoDecoderSpecificInfoSize(size);
+ if (err != KErrNone)
+ {
+ ERR_PRINTF1(_L("GetVideoDecoderSpecificInfoSize() failed"));
+ return err;
+ }
+
+ err = aBuffer.Create(size);
+ if (err != KErrNone)
+ {
+ ERR_PRINTF1(_L("Create buffer failed"));
+ return err;
+ }
+
+ err = iParser->GetVideoDecoderSpecificInfo(aBuffer);
+ if( err != KErrNone )
+ {
+ ERR_PRINTF1(_L("GetVideoDecoderSpecificInfo() failed"));
+ }
+
+ return err;
+ }
+
+TInt C3GPLibParseComposeFile::ParseAudioProperties(C3GPParse& aParser,
+ RBuf8& aAudioDecoderSpecificInfo,
+ T3GPAudioPropertiesBase*& aAudioProperties,
+ TUint& aLength)
+ {
+
+ ASSERT(iParser);
+
+ T3GPAudioType type;
+ TInt audioFPS;
+ TUint audioAvgBitRate;
+ TUint timeScale;
+
+ TInt err = aParser.GetAudioProperties(type, aLength, audioFPS, audioAvgBitRate, timeScale);
+ if(( err != KErrNone ) && ( err != KErrNotSupported ))
+ {
+ ERR_PRINTF2(_L("GetAudioProperties() failed: %d"), err);
+ return err;
+ }
+
+ switch(type)
+ {
+ case E3GPMpeg4Audio:
+ {
+ INFO_PRINTF1(_L("Audio Type: Mpeg4"));
+ err = GetAudioDecoderSpecificInfo(aAudioDecoderSpecificInfo);
+ if (err == KErrNone)
+ {
+ aAudioProperties = new T3GPAudioPropertiesMpeg4Audio(timeScale, aAudioDecoderSpecificInfo);
+ if( !aAudioProperties )
+ {
+ ERR_PRINTF1(_L("T3GPAudioPropertiesMpeg4Audio allocation failed"));
+ err = KErrNoMemory;
+ }
+ }
+ break;
+ }
+
+ case E3GPQcelp13K:
+ {
+ INFO_PRINTF1(_L("Audio Type: Qcelp13K"));
+ T3GPQcelpStorageMode mode;
+ err = iParser->GetQcelpStorageMode(mode);
+ if (err != KErrNone)
+ {
+ ERR_PRINTF1(_L("GetQcelpStorageMode failed"));
+ }
+ else
+ {
+ if( mode == E3GPMP4AudioDescriptionBox)
+ {
+ err = GetAudioDecoderSpecificInfo(aAudioDecoderSpecificInfo);
+ aAudioProperties = new T3GPAudioPropertiesQcelp(timeScale, audioFPS, aAudioDecoderSpecificInfo);
+ }
+ else
+ {
+ aAudioProperties = new T3GPAudioPropertiesQcelp(timeScale, audioFPS);
+ }
+
+ if( !aAudioProperties )
+ {
+ ERR_PRINTF1(_L("T3GPAudioPropertiesQcelp allocation failed"));
+ err = KErrNoMemory;
+ }
+ }
+ break;
+ }
+
+ case E3GPAmrNB:
+ {
+ INFO_PRINTF1(_L("Audio Type: AMR NB"));
+ aAudioProperties = new T3GPAudioPropertiesAmr(timeScale, audioFPS, KAudioModeSet, T3GPAudioPropertiesAmr::EAmrNB);
+ if( !aAudioProperties )
+ {
+ ERR_PRINTF1(_L("T3GPAudioPropertiesAmr allocation failed"));
+ err = KErrNoMemory;
+ }
+ break;
+ }
+
+ case E3GPAmrWB:
+ {
+ INFO_PRINTF1(_L("Audio Type: AMR WB"));
+ aAudioProperties = new T3GPAudioPropertiesAmr(timeScale, audioFPS, KAudioModeSet, T3GPAudioPropertiesAmr::EAmrWB);
+ if( !aAudioProperties )
+ {
+ ERR_PRINTF1(_L("T3GPAudioPropertiesAmr allocation failed"));
+ err = KErrNoMemory;
+ }
+ break;
+ }
+
+ case E3GPNoAudio:
+ INFO_PRINTF1(_L("Audio Type: None"));
+ break;
+
+ default:
+ INFO_PRINTF1(_L("Audio Type: Unrecognized!"));
+ err = KErrNotSupported;
+ break;
+ }
+
+ return err;
+ }
+
+TInt C3GPLibParseComposeFile::ReadVideoFrame(C3GPParse& aParser,
+ RBuf8& aVideoBuffer,
+ TBool& aVideoKeyFrame,
+ TUint& aVideoTimestampInTS,
+ T3GPFrameDependencies& aDependencies)
+ {
+ ASSERT(iParser);
+
+ // flush all data in the buffer
+ aVideoBuffer.Close();
+
+ TInt err = aParser.GetVideoFrameDependencies(aDependencies);
+ if (err != KErrNone)
+ {
+ aDependencies.iDependsOn = E3GPDependencyUnknown;
+ aDependencies.iIsDependedOn = E3GPDependencyUnknown;
+ aDependencies.iHasRedundancy = E3GPRedundancyUnknown;
+ }
+
+ TUint frameSize = 0;
+ err = aParser.GetVideoFrameSize(frameSize);
+ if (err == KErrNone)
+ {
+ if (frameSize > KMaxTInt / 2)
+ {
+ ERR_PRINTF1(_L("Video Frame too large!"));
+ err = KErrOverflow;
+ }
+ else
+ {
+ err = aVideoBuffer.Create((TInt)frameSize);
+ if (err == KErrNone)
+ {
+ TUint videoTimestampMS = 0;
+ err = aParser.ReadVideoFrame(aVideoBuffer, aVideoKeyFrame, videoTimestampMS, aVideoTimestampInTS);
+ if (err == KErrNone)
+ {
+ if (err == KErrNotSupported)
+ {
+ // Not supported error is OK
+ err = KErrNone;
+ }
+ else if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("GetVideoFrameDependencies failed with err = %d"), err);
+ }
+ }
+ else
+ {
+ ERR_PRINTF2(_L("ReadVideoFrame failed with err = %d"), err);
+ }
+ }
+ }
+ }
+ else
+ {
+ ERR_PRINTF2(_L("GetVideoFrameSize fails with %d"), err);
+ }
+
+ return err;
+ }
+
+TInt C3GPLibParseComposeFile::ReadAudioFrames(C3GPParse& aParser,
+ RBuf8& aBuffer,
+ TInt& aFramesInSample,
+ TUint& aTimestampInTS)
+ {
+ // flush all existing data
+ aBuffer.Close();
+
+ TUint size = 0;
+ TInt err = aParser.GetAudioFramesSize(size);
+ if (err == KErrNone)
+ {
+ if (size > KMaxTInt / 2)
+ {
+ // cannot create RBuf of size > KMaxTInt / 2
+ ERR_PRINTF1(_L("Audio Frames too large!"));
+ err = KErrOverflow;
+ }
+ else
+ {
+ err = aBuffer.Create((TInt)size);
+ if (err == KErrNone)
+ {
+ TUint audioTimestampMS = 0;
+ err = aParser.ReadAudioFrames(aBuffer, aFramesInSample, audioTimestampMS, aTimestampInTS);
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("ReadAudioFrames failed with err = %d"), err);
+ }
+ }
+ }
+ }
+ else
+ {
+ ERR_PRINTF2(_L("GetAudioFramesSize failed with err = %d"), err);
+ }
+
+ return err;
+ }
+
+TBool C3GPLibParseComposeFile::CompareInputOuputFileL(const TDesC& aInputFile)
+ {
+ ASSERT(iParser);
+ TInt err = 0;
+
+ if (iLargeFile)
+ {
+ iParsedFileHandle64.Close();
+ err = iParsedFileHandle64.Open(iFs, aInputFile, EFileShareReadersOrWriters);
+ if (err == KErrNone)
+ {
+ err = iParser->Open(iParsedFileHandle64);
+ }
+ }
+ else
+ {
+ err = iParser->Open(aInputFile);
+ }
+
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("C3GPParse 1 Open() returns %d"), err);
+ User::Leave(err);
+ }
+
+ RBuf outputFile;
+ CleanupClosePushL(outputFile);
+
+ outputFile.CreateL(KMaxFileName);
+ outputFile.Copy(iOutputDir);
+
+ TParsePtrC parsePtr(aInputFile);
+ TPtrC name = parsePtr.NameAndExt();
+ outputFile.Append(parsePtr.NameAndExt());
+
+ C3GPParse* parser2 = C3GPParse::NewL();
+ CleanupStack::PushL(parser2);
+
+ RFile64 file2;
+ if (iLargeFile)
+ {
+ err = file2.Open(iFs, outputFile, EFileShareReadersOrWriters);
+ if (err == KErrNone)
+ {
+ err = parser2->Open(file2);
+ }
+ }
+ else
+ {
+ err = parser2->Open(outputFile);
+ }
+
+ if (err != KErrNone)
+ {
+ ERR_PRINTF2(_L("C3GPParse 2 Open() returns %d"), err);
+ User::Leave(err);
+ }
+
+ TBool result = EFalse;
+ if (CompareVideoPropertiesL(*iParser, *parser2))
+ {
+ if (CompareAudioPropertiesL(*iParser, *parser2))
+ {
+ if (CompareAudioVideoData(*iParser, *parser2))
+ {
+ result = ETrue;
+ }
+ else
+ {
+ ERR_PRINTF1(_L("Audio/Video Data not matching"));
+ }
+ }
+ else
+ {
+ ERR_PRINTF1(_L("Audio Properites not matching"));
+ }
+ }
+ else
+ {
+ ERR_PRINTF1(_L("Video Properites not matching"));
+ }
+
+ parser2->Complete();
+ iParser->Complete();
+
+ if (iLargeFile)
+ {
+ file2.Close();
+ iParsedFileHandle64.Close();
+ }
+
+ CleanupStack::PopAndDestroy(2); // outputFile, parser2
+
+ return result;
+ }
+
+TBool C3GPLibParseComposeFile::CompareVideoPropertiesL(C3GPParse& aParser1,
+ C3GPParse& aParser2)
+ {
+ //
+ // Retrieve Video Properties from Parser 1
+ //
+ T3GPVideoPropertiesBase* videoProperties1 = NULL;
+ CleanupStack::PushL(videoProperties1);
+
+ RBuf8 videoDecoderSpecificInfo1;
+ CleanupClosePushL(videoDecoderSpecificInfo1);
+
+ TUint videoLengthInMs1 = 0;
+
+ TInt err1 = ParseVideoProperties(aParser1, videoDecoderSpecificInfo1, videoProperties1, videoLengthInMs1);
+ if (err1 != KErrNone && err1 != KErrNotSupported)
+ {
+ ERR_PRINTF2(_L("ParseVideoProperties 1 failed: err = %d"), err1);
+ User::Leave(err1);
+ }
+
+ //
+ // Retrieve Video Properties from Parser 2
+ //
+ T3GPVideoPropertiesBase* videoProperties2 = NULL;
+ CleanupStack::PushL(videoProperties2);
+
+ RBuf8 videoDecoderSpecificInfo2;
+ CleanupClosePushL(videoDecoderSpecificInfo2);
+
+ TUint videoLengthInMs2 = 0;
+
+ TInt err2 = ParseVideoProperties(aParser2, videoDecoderSpecificInfo2, videoProperties2, videoLengthInMs2);
+ if (err2 != KErrNone && err2 != KErrNotSupported)
+ {
+ ERR_PRINTF2(_L("ParseVideoProperties 2 failed: err = %d"), err2);
+ User::Leave(err2);
+ }
+
+ TBool result = EFalse;
+ if (err1 == err2 && err1 != KErrNotSupported)
+ {
+ if (videoLengthInMs1 == videoLengthInMs2)
+ {
+ if (videoProperties1 && videoProperties2)
+ {
+ result = (videoProperties1->iType == videoProperties2->iType) &&
+ (videoProperties1->iSize == videoProperties2->iSize) &&
+ (videoProperties1->iTimescale == videoProperties2->iTimescale);
+
+ if (result)
+ {
+ switch(videoProperties1->iType)
+ {
+ case E3GPMpeg4Video:
+ {
+ T3GPVideoPropertiesMpeg4Video* video1 = (T3GPVideoPropertiesMpeg4Video*)videoProperties1;
+ T3GPVideoPropertiesMpeg4Video* video2 = (T3GPVideoPropertiesMpeg4Video*)videoProperties2;
+
+ // NOTE: Comparison of the avg bit rate is omitted. The reason is that the avg. bit
+ // rate is calculated by:
+ // video avg bit rate = stream avg bit rate - audio avg bit rate
+ // However, stream avg. bit rate is not be properly set by the 3GP composer
+ // as it is not very important. Thus leading to the video avg. bit rate
+ // retrieved from the output file to NOT match the original.
+ result = ((video1->iMaxBitRate == video2->iMaxBitRate) &&
+ //(video1->iAvgBitRate == video2->iAvgBitRate) &&
+ (video1->iDecoderSpecificInfo == video2->iDecoderSpecificInfo));
+ break;
+ }
+
+ case E3GPAvcProfileBaseline:
+ case E3GPAvcProfileMain:
+ case E3GPAvcProfileExtended:
+ case E3GPAvcProfileHigh:
+ {
+ T3GPVideoPropertiesAvc* video1 = (T3GPVideoPropertiesAvc*)videoProperties1;
+ T3GPVideoPropertiesAvc* video2 = (T3GPVideoPropertiesAvc*)videoProperties2;
+
+ result = (video1->iDecoderSpecificInfo == video2->iDecoderSpecificInfo);
+ break;
+ }
+
+ case E3GPH263Profile0:
+ case E3GPH263Profile3:
+ {
+ T3GPVideoPropertiesH263* video1 = (T3GPVideoPropertiesH263*)videoProperties1;
+ T3GPVideoPropertiesH263* video2 = (T3GPVideoPropertiesH263*)videoProperties2;
+
+ result = (video1->iVideoLevel == video2->iVideoLevel);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (err1 == KErrNotSupported && err2 == err1)
+ {
+ result = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy(4); // videoProperties1,
+ // videoProperties2,
+ // videoDecoderSpecificInfo1,
+ // videoDecoderSpecificInfo2
+
+ return result;
+ }
+
+TBool C3GPLibParseComposeFile::CompareAudioPropertiesL(C3GPParse& aParser1,
+ C3GPParse& aParser2)
+ {
+ //
+ // Retrieve Audio Properties 1
+ //
+ T3GPAudioPropertiesBase* audioProperties1 = NULL;
+ CleanupStack::PushL(audioProperties1);
+
+ RBuf8 audioDecoderSpecificInfo1;
+ CleanupClosePushL(audioDecoderSpecificInfo1);
+
+ TUint audioLengthInMs1 = 0;
+ TInt err1 = ParseAudioProperties(aParser1, audioDecoderSpecificInfo1, audioProperties1, audioLengthInMs1);
+ if( err1 != KErrNone && err1 != KErrNotSupported)
+ {
+ ERR_PRINTF2(_L("ParseAudioProperties failed: err = %d"), err1);
+ User::Leave(err1);
+ }
+
+ //
+ // Retrieve Audio Properties 2
+ //
+ T3GPAudioPropertiesBase* audioProperties2 = NULL;
+ CleanupStack::PushL(audioProperties2);
+
+ RBuf8 audioDecoderSpecificInfo2;
+ CleanupClosePushL(audioDecoderSpecificInfo2);
+
+ TUint audioLengthInMs2 = 0;
+ TInt err2 = ParseAudioProperties(aParser2, audioDecoderSpecificInfo2, audioProperties2, audioLengthInMs2);
+ if( err2 != KErrNone && err2 != KErrNotSupported)
+ {
+ ERR_PRINTF2(_L("ParseAudioProperties failed: err = %d"), err2);
+ User::Leave(err2);
+ }
+
+ TBool result = EFalse;
+ if (err1 == err2 && err1 != KErrNotSupported)
+ {
+ if (audioLengthInMs2 == audioLengthInMs1)
+ {
+ if (audioProperties1 && audioProperties2)
+ {
+ result = (audioProperties1->iType == audioProperties2->iType) &&
+ (audioProperties1->iFramesPerSample == audioProperties2->iFramesPerSample) &&
+ (audioProperties1->iTimescale == audioProperties2->iTimescale);
+
+ if (result)
+ {
+ switch(audioProperties1->iType)
+ {
+ case E3GPMpeg4Audio:
+ {
+ T3GPAudioPropertiesMpeg4Audio* audio1 = (T3GPAudioPropertiesMpeg4Audio*) audioProperties1;
+ T3GPAudioPropertiesMpeg4Audio* audio2 = (T3GPAudioPropertiesMpeg4Audio*) audioProperties2;
+ result = (audio1->iDecoderSpecificInfo == audio2->iDecoderSpecificInfo);
+ }
+ break;
+
+ case E3GPAmrNB:
+ case E3GPAmrWB:
+ {
+ T3GPAudioPropertiesAmr* audio1 = (T3GPAudioPropertiesAmr*) audioProperties1;
+ T3GPAudioPropertiesAmr* audio2 = (T3GPAudioPropertiesAmr*) audioProperties2;
+ result = (audio1->iModeSet == audio2->iModeSet);
+ }
+ break;
+
+ case E3GPQcelp13K:
+ {
+ T3GPAudioPropertiesQcelp* audio1 = (T3GPAudioPropertiesQcelp*) audioProperties1;
+ T3GPAudioPropertiesQcelp* audio2 = (T3GPAudioPropertiesQcelp*) audioProperties2;
+ result = ((audio1->iDecoderSpecificInfo == audio2->iDecoderSpecificInfo) &&
+ (audio1->iMode == audio2->iMode));
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (err1 == KErrNotSupported && err2 == err1)
+ {
+ result = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy(4); // audioProperties1, audioProperties2, audioDecoderSpecificInfo1, audioDecoderSpecificInfo2
+
+ return result;
+ }
+
+TBool C3GPLibParseComposeFile::CompareAudioVideoData(C3GPParse& aParser1, C3GPParse& aParser2)
+ {
+ T3GPFrameType frameType1;
+ T3GPFrameType frameType2;
+ TInt err1 = KErrNone;
+ TInt err2 = KErrNone;
+ TBool keepLooping = ETrue;
+ TBool result = EFalse;
+
+ while (keepLooping)
+ {
+ err1 = aParser1.GetFrameType(frameType1);
+ err2 = aParser2.GetFrameType(frameType2);
+
+ if (err1 != err2)
+ {
+ break;
+ }
+ else
+ {
+ if (err1 == KErrNotFound)
+ {
+ // completed looping thru all the frames
+ break;
+ }
+
+ if (err1 != KErrNone)
+ {
+ // if the error is not KErrNotFound, something's wrong!
+ result = EFalse;
+ }
+ else if (frameType1 != frameType2)
+ {
+ result = EFalse;
+ }
+ else if (frameType1 == E3GPVideo)
+ {
+ result = CompareVideoFrame(aParser1, aParser2);
+ }
+ else if (frameType1 == E3GPAudio)
+ {
+ result = CompareAudioFrames(aParser1, aParser2);
+ }
+
+ if (!result)
+ {
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+TBool C3GPLibParseComposeFile::CompareVideoFrame(C3GPParse& aParser1, C3GPParse& aParser2)
+ {
+ TUint timestamp1 = 0;
+ TUint timestamp2 = 0;
+ RBuf8 buf1;
+ RBuf8 buf2;
+ TBool keyFrame1 = EFalse;
+ TBool keyFrame2 = EFalse;
+ T3GPFrameDependencies dep1;
+ T3GPFrameDependencies dep2;
+
+ TInt err1 = ReadVideoFrame(aParser1, buf1, keyFrame1, timestamp1, dep1);
+ TInt err2 = ReadVideoFrame(aParser2, buf2, keyFrame2, timestamp2, dep2);
+
+ TBool result = EFalse;
+ if (err1 == err2)
+ {
+ if (keyFrame1 == keyFrame2 && timestamp1 == timestamp2)
+ {
+ if (dep1.iDependsOn == dep2.iDependsOn &&
+ dep1.iHasRedundancy == dep2.iHasRedundancy &&
+ dep1.iIsDependedOn == dep2.iIsDependedOn)
+ {
+ if (buf1 == buf2)
+ {
+ result = ETrue;
+ }
+ else
+ {
+ result = EFalse;
+ }
+ }
+ else
+ {
+ result = EFalse;
+ }
+ }
+ else
+ {
+ result = EFalse;
+ }
+ }
+ else
+ {
+ result = EFalse;
+ }
+
+ // cleanup
+ buf1.Close();
+ buf2.Close();
+
+ return result;
+ }
+
+TBool C3GPLibParseComposeFile::CompareAudioFrames(C3GPParse& aParser1, C3GPParse& aParser2)
+ {
+ TInt fps1 = 0;
+ TInt fps2 = 0;
+ TUint timestamp1 = 0;
+ TUint timestamp2 = 0;
+ RBuf8 buf1;
+ RBuf8 buf2;
+
+ TInt err1 = ReadAudioFrames(aParser1, buf1, fps1, timestamp1);
+ TInt err2 = ReadAudioFrames(aParser2, buf2, fps2, timestamp2);
+
+ TBool result = EFalse;
+ if (err1 == err2)
+ {
+ if (fps1 == fps2 && timestamp1 == timestamp2)
+ {
+ if (buf1 == buf2)
+ {
+ result = ETrue;
+ }
+ else
+ {
+ result = EFalse;
+ }
+ }
+ else
+ {
+ result = EFalse;
+ }
+ }
+ else
+ {
+ result = EFalse;
+ }
+
+ // cleanup
+ buf1.Close();
+ buf2.Close();
+
+ return result;
+ }