videoeditorengine/vedengine/videoprocessor/src/mp4parser.cpp
changeset 0 951a5db380a0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/vedengine/videoprocessor/src/mp4parser.cpp	Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,1264 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "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:
+* Ixonos Plc
+*
+* Description:  
+*
+*/
+
+
+
+// INCLUDE FILES
+
+#include    "movieprocessorimpl.h"
+#include    "mp4parser.h"
+#include    "vedvideosettings.h"
+#include    "vedaudiosettings.h"
+#include    "vedvolreader.h"
+#include    "vedavcedit.h"
+
+// ASSERTIONS
+#define MPASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CMovieProcessorImpl"), EInternalAssertionFailure))
+
+#ifdef _DEBUG
+#include <e32svr.h>
+#define PRINT(x) RDebug::Print x;
+#else
+#define PRINT(x)
+#endif
+
+// LOCAL CONSTANTS AND MACROS
+#ifdef _DEBUG
+const TInt KErrorCode = CParser::EParserFailure;
+#else
+const TInt KErrorCode = KErrGeneral;
+#endif
+
+//const TUint KNumFramesInOneRun = 10;
+const TUint KVOLHeaderBufferSize = 256;
+const TUint KAVCDCRBufferSize = 1024;
+const TUint KMinBitrate = 128;
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+
+CMP4Parser::CMP4Parser()
+{       
+	iMP4Handle = 0;
+	iVideoType = 0;
+	iAudioType = 0; 
+	iBytesRead = 0;
+	iFirstRead = ETrue;		// added for Mp4
+	iFirstFrameInfo = ETrue;  // added for Mp4
+	iOutputNumberOfFrames = 0; 
+    iStreamSource = ESourceNone;
+	iFrameNumber=0;
+	iFirstTimeClipParsing=ETrue;
+    iStartFrameIndex=0;		
+}
+
+// Two-phased constructor.
+
+CMP4Parser* CMP4Parser::NewL(CMovieProcessorImpl* aProcessor, const TDesC &aFileName)
+{
+	CMP4Parser *self = new (ELeave) CMP4Parser;
+	CleanupStack::PushL(self);    
+	
+	if ( aFileName.Length() > 0 )   
+		self->iStreamSource = ESourceFile;
+	else
+		self->iStreamSource = ESourceUser;
+	
+	self->ConstructL(aProcessor,aFileName);
+
+	CleanupStack::Pop();  // self
+	
+	return self;
+}
+
+CMP4Parser* CMP4Parser::NewL(CMovieProcessorImpl* aProcessor, RFile* aFileHandle)
+{
+	CMP4Parser *self = new (ELeave) CMP4Parser;
+	CleanupStack::PushL(self);    
+	
+	self->iStreamSource = ESourceFile;	
+	
+	self->ConstructL(aProcessor,aFileHandle);
+
+	CleanupStack::Pop();  // self
+	
+	return self;
+}
+
+// Symbian OS default constructor can leave.
+
+void CMP4Parser::ConstructL(CMovieProcessorImpl* aProcessor, const TDesC &aFileName)
+{
+	MP4Err error;
+	iProcessor = aProcessor; 
+
+	// open MP4 library
+    if ( iStreamSource == ESourceFile )
+        {        
+        TBuf<258> temp(aFileName);
+        temp.ZeroTerminate();			
+
+        MP4FileName name = reinterpret_cast<MP4FileName>( const_cast<TUint16*>(temp.Ptr()) );
+
+        error = MP4ParseOpen(&iMP4Handle, name);
+        if ( error == MP4_OK )
+            {
+            // set buffer sizes; only parser buffer size is effective for this instance
+            error = MP4SetCustomFileBufferSizes(iMP4Handle, K3gpMp4ComposerWriteBufferSize, K3gpMp4ComposerNrOfWriteBuffers, K3gpMp4ParserReadBufferSize );
+            }
+        }
+    else
+        {
+        // buffer
+        error = MP4ParseOpen(&iMP4Handle, 0);        
+        }        
+		
+    if (error == MP4_OUT_OF_MEMORY)
+        {
+        User::Leave(KErrNoMemory);
+        }
+    else if ( error != MP4_OK )
+        {
+        User::Leave(KErrorCode);
+		}
+}
+
+void CMP4Parser::ConstructL(CMovieProcessorImpl* aProcessor, RFile* aFileHandle)
+{
+	MP4Err error;
+	iProcessor = aProcessor;
+
+	// open MP4 library
+    error = MP4ParseOpenFileHandle(&iMP4Handle, aFileHandle);
+    
+    if ( error == MP4_OK )
+        {
+        // set buffer sizes; only parser buffer size is effective for this instance
+        error = MP4SetCustomFileBufferSizes(iMP4Handle, K3gpMp4ComposerWriteBufferSize, K3gpMp4ComposerNrOfWriteBuffers, K3gpMp4ParserReadBufferSize );
+        }
+        
+    if (error == MP4_OUT_OF_MEMORY)
+        {
+        User::Leave(KErrNoMemory);
+        }
+    else if ( error != MP4_OK )
+        {
+        User::Leave(KErrorCode);
+		}
+}
+
+// Destructor
+CMP4Parser::~CMP4Parser()
+{
+    if (iMP4Handle)
+        MP4ParseClose(iMP4Handle);
+
+    iMP4Handle = 0;
+}
+
+
+
+// ---------------------------------------------------------
+// CMP4Parser::WriteDataBlockL
+// Write a block of data to parser
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+TInt CMP4Parser::WriteDataBlock(const TDes8& aBlock)
+{               
+	
+	MPASSERT(iStreamSource != ESourceFile);    
+	MP4Err error = MP4ParseWriteData(iMP4Handle, (mp4_u8*)(aBlock.Ptr()), mp4_u32(aBlock.Length()) );
+	
+	if ( error == MP4_OUT_OF_MEMORY )
+		return KErrNoMemory;
+	else if ( error == MP4_ERROR )
+		return KErrorCode;
+    else
+        return KErrNone;
+	
+}
+
+// ---------------------------------------------------------
+// CMP4Parser::GetNextFrameInformation
+// Get type (streaming-case), length and availability of next frame to be fetched
+// using MP4 library API functions
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+TInt CMP4Parser::GetNextFrameInformation(TFrameType& aType, TUint& aLength, TBool& aIsAvailable)
+{   
+	
+	// If aType == EFrameTypeNone, the type of next frame is retrieved 
+	// (valid only in streaming case)
+	// Otherwise, only the length of next specified type of frame is retrieved
+	MPASSERT(iStreamSource != ESourceNone);            
+	
+	mp4_u32 type = MP4_TYPE_NONE;
+	MP4Err error;
+
+	aIsAvailable = 0;    
+	if ( iNextFrameType == EFrameTypeNone )
+		// if the mp4 library is reading a file, a frame has always been read when 
+		// we come here
+		// otherwise it might be that a complete frame was not available yet
+		// and we come here to ask again        
+	{
+		if ( aType == EFrameTypeNone ) 
+		{
+			MPASSERT(iStreamSource == ESourceUser);
+			
+			// get next frame type
+			error = MP4ParseNextFrameType(iMP4Handle, &type);
+
+			if ( error == MP4_NOT_AVAILABLE )
+				return KErrNone;                
+			else if ( error == MP4_NO_FRAME )                
+				return EParserEndOfStream; // no video or audio frames left, stream ended
+			else if ( error == MP4_INVALID_INPUT_STREAM )
+				return KErrCorrupt;
+			else if ( error != MP4_OK )
+				return KErrorCode;
+            else
+            {
+                MPASSERT(error == MP4_OK);
+            }
+			
+			switch ( type ) 
+			{
+			case MP4_TYPE_H263_PROFILE_0:
+		    case MP4_TYPE_MPEG4_VIDEO:
+          
+				MPASSERT( type == iVideoType );
+				iNextFrameType = EFrameTypeVideo;         
+				break;
+				
+			case MP4_TYPE_AMR_NB:
+				MPASSERT( type == iAudioType );
+				iNextFrameType = EFrameTypeAudio;                    
+				break;        
+
+			default:
+				return KErrNotSupported;
+			}
+		}
+		else 
+		{
+			// library reads the file            
+			//MPASSERT(iStreamSource == ESourceFile);
+			type = ( aType == EFrameTypeVideo ) ? iVideoType : iAudioType;
+			iNextFrameType = aType;
+		}
+		
+		// get length for the frame
+		mp4_u32 length = 0, mp4Specific = 0;
+		MPASSERT( type != MP4_TYPE_NONE );
+		if ( (iFirstFrameInfo) &&
+		     ((iVideoType == MP4_TYPE_MPEG4_VIDEO) || (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)) ) 		   
+		{
+			error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific );
+			iFirstFrameInfo = EFalse;
+		}
+		error = MP4ParseNextFrameSize(iMP4Handle, type, &length);
+		MPASSERT( error != MP4_NOT_AVAILABLE );
+		
+		if ( length == 0 || error == MP4_NO_REQUESTED_FRAME )
+		{            
+			// file-reading case: all frames of this type have been read
+			//   and the caller should try with the other type
+			MPASSERT( length == 0 );
+			iNextFrameType = EFrameTypeNone;
+			aLength = 0;            
+			return KErrNone;            
+		}
+		else if ( error == MP4_INVALID_INPUT_STREAM )
+			return KErrCorrupt;
+		else if ( error != MP4_OK )
+			return KErrorCode;
+       else if ( length > iMaxVideoFrameLength )
+            {
+            PRINT((_L("CMP4Parser::GetNextFrameInformation() too large video frame size %d, return KErrCorrupt"),length));
+			return KErrCorrupt;
+            }
+        else
+            iNextFrameLength = TUint(length + mp4Specific);
+
+	}
+	MPASSERT(iNextFrameType != EFrameTypeNone);
+	MPASSERT(iNextFrameLength != 0);
+	
+	// check if frame is available
+	if ( iStreamSource == ESourceUser )
+	{
+		error = MP4ParseIsFrameAvailable(iMP4Handle, type);
+		if ( error != MP4_OK && error != MP4_NOT_AVAILABLE )
+			return KErrorCode;
+		aIsAvailable = ( error == MP4_NOT_AVAILABLE ) ? EFalse : ETrue;
+	}
+	else 
+		aIsAvailable = ETrue;
+	
+	aType = iNextFrameType;
+	aLength = iNextFrameLength;	
+	
+	return KErrNone;
+}   
+
+// ---------------------------------------------------------
+// CMP4Parser::ReadFrames
+// Read the next frame(s) from file / stream
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+TInt CMP4Parser::ReadFrames(TDes8& aDstBuffer, TFrameType aType, TUint32& aNumRead, 
+														TUint32& aTimeStamp)
+{
+	MP4Err error;
+	mp4_u32 returnedSize = 0;    
+	mp4_bool keyFrame = 0;
+
+	MPASSERT( iNextFrameType != EFrameTypeNone && aType == iNextFrameType ); 
+	MPASSERT( iNextFrameLength != 0 );
+
+#ifdef _DEBUG
+	mp4_u32 type = MP4_TYPE_NONE; // buffer support
+	type = ( aType == EFrameTypeVideo ) ? iVideoType : iAudioType; // buffer support
+	if (iStreamSource == ESourceUser)
+		MPASSERT( MP4ParseIsFrameAvailable(iMP4Handle, type) == MP4_OK );
+#endif
+
+
+	if (aType == EFrameTypeVideo) 
+	{	
+		TUint32 iTimeStampInTicks=0;
+		mp4_u32 mp4Specific = 0;
+
+		if ( (iFirstRead) &&
+		     ((iVideoType == MP4_TYPE_MPEG4_VIDEO) || (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)) ) 		   
+		{
+			error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr() + aDstBuffer.Length()), 
+				mp4_u32( aDstBuffer.MaxLength() ), &mp4Specific );
+			iFirstRead = EFalse;
+		}
+		
+		error = MP4ParseReadVideoFrame(iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr() + aDstBuffer.Length()+ mp4Specific), 
+			mp4_u32( aDstBuffer.MaxLength() ), &returnedSize, (mp4_u32*)&aTimeStamp,
+			&keyFrame, &iTimeStampInTicks);					    
+
+		returnedSize += mp4Specific;
+		iFrameNumber++;
+		aNumRead = 1;
+	}
+	else 
+	{       
+		error = MP4ParseReadAudioFrames(iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr()), 
+			mp4_u32(aDstBuffer.MaxLength()), &returnedSize, (mp4_u32*)&aTimeStamp, 
+			(mp4_u32*)&aNumRead, NULL);               
+		
+		//PRINT((_L("audio TS:%d, "), aTimeStamp));
+	}
+	
+	MPASSERT(error != MP4_BUFFER_TOO_SMALL);    
+	aDstBuffer.SetLength(aDstBuffer.Length() + TInt(returnedSize));
+	iBytesRead += returnedSize;
+	iNextFrameType = EFrameTypeNone;
+	iNextFrameLength = 0;
+		
+	//PRINT((_L("error=%d, numReturned=%d, returnedSize=%d, bufferSize=%d\n"), 
+	//	error, aNumRead, returnedSize, aDstBuffer.MaxLength()));
+		
+	if (error == MP4_NOT_AVAILABLE)
+		return EParserNotEnoughData;    
+	else if ( error == MP4_INVALID_INPUT_STREAM )
+		return KErrCorrupt;
+	else if ( error != MP4_OK )
+		return KErrorCode;
+    else
+        return KErrNone;
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::Reset
+// Resets the parser to its initial state
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+TInt CMP4Parser::Reset()
+{
+	MP4Err error;
+	
+	if ( iStreamSource == ESourceFile )
+	{
+		mp4_u32 audioPos, videoPos;
+		
+		// seek to very beginning
+		error = MP4ParseSeek(iMP4Handle, 0, &audioPos, &videoPos, EFalse);
+		if ( error != MP4_OK )
+			return KErrorCode;
+		
+		MPASSERT( videoPos == 0 && (iAudioType == 0 || audioPos == 0) );		
+		
+	}
+	else 
+	{
+		// close & open library to make sure old data is flushed
+		error = MP4ParseClose(iMP4Handle);
+		
+		if ( error != MP4_OK )
+			return KErrorCode;
+		error = MP4ParseOpen(&iMP4Handle, 0);
+		if ( error != MP4_OK )
+			return KErrorCode;                    
+	}
+	
+	iBytesRead = 0;
+	iNextFrameType = EFrameTypeNone;
+	iNextFrameLength = 0;
+	
+	return KErrNone;
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::ParseHeaderL
+// Get relevant stream parameters by calling mp4 library functions
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+TInt CMP4Parser::ParseHeaderL(CParser::TStreamParameters& aStreamParameters)
+{
+
+    PRINT((_L("CMP4Parser::ParseHeaderL() begin")));
+
+	MP4Err error;
+	mp4_double frameRate = 0;    
+	TBool hasVideo = ETrue;
+	
+	// Reset channel info
+	aStreamParameters.iHaveVideo = EFalse;
+	aStreamParameters.iHaveAudio = EFalse;
+	aStreamParameters.iNumDemuxChannels = 0;
+	aStreamParameters.iFileFormat = EFileFormatUnrecognized;
+	aStreamParameters.iVideoFormat = EVideoFormatNone;
+	aStreamParameters.iAudioFormat = EAudioFormatNone;
+	aStreamParameters.iVideoLength = 0;
+	aStreamParameters.iAudioLength = 0;
+	aStreamParameters.iStreamLength = 0;
+	aStreamParameters.iAudioFramesInSample = 0;
+	aStreamParameters.iVideoPicturePeriodNsec = 0;
+	aStreamParameters.iCanSeek = EFalse;
+	aStreamParameters.iFrameRate=0;
+	aStreamParameters.iVideoTimeScale=0; 
+	aStreamParameters.iAudioTimeScale=0; 
+	iAudioType = 0;
+	iVideoType = 0;
+	iNumberOfFrames=0;
+	
+	// get video description
+	error = MP4ParseRequestVideoDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iVideoLength,
+		&frameRate, &iVideoType, (mp4_u32 *)&aStreamParameters.iVideoWidth, 
+		(mp4_u32 *)&aStreamParameters.iVideoHeight, (mp4_u32 *)&aStreamParameters.iVideoTimeScale);
+
+	if ( error == MP4_NOT_AVAILABLE )
+		User::Leave(KErrorCode);
+	else if ( error == MP4_INVALID_INPUT_STREAM )
+		User::Leave(KErrCorrupt);
+	else if ( error == MP4_NO_VIDEO )  
+	{
+		hasVideo = EFalse;
+		aStreamParameters.iVideoWidth = aStreamParameters.iVideoHeight = 0;
+	}
+	else if ( error != MP4_OK )
+		User::Leave(KErrorCode);
+    else
+    {
+        MPASSERT(error == MP4_OK);
+    }
+
+	// get audio description. ask also for averagebitrate to get error if the track is empty; the information is needed later on
+    mp4_u32 averagebitrate = 0;
+
+	error = MP4ParseRequestAudioDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iAudioLength, 
+		&iAudioType, (mp4_u8*)&aStreamParameters.iAudioFramesInSample, (mp4_u32 *)&aStreamParameters.iAudioTimeScale, &averagebitrate );
+
+    if ( (error == MP4_ERROR) && ((iAudioType == MP4_TYPE_MPEG4_AUDIO) || (iAudioType == MP4_TYPE_AMR_NB) || (iAudioType == MP4_TYPE_AMR_WB)))
+        {
+        // a special case: there may be audio track but it is empty; if type was recognized, mark as no audio
+        PRINT((_L("CMP4Parser::ParseHeaderL() problems with getting audio description, mark no audio since audio type was recognized")));
+        iAudioType = MP4_NO_AUDIO;
+        error = MP4_NO_AUDIO;
+        }
+	if(error == MP4_NOT_AVAILABLE)     
+		User::Leave(EParserNotEnoughData);        
+	else if ( error == MP4_INVALID_INPUT_STREAM )
+		User::Leave(KErrCorrupt);
+	else if ( error != MP4_NO_AUDIO && error != MP4_OK )
+		User::Leave(KErrorCode);
+    else
+    {
+        MPASSERT(error == MP4_OK || error == MP4_NO_AUDIO);
+    }
+
+    // store the sample size for sanity checking purposes
+    iMaxAMRSampleSize = KVedMaxAMRFrameSize * aStreamParameters.iAudioFramesInSample;
+
+	if (aStreamParameters.iVideoLength > 0)
+		aStreamParameters.iStreamLength = aStreamParameters.iVideoLength;
+
+	if (aStreamParameters.iAudioLength > aStreamParameters.iVideoLength)
+		aStreamParameters.iStreamLength = aStreamParameters.iAudioLength;	
+	
+	aStreamParameters.iFrameRate = frameRate;
+
+	if(hasVideo)
+	{
+		    
+	    if ( iVideoType == MP4_TYPE_MPEG4_VIDEO )
+	    {
+	        // read video resolution from VOL header
+	        
+	        HBufC8* tmpBuffer = (HBufC8*) HBufC8::NewLC(KVOLHeaderBufferSize);
+            TPtr8 tmpPtr = tmpBuffer->Des();
+            mp4_u32 volSize = 0;
+            MP4Err volError = 0;
+            
+            volError = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 
+                                                            (mp4_u8*)(tmpPtr.Ptr()),
+                                                            KVOLHeaderBufferSize,
+                                                            &volSize );
+                                                            
+            if ( volError != MP4_OK )
+            {
+                User::Leave(KErrorCode);
+            }
+            tmpPtr.SetLength(volSize);
+            
+            CVedVolReader* tmpVolReader = CVedVolReader::NewL();
+            CleanupStack::PushL(tmpVolReader);
+
+            tmpVolReader->ParseVolHeaderL(tmpPtr);
+
+            aStreamParameters.iVideoWidth = tmpVolReader->Width();
+            aStreamParameters.iVideoHeight = tmpVolReader->Height();
+
+            CleanupStack::PopAndDestroy(tmpVolReader);
+            CleanupStack::PopAndDestroy(tmpBuffer);		
+
+	    }		
+	    	    
+	    else if ( iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE )
+	    {
+	        // read resolution from SPS
+
+	        HBufC8* tmpBuffer = (HBufC8*) HBufC8::NewLC(KAVCDCRBufferSize);	        	        
+            TPtr8 ptr = tmpBuffer->Des();
+            
+            // read decoder specific info
+            User::LeaveIfError( ReadAVCDecoderSpecificInfo(ptr) );
+            
+            // create AVC editing instance
+            CVedAVCEdit* avcEdit = CVedAVCEdit::NewL();
+            CleanupStack::PushL(avcEdit);
+            
+            TSize resolution(0,0);
+            User::LeaveIfError( avcEdit->GetResolution(ptr, resolution) );
+            
+            CleanupStack::PopAndDestroy(avcEdit);
+            CleanupStack::PopAndDestroy(tmpBuffer);
+
+            aStreamParameters.iVideoWidth = resolution.iWidth;
+            aStreamParameters.iVideoHeight = resolution.iHeight;
+	    }
+
+
+		iNumberOfFrames = GetNumberOfVideoFrames();
+		MPASSERT(iNumberOfFrames);
+    
+		if (iFirstTimeClipParsing)	// update only at the first parsing of a clip
+		{
+			// update the frame numbers
+			
+			iOutputNumberOfFrames = iProcessor->GetOutputNumberOfFrames();		
+			
+			if (iOutputNumberOfFrames == 0)
+			{
+				iOutputNumberOfFrames += iNumberOfFrames;  // total number of frames in all clips	
+			}
+			else if (!iProcessor->IsThumbnailInProgress())
+			{
+    			iOutputNumberOfFrames += iNumberOfFrames; 
+			}
+		}
+		
+		MPASSERT(frameRate > 0);
+		if (frameRate > 0)
+			aStreamParameters.iVideoPicturePeriodNsec = TInt64( TReal(1000000000) / TReal(frameRate) );
+		else
+			aStreamParameters.iVideoPicturePeriodNsec = TInt64(33366667);
+		
+		if ( iVideoType == MP4_TYPE_H263_PROFILE_0 || iVideoType == MP4_TYPE_H263_PROFILE_3 )
+		{
+			TVideoClipProperties prop;
+			prop.iH263Level = 0;
+			MP4ParseGetVideoClipProperties(iMP4Handle, prop);
+
+            iMaxVideoFrameLength = KMaxCodedPictureSizeQCIF;
+			if (prop.iH263Level == 45)
+                {
+				aStreamParameters.iVideoFormat = EVideoFormatH263Profile0Level45;
+                }
+			else 
+                {
+				aStreamParameters.iVideoFormat = EVideoFormatH263Profile0Level10;
+                }
+		}
+		else if ( iVideoType == MP4_TYPE_MPEG4_VIDEO )
+            {
+			aStreamParameters.iVideoFormat = EVideoFormatMPEG4;		
+            if ( aStreamParameters.iVideoWidth <= KVedResolutionQCIF.iWidth )
+                {
+                iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4L0BQCIF;//distinction between L0 and L0B not possible here
+                }
+            else if (aStreamParameters.iVideoWidth <= KVedResolutionCIF.iWidth )
+                {
+                iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4CIF;
+                }
+            else
+                {
+                // VGA
+                iMaxVideoFrameLength = KMaxCodedPictureSizeVGA;
+                }
+            }
+            
+        else if ( iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE )
+            {
+
+            // : Is it possible to dig up the level here ??
+			aStreamParameters.iVideoFormat = EVideoFormatAVCProfileBaseline;
+			
+            if ( aStreamParameters.iVideoWidth <= KVedResolutionQCIF.iWidth )
+                {
+                iMaxVideoFrameLength = KMaxCodedPictureSizeAVCLevel1B;  //distinction between L0 and L0B not possible here ??
+                }
+            else if (aStreamParameters.iVideoWidth <= KVedResolutionCIF.iWidth )
+                {
+                iMaxVideoFrameLength = KMaxCodedPictureSizeAVCLevel1_2;
+                }
+            else
+                {
+                // default
+                iMaxVideoFrameLength = KMaxCodedPictureSizeAVCLevel1_2;
+                }
+            }
+	}	
+
+	if ( error == MP4_OK )
+	{
+		// stream contains audio 
+		if ( iAudioType == MP4_TYPE_AMR_NB )
+			aStreamParameters.iAudioFormat = EAudioFormatAMR;
+		else
+		{
+			if ( iAudioType == MP4_TYPE_MPEG4_AUDIO )
+				aStreamParameters.iAudioFormat = EAudioFormatAAC;
+		}		
+	}
+	
+	TBool videoMpeg4OrAVC = ( iVideoType == MP4_TYPE_MPEG4_VIDEO || 
+	                          iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE );
+
+	if ( (videoMpeg4OrAVC && iAudioType == MP4_TYPE_MPEG4_AUDIO) ||
+		 (videoMpeg4OrAVC && iAudioType == MP4_TYPE_NONE) ||
+		 (iVideoType == MP4_TYPE_NONE && iAudioType == MP4_TYPE_MPEG4_AUDIO) )
+		aStreamParameters.iFileFormat = EFileFormatMP4;
+
+	else if (iVideoType != MP4_TYPE_NONE || iAudioType != MP4_TYPE_NONE)
+		aStreamParameters.iFileFormat = EFileFormat3GP;
+
+	if ( aStreamParameters.iStreamLength == 0 )
+		aStreamParameters.iFileFormat = EFileFormatUnrecognized;
+	
+	if ( aStreamParameters.iVideoFormat != EVideoFormatNone ) 
+	{
+		aStreamParameters.iHaveVideo = ETrue;
+		aStreamParameters.iNumDemuxChannels++;
+	}
+	
+	if ( aStreamParameters.iAudioFormat != EAudioFormatNone )
+	{
+		aStreamParameters.iHaveAudio = ETrue;
+		aStreamParameters.iNumDemuxChannels++;
+	}	
+	
+	aStreamParameters.iMaxPacketSize = 0;  // N/A
+	aStreamParameters.iLogicalChannelNumberVideo = 0;  // N/A
+	aStreamParameters.iLogicalChannelNumberAudio = 0;  // N/A
+	
+	// get stream description
+	error = MP4ParseRequestStreamDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iStreamSize, 
+		(mp4_u32 *)&aStreamParameters.iStreamBitrate);    
+	if ( error != MP4_OK )     
+		User::Leave(KErrorCode);
+	
+	// do sanity-check for bitrate
+	if (aStreamParameters.iStreamBitrate < KMinBitrate)
+	    User::Leave(KErrCorrupt);
+	
+	aStreamParameters.iReferencePicturesNeeded = 0;     
+	aStreamParameters.iNumScalabilityLayers = 0;
+	
+	// determine if the stream contains INTRA frames so seeking is possible
+	// If the stream contains more than one INTRA frame, seeking is 
+	// allowed. 
+	
+	if (hasVideo)
+	{
+		mp4_u32 position = aStreamParameters.iStreamLength + 1000;
+		mp4_u32 audioTime, videoTime;
+		
+		// Seek past stream duration to find out the position of last INTRA frame
+		error = MP4ParseSeek(iMP4Handle, position, &audioTime, &videoTime, ETrue);
+		if ( error != MP4_OK )     
+			User::Leave(KErrorCode);
+		
+		if (videoTime != 0) 
+		{
+			// at least two INTRAs
+			aStreamParameters.iCanSeek = ETrue;
+		}
+		
+		// rewind file back to beginning
+		error = MP4ParseSeek(iMP4Handle, 0, &audioTime, &videoTime, EFalse);
+		if ( error != MP4_OK )     
+			User::Leave(KErrorCode);
+	}
+
+    PRINT((_L("CMP4Parser::ParseHeaderL() end")));
+
+	return KErrNone; 
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::IsStreamable
+// Finds out whether input stream is multiplexed so that
+// it can be streamed, i.e. played while receiving the stream.
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+TInt CMP4Parser::IsStreamable()
+{
+	MP4Err error;
+	
+	error = MP4ParseIsStreamable(iMP4Handle);
+	if ( error == MP4_NOT_AVAILABLE )
+		return EParserNotEnoughData;
+	else if ( error == MP4_INVALID_INPUT_STREAM )
+		return KErrNotSupported;
+	else if ( error == MP4_ERROR )
+		return KErrorCode;    
+	else
+		return ( error == MP4_OK ) ? 1 : 0;
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::Seek
+// Seeks the file to desired position in milliseconds
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::Seek(TUint32 aPositionInMs, TUint32& anAudioTimeAfter, TUint32& aVideoTimeAfter)
+{
+	
+	MP4Err error = MP4_OK;
+	MPASSERT(iStreamSource == ESourceFile);
+	error = MP4ParseSeek(iMP4Handle, aPositionInMs, &anAudioTimeAfter, &aVideoTimeAfter, ETrue);
+	if (error != MP4_OK)
+		return KErrorCode;    
+	
+	return KErrNone;
+}
+
+
+
+TInt CMP4Parser::GetNumberOfFrames()
+{
+	return iNumberOfFrames;
+}
+
+// ---------------------------------------------------------
+// CMP4Parser::SeekOptimalIntraFrame
+// Seeks to INTRA frame position before given time
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::SeekOptimalIntraFrame(TTimeIntervalMicroSeconds aStartTime, TInt /*aIndex*/, TBool aFirstTime)
+{
+	MP4Err error = KErrNone; 
+	TInt revisedNumberOfFrames = 0;
+	mp4_u32 audioTime = 0; 
+	mp4_u32 videoTime = 0; 
+//	mp4_u32 timeScale = 0; 
+ 
+	// calculate the start time of the cut operation
+	TInt64 startTime = aStartTime.Int64() / TInt64(1000);    
+	mp4_u32 startPosition = (mp4_u32)( I64INT(startTime) ); // in milliseconds
+
+	TBool intraFound = (startPosition == 0);
+	
+	if (!aFirstTime)	
+	    intraFound = 0;
+		
+	// First check if the first included frame is intra	
+	if (!intraFound)
+	{
+	    // seek to previous frame preceding start time or at start time
+	    error = MP4ParseSeek(iMP4Handle, startPosition, &audioTime, &videoTime, EFalse);
+	    if (error != MP4_OK)
+	    {		
+		    return KErrorCode; 
+	    }
+	    MPASSERT(videoTime <= startPosition);
+
+	    // get index of the frame
+	    TInt index = iProcessor->GetVideoFrameIndex(TTimeIntervalMicroSeconds(videoTime*1000));
+	    
+	    if (videoTime < startPosition)	    
+	    {
+	        // if there was no frame at start time, seek 
+	        // one frame forward to the first included frame
+            index++;
+	    }
+	    
+        // get frame type
+        mp4_bool frameType;
+	    error = MP4ParseGetVideoFrameType(iMP4Handle, index, &frameType);	    
+	    if (error != MP4_OK)
+	    {		
+            return KErrorCode; 
+	    }
+	    if (frameType == 1)
+	    {
+	        intraFound = ETrue;
+	        iStartFrameIndex = index;
+	        
+	        mp4_u32 timeInTicks;
+	        // get timestamp of matched frame to startPosition
+	        error = MP4ParseGetVideoFrameStartTime(iMP4Handle, index, &timeInTicks, &startPosition);
+	        if (error != MP4_OK)
+	        {		
+		        return KErrorCode; 
+	        }	        
+	        
+	        // Now seek to found Intra in 1 ms increments. The loop is needed 
+	        // because due to rounding error, MP4Parser may seek to previous
+	        // frame instead of the I-frame at startPosition
+	        TInt seekTime = startPosition;
+	        videoTime = 0;
+	        
+	        while (videoTime != startPosition)
+	        {	            	        
+    	        error = MP4ParseSeek(iMP4Handle, seekTime, &audioTime, &videoTime, EFalse);
+        	    if (error != MP4_OK)
+        	    {		
+        		    return KErrorCode; 
+        	    }
+        	    MPASSERT(videoTime <= startPosition);
+        	    seekTime++;  // add 1 ms
+	        }
+        	
+	    }                
+	}	
+	
+	if (!intraFound)
+	{	    
+    	// seek to the I-frame preceding the start time
+    	error = MP4ParseSeek(iMP4Handle, startPosition, &audioTime, &videoTime, ETrue);
+    	if (error != MP4_OK)
+    	{		
+    		return KErrorCode; 
+    	}
+	}
+	
+	if (videoTime != 0) 
+	{
+	    if (!intraFound)
+        {                
+            // get index of the intra frame
+            TInt64 time = TInt64(TUint(videoTime)) * TInt64(1000);
+            iStartFrameIndex = iProcessor->GetVideoFrameIndex(TTimeIntervalMicroSeconds( time ));            
+        }        		
+		
+		if (aFirstTime)
+		{	
+		    revisedNumberOfFrames = iNumberOfFrames - iStartFrameIndex;	    
+		    // update movie and clip number of frames
+            iOutputNumberOfFrames -= iStartFrameIndex;            
+            iNumberOfFrames = revisedNumberOfFrames; 
+		}
+				
+		PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() revised = %d"),revisedNumberOfFrames));
+        PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() iNumberOfFrames = %d"),iNumberOfFrames));
+        PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() iStartFrameIndex = %d"),iStartFrameIndex));                                
+        PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() iOutputNumberOfFrames = %d"),iOutputNumberOfFrames));        				
+        iFrameNumber = iStartFrameIndex;
+	}
+	return KErrNone;
+}
+
+// ---------------------------------------------------------
+// CMP4Parser::GetNumberOfVideoFrames
+// Gets the number of video frames in clip
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::GetNumberOfVideoFrames()
+{
+    mp4_u32 numberOfFrames = 0;
+    MP4Err error = 0;    
+
+    error = MP4ParseGetNumberOfVideoFrames(iMP4Handle, &numberOfFrames);
+
+    if (error != MP4_OK)
+        return 0;
+
+    return numberOfFrames;
+  
+}
+
+// ---------------------------------------------------------
+// CMP4Parser::GetVideoFrameSize
+// Gets the size of video frame at given index
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::GetVideoFrameSize(TInt aIndex)
+{
+    mp4_u32 frameSize = 0;
+	mp4_u32 mp4Specific = 0;
+    MP4Err error = 0;
+
+	if ( aIndex == 0 && iVideoType == MP4_TYPE_MPEG4_VIDEO )
+	{
+		error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific );
+		
+		if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL )
+			return KErrorCode;
+	}
+
+    error = MP4ParseGetVideoFrameSize(iMP4Handle, aIndex, &frameSize);
+
+    if (error != MP4_OK)
+        return KErrorCode;
+
+    return frameSize + mp4Specific;
+	
+}
+
+
+
+// ---------------------------------------------------------
+// CMP4Parser::GetVideoFrameStartTime
+// Returns frame start time in millisec - optional iTimestamp for start time in ticks
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::GetVideoFrameStartTime(TInt aIndex, TInt* aTimeStampInTicks)
+{
+
+    MP4Err error = 0;
+    mp4_u32 timeStampInMs = 0;
+
+    MPASSERT(aTimeStampInTicks);
+  
+    PRINT((_L("CMP4Parser::GetVideoFrameStartTime(), get time for index %d"), aIndex));
+    error = MP4ParseGetVideoFrameStartTime(iMP4Handle, aIndex, (mp4_u32*)aTimeStampInTicks, &timeStampInMs);
+
+    if (error != MP4_OK)
+        {
+        PRINT((_L("CMP4Parser::GetVideoFrameStartTime(), error from MP4 parser %d"), error));
+        return KErrorCode;
+        }
+
+    PRINT((_L("CMP4Parser::GetVideoFrameStartTime(), time in ms %d"), timeStampInMs));
+    return timeStampInMs;
+  
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::GetVideoFrameType
+// Gets the type of video frame at given index
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt8 CMP4Parser::GetVideoFrameType(TInt aIndex)
+{
+
+    MP4Err error = 0;
+    mp4_bool frameType;
+    
+    error = MP4ParseGetVideoFrameType(iMP4Handle, aIndex, &frameType);
+
+    if (error != MP4_OK)
+        return KErrGeneral;
+ 
+	return TInt8(frameType);
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::GetVideoFrameProperties
+// Gets frame properties
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::GetVideoFrameProperties(TFrameInfoParameters* aVideoFrameInfoArray,
+										 TUint32 aStartIndex, TUint32 aSizeOfArray)
+{	
+	MP4Err error;
+	error = MP4GetVideoFrameProperties(iMP4Handle,aStartIndex,aSizeOfArray,aVideoFrameInfoArray);
+
+	if (error != MP4_OK)
+		return KErrorCode;
+
+	return KErrNone;
+}
+
+
+// ---------------------------------------------------------
+// CMP4Parser::ParseAudioInfo
+// Gets the frame information (frame size) for audio in the current clip
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::ParseAudioInfo(TInt& aAudioFrameSize)
+{
+	MP4Err error;
+	mp4_u32 audioLength=0;
+	mp4_u32 audioType=0;
+	mp4_u32 audioFramesInSample=0;
+	mp4_u32 audioTimeScale=0;
+    mp4_u32 avgBitRate=0;
+	mp4_double frameLength = 0.02; // 20 ms
+
+	error = MP4ParseRequestAudioDescription(iMP4Handle, (mp4_u32 *)&audioLength, 
+		&audioType, (mp4_u8*)&audioFramesInSample, (mp4_u32 *)&audioTimeScale, (mp4_u32*)&avgBitRate);
+    aAudioFrameSize = ((mp4_u32)((mp4_double)avgBitRate*frameLength)>>3); 
+
+	return error;
+}
+
+TInt CMP4Parser::GetMP4SpecificSize()
+{
+	MP4Err error = 0;
+	mp4_u32 mp4Specific = 0;
+	if ( iVideoType == MP4_TYPE_MPEG4_VIDEO )
+	{
+		error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific );
+		if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL )
+			return KErrGeneral;
+	}
+	return mp4Specific;
+}
+
+// ---------------------------------------------------------
+// CMP4Parser::ReadAudioDecoderSpecificInfoL
+// Gets the decoder specific info from the current file filled so that it can be composed to output file
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::ReadAudioDecoderSpecificInfoL(HBufC8*& aBytes, TInt aBufferSize)
+{
+	aBytes = HBufC8::NewL(aBufferSize);
+	CleanupStack::PushL(aBytes);
+	mp4_u8 *buffer = new (ELeave) mp4_u8[aBufferSize];
+	mp4_u32 decspecinfosize = 0;
+	
+	MP4Err err = MP4ParseReadAudioDecoderSpecificInfo(
+		iMP4Handle,
+		buffer,
+		aBufferSize,
+		&decspecinfosize);
+	if (err == MP4_OK)
+	{
+		for (TInt a = 0 ; a < (TInt)decspecinfosize ; a++)
+		{
+			aBytes->Des().Append(buffer[a]);
+		}
+	}
+	else
+	{
+		delete[] buffer;
+		buffer = 0;
+		CleanupStack::PopAndDestroy(aBytes);
+		aBytes = 0;
+		User::Leave(KErrGeneral);
+	}
+	delete[] buffer;
+	buffer = 0;
+	CleanupStack::Pop(aBytes);
+	return ETrue;
+}
+
+// ---------------------------------------------------------
+// CMP4Parser::SetDefaultAudioDecoderSpecificInfoL
+// Gets the default decoder specific info filled so that it can be composed to output file
+// the default info is for a 16 KHz, mono LC type AAC only
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CMP4Parser::SetDefaultAudioDecoderSpecificInfoL(HBufC8*& aBytes, TInt aBufferSize)
+{
+	aBytes = HBufC8::NewL(aBufferSize);
+	CleanupStack::PushL(aBytes);
+	
+	const TUint8 frameDecSpecInfo[] = {0x14,0x08};	//the decoder specific 
+	const TInt frameSize = 2;  //constant as maximum size of decoderspecific info is 2
+	
+		for (TInt a = 0 ; a < frameSize ; a++)
+		{
+			aBytes->Des().Append(frameDecSpecInfo[a]);
+		}
+	CleanupStack::Pop(aBytes);
+	return ETrue;
+}
+
+
+TInt CMP4Parser::GetAudioBitrate(TInt& aBitrate)
+{
+
+    mp4_u32 length;
+    mp4_u32 type;
+    mp4_u8 framesPerSample;
+    mp4_u32 timeScale;
+    mp4_u32 averageBitrate;
+
+    MP4Err error = 0;
+    
+    error = MP4ParseRequestAudioDescription(iMP4Handle, &length, 
+        &type, &framesPerSample, &timeScale, &averageBitrate);
+
+    if ( error != 0 )
+        return KErrGeneral;
+
+    aBitrate = averageBitrate;
+
+    return KErrNone;
+
+
+}
+
+TInt CMP4Parser::GetVideoFrameRate(TReal& aFrameRate)
+{
+
+    mp4_u32 length;
+    mp4_double frameRate; 
+    mp4_u32 videoType;
+    mp4_u32 width;
+    mp4_u32 height;
+    mp4_u32 timeScale;
+
+    MP4Err error = 0;
+
+    // get video description
+	error = MP4ParseRequestVideoDescription(iMP4Handle, &length, &frameRate, 
+        &videoType, &width, &height, &timeScale);		
+
+    if ( error != 0 )
+        return KErrGeneral;
+    
+    TReal temp = frameRate * 2.0;
+    TInt temp2 = TInt(temp + 0.5);
+
+    aFrameRate = temp2 / 2.0;
+
+    return KErrNone;
+}
+
+TInt CMP4Parser::GetDecoderSpecificInfoSize()
+{
+
+    MPASSERT(iMP4Handle);
+
+    mp4_u32 mp4Specific = 0;
+        
+    MP4Err error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific );        
+    
+    if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL )
+        return KErrGeneral;
+    
+    return mp4Specific;
+}
+
+TInt CMP4Parser::ReadAVCDecoderSpecificInfo(TDes8& buf)
+{
+
+    mp4_u32 mp4Specific = 0;
+    
+    MP4Err error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, (mp4_u8*)(buf.Ptr()), 
+				mp4_u32( buf.MaxLength() ), &mp4Specific );
+        
+        
+    if (error != MP4_OK)
+	    return KErrorCode;
+    
+    buf.SetLength(mp4Specific);
+    
+    return KErrNone;
+    
+}
+
+TInt CMP4Parser::GetVideoDuration(TInt& aDurationInMs)
+{
+
+    mp4_u32 length;
+    mp4_double frameRate; 
+    mp4_u32 videoType;
+    mp4_u32 width;
+    mp4_u32 height;
+    mp4_u32 timeScale;
+
+    MP4Err error = 0;
+
+    // get video description
+	error = MP4ParseRequestVideoDescription(iMP4Handle, &length, &frameRate, 
+        &videoType, &width, &height, &timeScale);		
+
+    if ( error != MP4_OK )
+        return KErrGeneral;
+    
+    aDurationInMs = length;
+
+    return KErrNone;
+    
+}
+
+
+// End of File