mmplugins/lib3gp/impl/src/asyncfileparser.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/impl/src/asyncfileparser.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,536 @@
+// Copyright (c) 2006-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 FILES
+#include <e32base.h>
+#include <f32file.h>
+#include <f32file64.h>
+#include <3gplibrary/mp4lib.h>
+#include "mp4atom.h"
+#include "mp4memwrap.h"
+#include "asyncfileparser.h"
+
+// MACROS
+// Debug print macro
+#if defined(_DEBUG) && defined(_ASYNCFILEPARSERLOGGING)
+#include <e32svr.h>
+#define PRINT(x)
+#else
+#define PRINT(x)
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::CFileAsyncParser
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CFileAsyncParser::CFileAsyncParser() : CActive( EPriorityHigh ), iDiskBufferPointer(NULL,0)
+    {
+    
+    }
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CFileAsyncParser::ConstructL( MP4HandleStruct* aHandle, RFile64& aFile )
+    {
+    PRINT(_L("CFileAsyncParser::ConstructL() IN"));
+    iError = KErrNone;
+    iInputFile = &aFile;
+    iHandle = aHandle;    
+	iAudioSize = 0;
+	iReturnedAudioFrames = 0;
+	iAudioTimeStamp = 0; 		
+	iAudioTimeStamp2 = 1;   // always fill timestamp2 too (null = dont fill)
+	iAllDataInMemory = EFalse; 
+	
+	if ( iHandle->readBufferSize == 0)
+	{
+		iReadBufferSize = READBUFSIZE;
+	}
+	else
+	{
+		iReadBufferSize = iHandle->readBufferSize;
+	}	
+	
+	iDiskBuffer = HBufC8::NewL(iReadBufferSize);
+	iCurrentDiskReadPosition = 0;
+	iCurrentBufferReadPosition = 0;
+    CActiveScheduler::Add(this);
+    
+    PRINT(_L("CFileAsyncParser::ConstructL() OUT"));
+    }
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CFileAsyncParser* CFileAsyncParser::NewL( MP4HandleStruct* aHandle, RFile64& aFile )
+    {
+    CFileAsyncParser* self = new(ELeave) CFileAsyncParser;
+    CleanupStack::PushL(self);
+    self->ConstructL( aHandle, aFile );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CFileAsyncParser::~CFileAsyncParser()
+    {
+    PRINT(_L("CFileAsyncParser::~CFileAsyncParser() in"));
+
+    if ( IsActive() )
+        {
+        if ( iAsyncReadOngoing )
+            {
+            Cancel();
+            }
+        }
+
+    delete iDiskBuffer;
+    PRINT(_L("CFileAsyncParser::~CFileAsyncParser() out"));
+    }
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::ReadAudioFrames(  );
+// Writes incoming buffer data to internal buffers for writing to disk.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileAsyncParser::ReadAudioFrames( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
+	{
+	PRINT(_L("CFileAsyncParser::ReadAudioFrames()"));
+	iProcessingAudio = ETrue;
+	return ReadDataAsync( buffer, aPosition, aBytesToRead );
+	}
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::ReadVideoFrame( );
+// Writes incoming buffer data to internal buffers for writing to disk.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileAsyncParser::ReadVideoFrame( mp4_u8* buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
+	{
+	PRINT(_L("CFileAsyncParser::ReadVideoFrame()"));
+	iProcessingAudio = EFalse;
+	return ReadDataAsync( buffer, aPosition, aBytesToRead );
+	}
+
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::ReadDataAsync(  );
+// Reads data from file asynchronously.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileAsyncParser::ReadDataAsync( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
+	{
+	PRINT(_L("CFileAsyncParser::ReadDataAsync() in"));
+	iBuffer = buffer;
+	if ( iAsyncReadOngoing )
+		{
+		return -1; // only one async read can be ongoing at one time;	
+		}
+	if (!iDiskBuffer)
+		{
+		return -1;
+		}
+		
+  	// Is the new seek point inside the current disk buffer?
+  	if ( (iCurrentDiskReadPosition > aPosition) &&  
+  		 (( iCurrentDiskReadPosition - iDiskBuffer->Length() ) <= aPosition  ))
+  		{
+    	// Yes
+	    iCurrentBufferReadPosition = iDiskBuffer->Length() - (iCurrentDiskReadPosition - aPosition);
+  		}
+  	else
+  		{
+    	// No, set current position and zero diskbuffer
+		iCurrentBufferReadPosition = 0;
+		iCurrentDiskReadPosition = (mp4_i64)aPosition;
+		iDiskBuffer->Des().SetLength(0);
+		}
+		
+	iBytesToRead = aBytesToRead;
+	iBytesRead = 0;
+	TInt available = 0;
+	
+	// How much data is available in diskbuffer.
+	available =  iDiskBuffer->Length() - iCurrentBufferReadPosition;
+	if (available > iBytesToRead)
+	{
+	  available = iBytesToRead;
+	}
+
+	// If any available copy it first to output buffer
+	if (available ) 
+	{
+	  memcpy(iBuffer, iDiskBuffer->Ptr() + iCurrentBufferReadPosition, available);
+	  iCurrentBufferReadPosition += available;
+	  iBytesRead += available;
+	}
+
+	// If we got everything from diskbuffer process it right away
+	if (iBytesRead == iBytesToRead)
+	{
+		PRINT(_L("CFileAsyncParser::ReadDataAsync() Data found in memory, no need to read file - return right away"));
+		iAllDataInMemory = ETrue;
+		SetActive();
+        TRequestStatus* tmp = &iStatus;
+        User::RequestComplete(tmp, KErrNone);
+        PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
+		return MP4_OK;
+	}
+	else
+	{
+		// Need to read rest of the requested data from file.
+		iAllDataInMemory = EFalse;
+	}
+
+	// Determine used readbuffer size
+	if ( iHandle->readBufferSize == 0)
+	{
+		iReadBufferSize = READBUFSIZE;
+	}
+	else
+	{
+		iReadBufferSize = iHandle->readBufferSize;
+	}
+	
+	// Increase disk read buffer size if requested frames are larger than current disk buffer.
+	if ( (iBytesToRead > iReadBufferSize ) || (iReadBufferSize != iDiskBuffer->Des().MaxLength()) )
+	{
+        iReadBufferSize = iBytesToRead;
+        if (iDiskBuffer)
+        {
+            delete iDiskBuffer;
+            iDiskBuffer = NULL;
+            TRAPD(memerror, iDiskBuffer = HBufC8::NewL(iReadBufferSize));
+            if (memerror)
+            {
+	            return MP4_OUT_OF_MEMORY;
+            }
+            else
+            {
+				iCurrentBufferReadPosition = 0;
+            }
+        }
+	}
+
+	iAsyncReadOngoing = ETrue;
+	iDiskBufferPointer.Set(iDiskBuffer->Des());
+	iCurrentDiskReadPosition = aPosition + iBytesRead;
+	switch (iHandle->sourceType)
+	  {
+	    case MP4_SOURCE_RFILE:
+	    {
+		  PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading RFile64"));	    
+	      RFile64* rfile = (RFile64*)iHandle->rfile;
+	      rfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
+	      break;
+	    }
+	    case MP4_SOURCE_CAF:
+	    {
+		  PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading CAF object"));	    	    
+	      iHandle->cafError = iHandle->cfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
+	      if ( iHandle->cafError != KErrNone)
+	        return -2;
+	      break;
+	    }
+	    default:
+	      return -1;
+	  }
+
+    if ( !IsActive() )
+	    {
+	    SetActive();
+	    }
+	PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
+	return 0;
+	}
+
+
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::DoCancel()
+// From CActive Cancels async request.
+// -----------------------------------------------------------------------------
+//
+void CFileAsyncParser::DoCancel()
+    {
+    PRINT(_L("CFileAsyncParser::DoCancel() in"));
+    if (iAsyncReadOngoing)
+    	{
+    	if (iHandle->sourceType == MP4_SOURCE_RFILE)
+    	    {
+    	    // cancel read from file
+    	    ((RFile64 *)(iHandle->rfile))->ReadCancel();
+        	}
+    	else if (iHandle->sourceType == MP4_SOURCE_CAF)
+        	{
+        	// cancel read from caf object
+        	iHandle->cfile->ReadCancel(iStatus);
+        	}
+    	iAsyncReadOngoing = EFalse;
+    	}
+    
+    PRINT(_L("CFileAsyncParser::DoCancel() out"));
+    }
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::ReturnAudioFrames()
+// Return audio frames to observer.
+// -----------------------------------------------------------------------------
+//
+void CFileAsyncParser::ReturnAudioFrames()
+	{
+	PRINT(_L("CFileAsyncParser::ReturnAudioFrames() in"));
+	TInt error = KErrNone;
+	
+	// Update last accessed position in file pointer
+    if (iHandle->audioSampleOffset + iHandle->audioSampleSize - 1 > iHandle->lastAccessedPosInFile)
+	    {
+	    iHandle->lastAccessedPosInFile = iHandle->audioSampleOffset + iHandle->audioSampleSize - 1;
+	    }
+	
+	// Fill audio frame size
+	iAudioSize = iHandle->audioSampleSize;
+	
+	// Fill audio timestamp information
+	iAudioTimeStamp = 0;
+	iAudioTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
+	error = convertAudioSampleToTime(iHandle, iHandle->moov->trakAudio->mdia, &iAudioTimeStamp, &iAudioTimeStamp2);	
+	if (error == MP4_OK)
+		{
+		// Fill iReturnedAudioFrames
+		iReturnedAudioFrames = 0;
+		error = CalculateAudioFrameCount();
+		}
+	
+	// Move forward in audio samples
+	if (error == MP4_OK)
+		{
+		error = advanceAudioSample(iHandle, iHandle->moov->trakAudio);
+		if ( error == -1)
+			{
+			error = MP4_ERROR;
+			}
+		else if ( error == -2 )
+			{
+			error = MP4_OK;
+			iHandle->audioLast = MP4TRUE;
+			}
+		}
+
+	iAsyncReadOngoing = EFalse;
+	iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(error, 
+    													  iAudioSize,
+    													  iAudioTimeStamp,
+    													  iReturnedAudioFrames,
+    										  			  iAudioTimeStamp2);
+	PRINT(_L("CFileAsyncParser::ReturnAudioFrames() out"));		
+	}
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::ReturnVideoFrame()
+// Return video frame to observer.
+// -----------------------------------------------------------------------------
+//
+void CFileAsyncParser::ReturnVideoFrame()
+	{
+	PRINT(_L("CFileAsyncParser::ReturnVideoFrame() in"));
+	TInt error = KErrNone;
+	
+	// Update last accessed position in file pointer
+    if (iHandle->videoFrameOffset + iHandle->videoFrameSize - 1 > iHandle->lastAccessedPosInFile)
+	    {
+	    iHandle->lastAccessedPosInFile = iHandle->videoFrameOffset + iHandle->videoFrameSize - 1;
+	    }
+	
+	// Fill video frame size
+	iVideoSize = iHandle->videoFrameSize;
+	
+	// Fill video timestamp information
+	iVideoTimeStamp = 0;
+	iVideoTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
+	error = convertVideoSampleToTime(iHandle, iHandle->moov->trakVideo->mdia, &iVideoTimeStamp, &iVideoTimeStamp2);	
+	if (error == MP4_OK)
+		{
+		// Fill iKeyFrame
+		iVideoKeyFrame = 0;
+		error = isVideoFrameKeyFrame(iHandle, iHandle->moov->trakVideo, &iVideoKeyFrame);
+		}
+	
+	// Move forward in video frames
+	if (error == MP4_OK)
+		{
+		error = advanceVideoFrame(iHandle, iHandle->moov->trakVideo);
+		if ( error == -1)
+			{
+			error = MP4_ERROR;
+			}
+		else if ( error == -2 )
+			{
+			error = MP4_OK;
+			iHandle->videoLast = MP4TRUE;
+			}
+		}
+
+	iAsyncReadOngoing = EFalse;
+	iHandle->asyncObserver->M3GPMP4LibVideoFrameAvailable(error,
+        										   		  iVideoSize, 
+        										  		  iVideoTimeStamp, 
+        										   		  iVideoKeyFrame, 
+        										   		  iVideoTimeStamp2);
+	PRINT(_L("CFileAsyncParser::ReturnVideoFrame() out"));		
+	}
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::CalculateAudioFrameCount()
+// Return video frame to observer.
+// -----------------------------------------------------------------------------
+//
+TInt CFileAsyncParser::CalculateAudioFrameCount()
+	{
+  	mp4_i32 frameLength = 0;
+  	mp4_u32 numOfFrames = 0;
+  	mp4_u8 *framepointer = 0;
+  	mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};	
+	trackAtom *trak = iHandle->moov->trakAudio;
+	
+	if (!trak)
+		{
+		return -1;
+		}
+
+	/* AMR */
+	if (trak->mdia->minf)
+	if (trak->mdia->minf->stbl)
+	  if (trak->mdia->minf->stbl->stsd)
+	    if (iHandle->type & MP4_TYPE_AMR_NB)
+	    {
+	        framepointer = iBuffer;
+	        numOfFrames = 0;
+	        while ( iBytesRead > 0 )
+	        {
+	            frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
+	            if ( frameLength == 0)
+	            {
+	                return -4;
+	            }
+	            iBytesRead -= frameLength;
+	            framepointer += frameLength;
+	            numOfFrames++;
+	        }
+	        iReturnedAudioFrames = numOfFrames;
+	    }
+	    else if (iHandle->type & MP4_TYPE_AMR_WB)
+	    {
+		  /* Return the number of sample entries listed for this particular sample entry index */
+	      if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1])
+	        if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr)
+	          iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr->framesPerSample;
+	    }
+	    else
+	    {
+	    }
+
+	/* MPEG-4 audio */
+	if (trak->mdia->minf)
+	if (trak->mdia->minf->stbl)
+	  if (trak->mdia->minf->stbl->stsd)
+	    if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
+	      iReturnedAudioFrames = 1;
+
+	/* QCELP 13K as QCELPSampleEntry*/
+	if (trak->mdia->minf)
+	if (trak->mdia->minf->stbl)
+	  if (trak->mdia->minf->stbl->stsd)
+	    if ((iHandle->type & MP4_TYPE_QCELP_13K) && (!iHandle->qcelpStoredAsMPEGAudio))
+	    {
+		  /* Return the number of sample entries listed for this particular sample entry index */
+	      if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1])
+	        if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp)
+	          iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
+	    }
+
+	/* QCELP 13K as MPEG-4 audio */
+	if (trak->mdia->minf)
+	if (trak->mdia->minf->stbl)
+	  if (trak->mdia->minf->stbl->stsd)
+	    if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
+	      iReturnedAudioFrames = 1;
+
+	return MP4_OK;	
+	}
+
+// -----------------------------------------------------------------------------
+// CFileAsyncParser::RunL()
+// From CActive Called when async request completes.
+// -----------------------------------------------------------------------------
+//
+void CFileAsyncParser::RunL()
+    {
+    PRINT(_L("CFileAsyncParser::RunL() in"));
+    if ( iStatus != KErrNone )
+        {
+        PRINT((_L("CFileAsyncParser::RunL() error in previous async: %d "), iStatus.Int() ));
+        iError = iStatus.Int();
+		iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(MP4_FILE_ERROR,0,0,0,0);
+        return;
+        }
+
+    if (!iAllDataInMemory)
+	    {
+		if ((mp4_u32)iDiskBuffer->Length() == 0) // EOF or error
+		{
+			iError = MP4_FILE_ERROR; // metadata info doesn't match file -> corrupted clip.
+		}
+		
+		memcpy(iBuffer+iBytesRead, iDiskBuffer->Ptr(), iBytesToRead-iBytesRead);
+	  	iCurrentBufferReadPosition += iBytesToRead-iBytesRead;
+	  	iCurrentDiskReadPosition += iDiskBuffer->Length();
+		iBytesRead = iBytesToRead;
+	  	
+	  	// set handle disk buffer sizes to zero just in case.
+	  	iHandle->diskReadBufPos = 0;
+		iHandle->diskReadSize = 0;
+		iHandle->diskReadBufStart = 0;
+		iHandle->diskReadPos = iCurrentDiskReadPosition;
+    	}
+
+	if ( iProcessingAudio )
+		{
+		ReturnAudioFrames();
+		}
+	else
+		{
+		ReturnVideoFrame();	
+		}
+    
+    PRINT(_L("CFileAsyncParser::RunL() out"));
+    }
+
+//  End of File