--- /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