mmplugins/lib3gp/impl/src/filewriter.cpp
changeset 0 40261b775718
child 23 545d349d14da
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/impl/src/filewriter.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,591 @@
+// 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 "mp4atom.h"
+#include "filewriter.h"
+
+// MACROS
+// Debug print macro
+#ifdef _DEBUG
+#include <e32svr.h>
+//#define PRINT(x) RDebug::Print x
+#define PRINT(x)
+#else
+#define PRINT(x)
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CFileWriter::CFileWriter
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CFileWriter::CFileWriter() : CActive( EPriorityHigh ) 
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CFileWriter::ConstructL( RFile64& aFile )
+    {
+    PRINT((_L("CFileWriter::ConstructL() in")));         
+    iFlush = EFalse;
+    iError = KErrNone;
+    iOutputFile = &aFile;
+    iWritingStarted = EFalse;
+    iOutputBufferSize = KFileWriterBufferSizeSmall;
+    iMaxOutputBufHardLimit = KFileWriterHardBufLimit;
+    iMaxOutputBufSoftLimit = KFileWriterSoftBufLimit;
+    iOutputFileSetSizeCooldown = 0;
+
+    iMemReadyForWriting = EFalse;
+    iInputBuf = NULL;
+    iEmptyBufferQueue.Reset();
+    iFullBufferQueue.Reset();
+
+    AllocateBuffersL();
+    CActiveScheduler::Add(this);
+    PRINT((_L("CFileWriter::ConstructL() out")));         
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CFileWriter* CFileWriter::NewL( RFile64& aFile )
+    {
+    CFileWriter* self = new(ELeave) CFileWriter;
+    CleanupStack::PushL(self);
+    self->ConstructL( aFile );
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+
+// Destructor
+CFileWriter::~CFileWriter()
+    {
+    PRINT((_L("CFileWriter::~CFileWriter() in")));         
+    if ( IsActive() )
+        {
+        if ( iAsyncWritingOngoing )
+            {
+            Cancel();    
+            }
+        else
+            {
+            TRequestStatus* status = &iStatus;
+            User::RequestComplete( status, KErrNone );
+            Cancel();
+            }
+        }
+
+    if ( iInputBuf )
+        {
+        delete iInputBuf;
+        }
+
+    iEmptyBufferQueue.ResetAndDestroy();
+    iFullBufferQueue.ResetAndDestroy();
+    PRINT((_L("CFileWriter::~CFileWriter() out")));         
+    }
+
+
+// -----------------------------------------------------------------------------
+// CFileWriter::Write( const TDesC8& aBuf )
+// Writes incoming buffer data to internal buffers for writing to disk.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileWriter::Write( const TDesC8& aBuf )
+    {
+    PRINT(_L("CFileWriter::Write() in"));
+    PRINT((_L("e_cfilewriter_write 1")));
+
+    iWritingStarted = ETrue;
+    
+    if ( !iMemReadyForWriting )
+    	{
+    	return KErrNoMemory;
+    	}
+
+    PRINT((_L("e_cfilewriter_write_adddatatobuffer 1")));	
+    TInt error = AddDataToBuffer( aBuf );
+    PRINT((_L("e_cfilewriter_write_adddatatobuffer 0")));	    
+    
+    if ( error != KErrNone )
+        {
+        PRINT((_L("CFileWriter::Write() buffer write error: %d"), error));         
+        return error;
+        }
+
+    PRINT((_L("CFileWriter::Write() Write Buffer, Status: Full:%d Empty:%d "), 
+                    iFullBufferQueue.Count(), iEmptyBufferQueue.Count() ));
+
+    if ( iAsyncWritingOngoing )
+        {
+        if ( iFullBufferQueue.Count() >= iMaxOutputBufHardLimit )
+            {
+            PRINT((_L("CFileWriter::Write() Waiting async write to complete")));
+			PRINT((_L("e_cfilewriter_write_wait_async 1")));            
+            User::WaitForRequest( iStatus );
+			PRINT((_L("e_cfilewriter_write_wait_async 0")));            
+            PRINT((_L("CFileWriter::Write() Async write done")));
+            TRAP(error, RunL());
+            if (error != KErrNone)
+            	{
+            	PRINT((_L("CFileWriter::Write() call runL leave, error: %d"), error));         
+                return error;
+            	}
+            }
+        }
+    else
+        {
+        if ( iFullBufferQueue.Count() )
+            {
+            PRINT(_L("CFileWriter::Write() writing async"));                     
+            PRINT((_L("e_cfilewriter_write_startwrite 1")));                     
+            iOutputFile->Write( *iFullBufferQueue[0], iStatus );
+            PRINT((_L("e_cfilewriter_write_startwrite 0")));
+            iAsyncWritingOngoing = ETrue;
+            if ( !IsActive() )
+                {
+                SetActive();
+                }
+            }
+        }
+
+    PRINT(_L("CFileWriter::Write() out"));
+    PRINT((_L("e_cfilewriter_write 0")));    
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::Flush( const TDesC8& aBuf )
+// Flush internal buffers to disk.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileWriter::Flush( const TDesC8& aBuf )
+    {
+    PRINT(_L("CFileWriter::Flush() in"));
+    PRINT((_L("e_cfilewriter_flush 1")));
+ 
+ 	if ( !iMemReadyForWriting )
+ 		{
+ 		return KErrNoMemory;
+ 		}
+ 	
+    iWritingStarted = ETrue;
+
+    PRINT((_L("e_cfilewriter_flush_adddatatobuf 1")));
+    TInt error = AddDataToBuffer( aBuf );
+    if ( error != KErrNone )
+        {
+        return error;
+        }
+	PRINT((_L("e_cfilewriter_flush_adddatatobuf 0")));        
+
+    PRINT((_L("CFileWriter::Flush() FullCount: %d "), iFullBufferQueue.Count()));
+    iFlush = ETrue;
+
+    if ( iAsyncWritingOngoing )
+        {
+        PRINT((_L("CFileWriter::Flush() Waiting async write to complete")));
+        PRINT((_L("e_cfilewriter_flush_waitasynctostop 1")));
+        User::WaitForRequest( iStatus );
+        PRINT((_L("e_cfilewriter_flush_waitasynctostop 0")));
+        PRINT((_L("CFileWriter::Flush() Async write done, flushing")));
+        TRAP(error, RunL());
+        if (error != KErrNone)
+        	{
+        	PRINT((_L("CFileWriter::Flush() call runL leave, error: %d"), error));         
+            return error;
+        	}
+        }
+
+    while ( iFullBufferQueue.Count() )
+        {
+        PRINT((_L("e_cfilewriter_flush_writequeue_sync 1")));
+        error = iOutputFile->Write( *iFullBufferQueue[0] );
+        PRINT((_L("e_cfilewriter_flush_writequeue_sync 0")));
+        PRINT((_L("e_cfilewriter_flush_remove_buf 1")));
+        if ( error == KErrNone )
+            {
+            iFullBufferQueue[0]->Des().Zero();
+            if ( iEmptyBufferQueue.Append( iFullBufferQueue[0] ) )
+                {
+                PRINT(_L("CFileWriter::Flush() Append failed"));
+                delete ( iFullBufferQueue[0] ); 
+                }
+            iFullBufferQueue.Remove( 0 );
+            }
+        else
+            {
+            PRINT((_L("CFileWriter::Flush() fullBufQueue write failed, error: %d"), error));
+            iFlush = EFalse;
+            return error;
+            }
+        PRINT((_L("e_cfilewriter_flush_remove_buf 0")));    
+        }
+
+    if ( iInputBuf->Length() )
+        {
+        PRINT((_L("e_cfilewriter_flush_writeinput_sync 1")));
+        error = iOutputFile->Write( *iInputBuf );
+        PRINT((_L("e_cfilewriter_flush_writeinput_sync 0")));
+        if ( error == KErrNone )
+            {
+            iInputBuf->Des().Zero();
+            }
+        else
+            {
+            PRINT((_L("CFileWriter::Flush() inputbuf write failed, error: %d"), error));
+            iFlush = EFalse;
+            return error;
+            }
+        }
+        
+    iFlush = EFalse;
+    PRINT((_L("CFileWriter::Flush() FullCount: %d <= Should be 0"), iFullBufferQueue.Count()));
+    PRINT(_L("CFileWriter::Flush() out"));
+    PRINT((_L("e_cfilewriter_flush 0")));    
+    return KErrNone;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CFileWriter::SetOutputBufferSize( TOutputBufferSize aBufferSize )
+// Set output buffer sizes.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileWriter::SetOutputBufferSize( TOutputBufferSize aBufferSize, MP4Handle aHandle )
+    {
+    MP4HandleImp handle = (MP4HandleImp)aHandle;    
+    TInt size = 0;
+
+    if ( iWritingStarted )
+        {
+        return KErrNotReady;
+        }
+
+    if ( aBufferSize == EBufferSizeSmall ) 
+        {
+        size = KFileWriterBufferSizeSmall;
+        }
+    else if ( aBufferSize == EBufferSizeLarge ) 
+        {
+        size = KFileWriterBufferSizeLarge;
+        }
+    else if ( aBufferSize == EBufferSizeCustom )
+        {
+        size = handle->mediaWriteBufferSize;
+        }
+    else
+        {
+        return KErrArgument;    
+        }
+
+    if ( size == iOutputBufferSize )
+        {
+        return KErrNone;
+        }
+    else
+        {
+        iOutputBufferSize = size;
+        }
+
+    iMemReadyForWriting = EFalse;
+    delete iInputBuf;
+    iInputBuf = NULL;
+    iEmptyBufferQueue.ResetAndDestroy();
+    iFullBufferQueue.ResetAndDestroy();
+
+    TRAPD(err, AllocateBuffersL() );
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::SetOutputBufferCount( MP4Handle aHandle )
+// Set output buffer count.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CFileWriter::SetOutputBufferCount( MP4Handle aHandle )
+    {
+    MP4HandleImp handle = (MP4HandleImp)aHandle;    
+
+    if (  handle->writeBufferMaxCount >= 6 )     
+        {
+        iMaxOutputBufHardLimit = handle->writeBufferMaxCount;
+        iMaxOutputBufSoftLimit = KFileWriterMinBufferCount + ((iMaxOutputBufHardLimit-KFileWriterMinBufferCount)/2);
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CFileWriter::AddDataToBuffer( const TDesC8& aBuf )
+// Writes incoming data to internal buffers and buffer queues..
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CFileWriter::AddDataToBuffer( const TDesC8& aBuf )
+    {
+    PRINT(_L("CFileWriter::AddDataToBuffer() in"));
+
+    TInt byteswritten = 0;
+    TInt numbytes = 0;
+    TInt available = 0; // Available bytes in write buffer
+    TInt error = KErrNone;
+
+    if ( iError != KErrNone )
+        {
+        PRINT((_L("CFileWriter::AddDataToBuffer() out, RunL iError: %d"), iError));
+        return iError;
+        }
+
+    if ( iInputBuf == NULL )
+    	{
+    	return KErrNoMemory;
+    	}
+
+    while (byteswritten < aBuf.Length() )
+        {
+        available = (iInputBuf->Des()).MaxLength() - iInputBuf->Length();
+
+        if (available > 0)
+            {
+            numbytes = aBuf.Length() - byteswritten;
+            if (numbytes > available)
+                {
+                numbytes = available;
+                }
+            iInputBuf->Des().Append( aBuf.Mid( byteswritten, numbytes ) );
+            byteswritten += numbytes;
+            }
+        else // Buffer is full, write it to disk
+            {
+            // input is full, move full inputbuf to full buf queue
+            if ( iFullBufferQueue.Append( iInputBuf ) != KErrNone )
+                {
+                PRINT(_L("CFileWriter::AddDataToBuffer() Append failed"));
+                delete iInputBuf;
+                iInputBuf = NULL;
+                }
+            if ( iEmptyBufferQueue.Count() == 0 )
+                {
+                // no empty buffers in queue, allocating new one
+                TRAP(error, iInputBuf = HBufC8::NewL( iOutputBufferSize ));
+                if ( error != KErrNone )
+                    {
+                    PRINT((_L("CFileWriter::AddDataToBuffer(), memory alloc failed: %d"), error));
+                    iInputBuf = NULL;
+                    iError = error;
+                    break;
+                    }
+                }
+            else
+                {
+                iInputBuf = iEmptyBufferQueue[ 0 ];
+                iEmptyBufferQueue.Remove( 0 );
+                }
+            }
+        }
+
+    PRINT((_L("CFileWriter::AddDataToBuffer() out, error: %d"), error));
+    return error;
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::AllocateBuffersL()
+// Allocates input and output buffers.
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CFileWriter::AllocateBuffersL()
+    {
+    PRINT((_L("CFileWriter::AllocateBuffersL() in, outbufsize: %d"), iOutputBufferSize));
+    HBufC8* buf = NULL;
+    TInt err = 0;
+    iMemReadyForWriting = EFalse;
+
+    iInputBuf = HBufC8::NewL( iOutputBufferSize );
+    for( TInt i=0; i<KFileWriterMinBufferCount; i++ )
+        {
+        buf = HBufC8::NewL( iOutputBufferSize );
+        err = iEmptyBufferQueue.Append( buf );
+        if ( err )
+            {
+            delete ( buf );
+            User::Leave( err );
+            }
+        }
+    iMemReadyForWriting = ETrue;
+    PRINT((_L("CFileWriter::AllocateBuffersL() out")));
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::DoCancel()
+// From CActive Cancels async request.
+// -----------------------------------------------------------------------------
+//
+void CFileWriter::DoCancel()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CFileWriter::RunL()
+// From CActive Called when async request completes.
+// -----------------------------------------------------------------------------
+//
+void CFileWriter::RunL()
+    {
+    PRINT(_L("CFileWriter::RunL() in"));
+	PRINT((_L("e_cfilewriter_runl 1")));    
+    iAsyncWritingOngoing = EFalse;
+
+    if ( iStatus == KErrNone )
+        {
+        iOutputFileSize += iFullBufferQueue[0]->Des().Length();
+        iFullBufferQueue[0]->Des().Zero();
+        iError = iEmptyBufferQueue.Append( iFullBufferQueue[0] );
+        if ( iError )
+            {
+            PRINT((_L("CFileWriter::RunL() Append failed 1 %d"), iError ));
+            delete ( iFullBufferQueue[0] );
+            iFullBufferQueue.Remove( 0 );
+            return;
+            }
+        iFullBufferQueue.Remove( 0 );
+        }
+    else
+        {
+        PRINT((_L("CFileWriter::RunL() Write error in previous async: %d "), iStatus.Int() ));
+        iError = iStatus.Int();
+        return;
+        }
+
+    PRINT((_L("CFileWriter::RunL() Buffer written, Status: Full:%d Empty:%d Filesize:%d"), iFullBufferQueue.Count(), iEmptyBufferQueue.Count(), iOutputFileSize ));
+    
+    if ( iFlush )
+        {
+        PRINT(_L("CFileWriter::RunL() out, flushing"));
+        PRINT((_L("e_cfilewriter_runl 0")));  
+        return;
+        }
+        
+	// SetSize - reserve room for file writes in output file for all full buffers.
+	// This is done for performance reasons. Reserving space beforehand reduce FS overhead per write.
+	// Don't do new setsize until previously increased filesize has been filled.
+	if ( iOutputFileSetSizeCooldown ) 
+		{
+		iOutputFileSetSizeCooldown--;
+		PRINT((_L("CFileWriter::RunL() Setsize, buffer was written to reserved space, cooldown: %d"), iOutputFileSetSizeCooldown));		
+		}
+		
+	// if we have cumulated over iMaxOutputBufSoftLimit/2 full output buffers and setsize not in cooldown then set new size.
+	if ( !iOutputFileSetSizeCooldown && (iFullBufferQueue.Count() > iMaxOutputBufSoftLimit/2) )
+		{
+		PRINT(_L("CFileWriter::RunL() Setsize, start new size set"));
+		iOutputFile->SetSize(iOutputFileSize + (iFullBufferQueue.Count()*iOutputBufferSize) );
+		iOutputFileSetSizeCooldown = iFullBufferQueue.Count();
+		PRINT((_L("CFileWriter::RunL() Setsize, New size set to: %d, cooldown set: %d"), iOutputFileSize + (iFullBufferQueue.Count()*iOutputBufferSize), iOutputFileSetSizeCooldown));		
+		}
+	
+    if ( iFullBufferQueue.Count() >= iMaxOutputBufHardLimit )
+        {
+        while ( iFullBufferQueue.Count() > iMaxOutputBufSoftLimit )
+            {
+            PRINT((_L("e_cfilewriter_runl_write 1")));                     
+            iError = iOutputFile->Write( *iFullBufferQueue[0]);
+            PRINT((_L("e_cfilewriter_runl_write 0")));                     
+            if ( iError == KErrNone )
+                {
+                iOutputFileSize += iFullBufferQueue[0]->Des().Length();
+                iFullBufferQueue[0]->Des().Zero();
+                iError = iEmptyBufferQueue.Append( iFullBufferQueue[0] );
+                if ( iError )
+                    {
+                    PRINT((_L("CFileWriter::RunL() Append failed 2 %d"), iError));
+                    delete ( iFullBufferQueue[0] );
+                    iFullBufferQueue.Remove( 0 );
+                    return;
+                    }
+                iFullBufferQueue.Remove( 0 );
+    			PRINT((_L("CFileWriter::RunL() Hardlimit : Buffer sync written, Status: Full:%d Empty:%d Filesize:%d"), iFullBufferQueue.Count(), iEmptyBufferQueue.Count(), iOutputFileSize ));
+                }   
+            else
+                {
+                PRINT((_L("CFileWriter::RunL() Write error: %d "), iError));
+                return;
+                }   
+            }
+        }
+
+    if ( iFullBufferQueue.Count() >= iMaxOutputBufSoftLimit )
+        {
+        PRINT((_L("e_cfilewriter_runl_outfile_write 1")));                     
+        iError = iOutputFile->Write( *iFullBufferQueue[0]);
+        PRINT((_L("e_cfilewriter_runl_outfile_write 0")));                     
+        if ( iError == KErrNone )
+            {
+            iOutputFileSize += iFullBufferQueue[0]->Des().Length();
+            iFullBufferQueue[0]->Des().Zero();
+            iError = iEmptyBufferQueue.Append( iFullBufferQueue[0] );
+            if ( iError )
+                {
+                PRINT((_L("CFileWriter::RunL() Append failed 3 %d"), iError));
+                delete ( iFullBufferQueue[0] );
+                iFullBufferQueue.Remove( 0 );
+                return;
+                }
+            iFullBufferQueue.Remove( 0 );
+    		PRINT((_L("CFileWriter::RunL() Softlimit : Buffer sync written, Status: Full:%d Empty:%d Filesize:%d"), iFullBufferQueue.Count(), iEmptyBufferQueue.Count(), iOutputFileSize ));
+            }   
+        else
+            {
+            PRINT((_L("CFileWriter::RunL() Write error: %d "), iError));
+            return;
+            }
+        }
+
+    if ( iFullBufferQueue.Count() )
+        {
+        PRINT((_L("e_cfilewriter_runl_outfile2_write 1")));                     
+        iOutputFile->Write( *iFullBufferQueue[0], iStatus );
+        PRINT((_L("e_cfilewriter_runl_outfile2_write 0")));                     
+        iAsyncWritingOngoing = ETrue;
+        if ( !IsActive() )
+            {
+            SetActive();
+            }
+        }
+
+	PRINT((_L("e_cfilewriter_runl 0")));  
+    PRINT((_L("CFileWriter::RunL() out, iError=%d"), iError));
+    }
+
+//  End of File