sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: sl@0: // INCLUDE FILES sl@0: #include sl@0: #include sl@0: #include "mp4atom.h" sl@0: #include "filewriter.h" sl@0: sl@0: // MACROS sl@0: // Debug print macro sl@0: #ifdef _DEBUG sl@0: #include sl@0: //#define PRINT(x) RDebug::Print x sl@0: #define PRINT(x) sl@0: #else sl@0: #define PRINT(x) sl@0: #endif sl@0: sl@0: // ============================ MEMBER FUNCTIONS =============================== sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::CFileWriter sl@0: // C++ default constructor can NOT contain any code, that sl@0: // might leave. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CFileWriter::CFileWriter( TInt aInitSetSize, TInt aOutputBufferSizeSmall, TInt aOutputBufferSizeLarge ): sl@0: CActive( EPriorityHigh ), sl@0: iSetSize( aInitSetSize ), sl@0: iOutputBufferSizeSmall( aOutputBufferSizeSmall ), sl@0: iOutputBufferSizeLarge( aOutputBufferSizeLarge ) sl@0: { sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::ConstructL sl@0: // Symbian 2nd phase constructor can leave. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CFileWriter::ConstructL( RFile64& aFile ) sl@0: { sl@0: PRINT((_L("CFileWriter::ConstructL() in"))); sl@0: iFlush = EFalse; sl@0: iError = KErrNone; sl@0: sl@0: iOutputFile = &aFile; sl@0: iWritingStarted = EFalse; sl@0: iOutputBufferSize = KFileWriterBufferSizeSmall; sl@0: iMaxOutputBufHardLimit = KFileWriterHardBufLimit; sl@0: iMaxOutputBufSoftLimit = KFileWriterSoftBufLimit; sl@0: sl@0: iMemReadyForWriting = EFalse; sl@0: iInputBuf = NULL; sl@0: iEmptyBufferQueue.Reset(); sl@0: iFullBufferQueue.Reset(); sl@0: sl@0: AllocateBuffersL(); sl@0: CActiveScheduler::Add(this); sl@0: PRINT((_L("CFileWriter::ConstructL() out"))); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::NewL sl@0: // Two-phased constructor. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CFileWriter* CFileWriter::NewL( RFile64& aFile, TInt aInitSetSize, TInt aOutputBufferSizeSmall, TInt aOutputBufferSizeLarge ) sl@0: { sl@0: CFileWriter* self = new(ELeave) CFileWriter( aInitSetSize, aOutputBufferSizeSmall, aOutputBufferSizeLarge ); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL( aFile ); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: // Destructor sl@0: CFileWriter::~CFileWriter() sl@0: { sl@0: PRINT((_L("CFileWriter::~CFileWriter() in"))); sl@0: if ( IsActive() ) sl@0: { sl@0: if ( iAsyncWritingOngoing ) sl@0: { sl@0: Cancel(); sl@0: } sl@0: else sl@0: { sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete( status, KErrNone ); sl@0: Cancel(); sl@0: } sl@0: } sl@0: sl@0: if ( iInputBuf ) sl@0: { sl@0: delete iInputBuf; sl@0: } sl@0: sl@0: iEmptyBufferQueue.ResetAndDestroy(); sl@0: iFullBufferQueue.ResetAndDestroy(); sl@0: PRINT((_L("CFileWriter::~CFileWriter() out"))); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::UpdateOutputFileSize() sl@0: // Updates output file size and reserves extra space for following writing sl@0: // if iSetSize is set. sl@0: // Takes into account if the position in the file was changed. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CFileWriter::UpdateOutputFileSize() sl@0: { sl@0: TInt64 pos = 0; sl@0: PRINT((_L("e_cfilewriter_write_updateoutputfilesize_seek 1"))); sl@0: iOutputFile->Seek(ESeekCurrent, pos); sl@0: PRINT((_L("e_cfilewriter_write_updateoutputfilesize_seek 0"))); sl@0: sl@0: PRINT((_L("CFileWriter::UpdateOutputFileSize() pos: %Ld"), pos)); sl@0: PRINT((_L("CFileWriter::UpdateOutputFileSize() iOutputFileSize: %Ld"), iOutputFileSize)); sl@0: PRINT((_L("CFileWriter::UpdateOutputFileSize() iSetSize: %Ld"), iSetSize)); sl@0: sl@0: if (pos > iOutputFileSize) sl@0: { sl@0: iOutputFileSize = pos; sl@0: } sl@0: sl@0: while (iOutputFileSize >= iSetSize) sl@0: { sl@0: iSetSize += static_cast(iOutputBufferSize) * (static_cast(iMaxOutputBufHardLimit) >> 1); sl@0: PRINT((_L("e_cfilewriter_updateoutputfilesize_setsize 1"))); sl@0: iOutputFile->SetSize( iSetSize ); sl@0: PRINT((_L("e_cfilewriter_updateoutputfilesize_setsize 0"))); sl@0: } sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::Write( const TDesC8& aBuf ) sl@0: // Writes incoming buffer data to internal buffers for writing to disk. sl@0: // (other items were commented in a header). sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt CFileWriter::Write( const TDesC8& aBuf ) sl@0: { sl@0: PRINT(_L("CFileWriter::Write() in")); sl@0: PRINT((_L("e_cfilewriter_write 1"))); sl@0: sl@0: iWritingStarted = ETrue; sl@0: sl@0: if ( !iMemReadyForWriting ) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: PRINT((_L("e_cfilewriter_write_adddatatobuffer 1"))); sl@0: TInt error = AddDataToBuffer( aBuf ); sl@0: PRINT((_L("e_cfilewriter_write_adddatatobuffer 0"))); sl@0: sl@0: if ( error != KErrNone ) sl@0: { sl@0: PRINT((_L("CFileWriter::Write() buffer write error: %d"), error)); sl@0: return error; sl@0: } sl@0: sl@0: PRINT((_L("CFileWriter::Write() Write Buffer, Status: Full:%d Empty:%d "), sl@0: iFullBufferQueue.Count(), iEmptyBufferQueue.Count() )); sl@0: sl@0: if ( iAsyncWritingOngoing ) sl@0: { sl@0: if ( iFullBufferQueue.Count() >= iMaxOutputBufHardLimit ) sl@0: { sl@0: PRINT((_L("CFileWriter::Write() Waiting async write to complete"))); sl@0: PRINT((_L("e_cfilewriter_write_wait_async 1"))); sl@0: User::WaitForRequest( iStatus ); sl@0: PRINT((_L("e_cfilewriter_write_wait_async 0"))); sl@0: PRINT((_L("CFileWriter::Write() Async write done"))); sl@0: TRAP(error, RunL()); sl@0: if (error != KErrNone) sl@0: { sl@0: PRINT((_L("CFileWriter::Write() call runL leave, error: %d"), error)); sl@0: return error; sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if ( iFullBufferQueue.Count() ) sl@0: { sl@0: PRINT(_L("CFileWriter::Write() writing async")); sl@0: PRINT((_L("e_cfilewriter_write_startwrite 1"))); sl@0: iOutputFile->Write( *iFullBufferQueue[0], iStatus ); sl@0: PRINT((_L("e_cfilewriter_write_startwrite 0"))); sl@0: iAsyncWritingOngoing = ETrue; sl@0: if ( !IsActive() ) sl@0: { sl@0: SetActive(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: PRINT(_L("CFileWriter::Write() out")); sl@0: PRINT((_L("e_cfilewriter_write 0"))); sl@0: return error; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::Flush( const TDesC8& aBuf ) sl@0: // Flush internal buffers to disk. sl@0: // (other items were commented in a header). sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt CFileWriter::Flush( const TDesC8& aBuf ) sl@0: { sl@0: PRINT(_L("CFileWriter::Flush() in")); sl@0: PRINT((_L("e_cfilewriter_flush 1"))); sl@0: sl@0: if ( !iMemReadyForWriting ) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: iWritingStarted = ETrue; sl@0: sl@0: PRINT((_L("e_cfilewriter_flush_adddatatobuf 1"))); sl@0: TInt error = AddDataToBuffer( aBuf ); sl@0: if ( error != KErrNone ) sl@0: { sl@0: return error; sl@0: } sl@0: PRINT((_L("e_cfilewriter_flush_adddatatobuf 0"))); sl@0: sl@0: PRINT((_L("CFileWriter::Flush() FullCount: %d "), iFullBufferQueue.Count())); sl@0: iFlush = ETrue; sl@0: sl@0: if ( iAsyncWritingOngoing ) sl@0: { sl@0: PRINT((_L("CFileWriter::Flush() Waiting async write to complete"))); sl@0: PRINT((_L("e_cfilewriter_flush_waitasynctostop 1"))); sl@0: User::WaitForRequest( iStatus ); sl@0: PRINT((_L("e_cfilewriter_flush_waitasynctostop 0"))); sl@0: PRINT((_L("CFileWriter::Flush() Async write done, flushing"))); sl@0: TRAP(error, RunL()); sl@0: if (error != KErrNone) sl@0: { sl@0: PRINT((_L("CFileWriter::Flush() call runL leave, error: %d"), error)); sl@0: return error; sl@0: } sl@0: } sl@0: sl@0: while ( iFullBufferQueue.Count() ) sl@0: { sl@0: PRINT((_L("e_cfilewriter_flush_writequeue_sync 1"))); sl@0: error = iOutputFile->Write( *iFullBufferQueue[0] ); sl@0: PRINT((_L("e_cfilewriter_flush_writequeue_sync 0"))); sl@0: PRINT((_L("e_cfilewriter_flush_remove_buf 1"))); sl@0: if ( error == KErrNone ) sl@0: { sl@0: UpdateOutputFileSize(); sl@0: iFullBufferQueue[0]->Des().Zero(); sl@0: if ( iEmptyBufferQueue.Append( iFullBufferQueue[0] ) ) sl@0: { sl@0: PRINT(_L("CFileWriter::Flush() Append failed")); sl@0: delete ( iFullBufferQueue[0] ); sl@0: } sl@0: iFullBufferQueue.Remove( 0 ); sl@0: } sl@0: else sl@0: { sl@0: PRINT((_L("CFileWriter::Flush() fullBufQueue write failed, error: %d"), error)); sl@0: iFlush = EFalse; sl@0: return error; sl@0: } sl@0: PRINT((_L("e_cfilewriter_flush_remove_buf 0"))); sl@0: } sl@0: sl@0: if ( iInputBuf->Length() ) sl@0: { sl@0: PRINT((_L("e_cfilewriter_flush_writeinput_sync 1"))); sl@0: error = iOutputFile->Write( *iInputBuf ); sl@0: PRINT((_L("e_cfilewriter_flush_writeinput_sync 0"))); sl@0: if ( error == KErrNone ) sl@0: { sl@0: UpdateOutputFileSize(); sl@0: iInputBuf->Des().Zero(); sl@0: } sl@0: else sl@0: { sl@0: PRINT((_L("CFileWriter::Flush() inputbuf write failed, error: %d"), error)); sl@0: iFlush = EFalse; sl@0: return error; sl@0: } sl@0: } sl@0: sl@0: iFlush = EFalse; sl@0: PRINT((_L("CFileWriter::Flush() FullCount: %d <= Should be 0"), iFullBufferQueue.Count())); sl@0: PRINT(_L("CFileWriter::Flush() out")); sl@0: PRINT((_L("e_cfilewriter_flush 0"))); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::SetOutputBufferSize( TOutputBufferSize aBufferSize ) sl@0: // Set output buffer sizes. sl@0: // (other items were commented in a header). sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt CFileWriter::SetOutputBufferSize( TOutputBufferSize aBufferSize, MP4Handle aHandle ) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)aHandle; sl@0: TInt size = 0; sl@0: sl@0: if ( iWritingStarted ) sl@0: { sl@0: return KErrNotReady; sl@0: } sl@0: sl@0: if ( aBufferSize == EBufferSizeSmall ) sl@0: { sl@0: size = iOutputBufferSizeSmall; sl@0: } sl@0: else if ( aBufferSize == EBufferSizeLarge ) sl@0: { sl@0: size = iOutputBufferSizeLarge; sl@0: } sl@0: else if ( aBufferSize == EBufferSizeCustom ) sl@0: { sl@0: size = handle->mediaWriteBufferSize; sl@0: } sl@0: else sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: if ( size == iOutputBufferSize ) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: else sl@0: { sl@0: iOutputBufferSize = size; sl@0: } sl@0: sl@0: iMemReadyForWriting = EFalse; sl@0: delete iInputBuf; sl@0: iInputBuf = NULL; sl@0: iEmptyBufferQueue.ResetAndDestroy(); sl@0: iFullBufferQueue.ResetAndDestroy(); sl@0: sl@0: TRAPD(err, AllocateBuffersL() ); sl@0: return err; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::SetOutputBufferCount( MP4Handle aHandle ) sl@0: // Set output buffer count. sl@0: // (other items were commented in a header). sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CFileWriter::SetOutputBufferCount( MP4Handle aHandle ) sl@0: { sl@0: MP4HandleImp handle = (MP4HandleImp)aHandle; sl@0: sl@0: if ( handle->writeBufferMaxCount >= 6 ) sl@0: { sl@0: iMaxOutputBufHardLimit = handle->writeBufferMaxCount; sl@0: iMaxOutputBufSoftLimit = KFileWriterMinBufferCount + ((iMaxOutputBufHardLimit-KFileWriterMinBufferCount)/2); sl@0: } sl@0: } sl@0: sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::AddDataToBuffer( const TDesC8& aBuf ) sl@0: // Writes incoming data to internal buffers and buffer queues.. sl@0: // (other items were commented in a header). sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt CFileWriter::AddDataToBuffer( const TDesC8& aBuf ) sl@0: { sl@0: PRINT(_L("CFileWriter::AddDataToBuffer() in")); sl@0: sl@0: TInt byteswritten = 0; sl@0: TInt numbytes = 0; sl@0: TInt available = 0; // Available bytes in write buffer sl@0: TInt error = KErrNone; sl@0: sl@0: if ( iError != KErrNone ) sl@0: { sl@0: PRINT((_L("CFileWriter::AddDataToBuffer() out, RunL iError: %d"), iError)); sl@0: return iError; sl@0: } sl@0: sl@0: if ( iInputBuf == NULL ) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: while (byteswritten < aBuf.Length() ) sl@0: { sl@0: available = iOutputBufferSize - iInputBuf->Length(); sl@0: sl@0: if (available > 0) sl@0: { sl@0: numbytes = aBuf.Length() - byteswritten; sl@0: if (numbytes > available) sl@0: { sl@0: numbytes = available; sl@0: } sl@0: iInputBuf->Des().Append( aBuf.Mid( byteswritten, numbytes ) ); sl@0: byteswritten += numbytes; sl@0: } sl@0: else // Buffer is full, write it to disk sl@0: { sl@0: // input is full, move full inputbuf to full buf queue sl@0: if ( iFullBufferQueue.Append( iInputBuf ) != KErrNone ) sl@0: { sl@0: PRINT(_L("CFileWriter::AddDataToBuffer() Append failed")); sl@0: delete iInputBuf; sl@0: iInputBuf = NULL; sl@0: } sl@0: if ( iEmptyBufferQueue.Count() == 0 ) sl@0: { sl@0: // no empty buffers in queue, allocating new one sl@0: TRAP(error, iInputBuf = HBufC8::NewL( iOutputBufferSize )); sl@0: if ( error != KErrNone ) sl@0: { sl@0: PRINT((_L("CFileWriter::AddDataToBuffer(), memory alloc failed: %d"), error)); sl@0: iInputBuf = NULL; sl@0: iError = error; sl@0: break; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iInputBuf = iEmptyBufferQueue[ 0 ]; sl@0: iEmptyBufferQueue.Remove( 0 ); sl@0: } sl@0: } sl@0: } sl@0: sl@0: PRINT((_L("CFileWriter::AddDataToBuffer() out, error: %d"), error)); sl@0: return error; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CFileWriter::AllocateBuffersL() sl@0: // Allocates input and output buffers. sl@0: // (other items were commented in a header). sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CFileWriter::AllocateBuffersL() sl@0: { sl@0: PRINT((_L("CFileWriter::AllocateBuffersL() in, outbufsize: %d"), iOutputBufferSize)); sl@0: HBufC8* buf = NULL; sl@0: TInt err = 0; sl@0: iMemReadyForWriting = EFalse; sl@0: sl@0: iInputBuf = HBufC8::NewL( iOutputBufferSize ); sl@0: for( TInt i=0; iDes().Zero(); sl@0: iError = iEmptyBufferQueue.Append( iFullBufferQueue[0] ); sl@0: if ( iError ) sl@0: { sl@0: PRINT((_L("CFileWriter::RunL() Append failed 1 %d"), iError )); sl@0: delete ( iFullBufferQueue[0] ); sl@0: iFullBufferQueue.Remove( 0 ); sl@0: return; sl@0: } sl@0: iFullBufferQueue.Remove( 0 ); sl@0: } sl@0: else sl@0: { sl@0: PRINT((_L("CFileWriter::RunL() Write error in previous async: %d "), iStatus.Int() )); sl@0: iError = iStatus.Int(); sl@0: return; sl@0: } sl@0: sl@0: PRINT((_L("CFileWriter::RunL() Buffer written, Status: Full:%d Empty:%d Filesize:%Ld"), iFullBufferQueue.Count(), iEmptyBufferQueue.Count(), iOutputFileSize )); sl@0: sl@0: if ( iFlush ) sl@0: { sl@0: PRINT(_L("CFileWriter::RunL() out, flushing")); sl@0: PRINT((_L("e_cfilewriter_runl 0"))); sl@0: return; sl@0: } sl@0: sl@0: if ( iFullBufferQueue.Count() >= iMaxOutputBufHardLimit ) sl@0: { sl@0: while ( iFullBufferQueue.Count() > iMaxOutputBufSoftLimit ) sl@0: { sl@0: PRINT((_L("e_cfilewriter_runl_write 1"))); sl@0: iError = iOutputFile->Write( *iFullBufferQueue[0]); sl@0: PRINT((_L("e_cfilewriter_runl_write 0"))); sl@0: if ( iError == KErrNone ) sl@0: { sl@0: UpdateOutputFileSize(); sl@0: iFullBufferQueue[0]->Des().Zero(); sl@0: iError = iEmptyBufferQueue.Append( iFullBufferQueue[0] ); sl@0: if ( iError ) sl@0: { sl@0: PRINT((_L("CFileWriter::RunL() Append failed 2 %d"), iError)); sl@0: delete ( iFullBufferQueue[0] ); sl@0: iFullBufferQueue.Remove( 0 ); sl@0: return; sl@0: } sl@0: iFullBufferQueue.Remove( 0 ); sl@0: PRINT((_L("CFileWriter::RunL() Hardlimit : Buffer sync written, Status: Full:%d Empty:%d Filesize:%Ld"), iFullBufferQueue.Count(), iEmptyBufferQueue.Count(), iOutputFileSize )); sl@0: } sl@0: else sl@0: { sl@0: PRINT((_L("CFileWriter::RunL() Write error: %d "), iError)); sl@0: return; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if ( iFullBufferQueue.Count() >= iMaxOutputBufSoftLimit ) sl@0: { sl@0: PRINT((_L("e_cfilewriter_runl_outfile_write 1"))); sl@0: iError = iOutputFile->Write( *iFullBufferQueue[0]); sl@0: PRINT((_L("e_cfilewriter_runl_outfile_write 0"))); sl@0: if ( iError == KErrNone ) sl@0: { sl@0: UpdateOutputFileSize(); sl@0: iFullBufferQueue[0]->Des().Zero(); sl@0: iError = iEmptyBufferQueue.Append( iFullBufferQueue[0] ); sl@0: if ( iError ) sl@0: { sl@0: PRINT((_L("CFileWriter::RunL() Append failed 3 %d"), iError)); sl@0: delete ( iFullBufferQueue[0] ); sl@0: iFullBufferQueue.Remove( 0 ); sl@0: return; sl@0: } sl@0: iFullBufferQueue.Remove( 0 ); sl@0: PRINT((_L("CFileWriter::RunL() Softlimit : Buffer sync written, Status: Full:%d Empty:%d Filesize:%Ld"), iFullBufferQueue.Count(), iEmptyBufferQueue.Count(), iOutputFileSize )); sl@0: } sl@0: else sl@0: { sl@0: PRINT((_L("CFileWriter::RunL() Write error: %d "), iError)); sl@0: return; sl@0: } sl@0: } sl@0: sl@0: if ( iFullBufferQueue.Count() ) sl@0: { sl@0: PRINT((_L("e_cfilewriter_runl_outfile2_write 1"))); sl@0: iOutputFile->Write( *iFullBufferQueue[0], iStatus ); sl@0: PRINT((_L("e_cfilewriter_runl_outfile2_write 0"))); sl@0: iAsyncWritingOngoing = ETrue; sl@0: if ( !IsActive() ) sl@0: { sl@0: SetActive(); sl@0: } sl@0: } sl@0: sl@0: PRINT((_L("e_cfilewriter_runl 0"))); sl@0: PRINT((_L("CFileWriter::RunL() out, iError=%d"), iError)); sl@0: } sl@0: sl@0: // End of File