mmplugins/lib3gp/impl/src/metadatafilewriter.cpp
author hgs
Mon, 23 Aug 2010 20:19:06 +0100
changeset 45 5accba95f577
parent 0 40261b775718
permissions -rw-r--r--
2010wk29_03

// 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 "metadatafilewriter.h"

// MACROS
// Debug print macro
#ifdef _DEBUG
#include <e32svr.h>
#define PRINT(x)
#else
#define PRINT(x)
#endif

const TInt KMetaDataWriterBufferSize        = (4*4096);
const TInt KMetaDataWriterInputBufCount     = 10;
const TInt KMetaDataWriterOutputBufCount    = 4;

// ============================ MEMBER FUNCTIONS ===============================

CMetaDataWriterBuffer::~CMetaDataWriterBuffer()
    {
    delete iData;
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::CMetaDataFileWriter
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CMetaDataFileWriter::CMetaDataFileWriter() : CActive( EPriorityHigh ) 
    {
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CMetaDataFileWriter::ConstructL( )
    {
    PRINT(_L("CMetaDataFileWriter::ConstructL() in"));

    iError = KErrNone;
    iAsyncWritingOngoing = EFalse;
    iFlush = EFalse;
    iFlushDone = EFalse;

    for (TInt i=0; i<KMetaDataWriterInputBufCount; i++)
        {
        iOutputFile.AppendL(NULL);

        CMetaDataWriterBuffer* emptyInputBuffer = new (ELeave) CMetaDataWriterBuffer;
        CleanupStack::PushL(emptyInputBuffer);
        
        emptyInputBuffer->iData = HBufC8::NewL(KMetaDataWriterBufferSize);
        emptyInputBuffer->iOutputFileNum = i;
        iInputBufferArray.AppendL(emptyInputBuffer);
        
        CleanupStack::Pop(emptyInputBuffer);
        
        iInputBufferArrayDelivered[i] = 0;
        }

    for (TInt j=0; j<KMetaDataWriterOutputBufCount; j++)
        {
        CMetaDataWriterBuffer* emptyOutputBuffer = new (ELeave) CMetaDataWriterBuffer;
        CleanupStack::PushL(emptyOutputBuffer);
        
        emptyOutputBuffer->iData = HBufC8::NewL(KMetaDataWriterBufferSize);
        emptyOutputBuffer->iOutputFileNum = -1;
        iEmptyBufferQueue.AppendL(emptyOutputBuffer);
        
        CleanupStack::Pop(emptyOutputBuffer);
        }

    CActiveScheduler::Add(this);

    PRINT(_L("CMetaDataFileWriter::ConstructL() out"));
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CMetaDataFileWriter* CMetaDataFileWriter::NewL()
    {
    PRINT(_L("CMetaDataFileWriter::NewL() in"));
    
    CMetaDataFileWriter* self = new(ELeave) CMetaDataFileWriter;
    CleanupStack::PushL(self);
    self->ConstructL( );
    CleanupStack::Pop(self);

    PRINT(_L("CMetaDataFileWriter::NewL() out"));
    return self;
    }


// Destructor
CMetaDataFileWriter::~CMetaDataFileWriter()
    {
    PRINT(_L("CMetaDataFileWriter::~CMetaDataFileWriter() in"));


    if ( IsActive() )
        {
        if ( iAsyncWritingOngoing )
            {
            Cancel();    
            }
        else
            {
            TRequestStatus* status = &iStatus;
            User::RequestComplete( status, KErrNone );
            Cancel();
            }
        }

    iOutputFile.Reset();
    iInputBufferArray.ResetAndDestroy();
    iOutputBufferQueue.ResetAndDestroy();
    iEmptyBufferQueue.ResetAndDestroy();
    PRINT(_L("CMetaDataFileWriter::~CMetaDataFileWriter() out"));
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::Write( const TDesC8& aBuf )
// Writes incoming buffer data to internal buffers for writing to disk.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMetaDataFileWriter:: Write( RFile64& aFile, const TInt aFileNumber, const TDesC8& aBuf )
    {
    PRINT(_L("CMetaDataFileWriter::Write() in"));
    PRINT((_L("e_cmetadatawriter_write 1")));

    iOutputFile[aFileNumber] = &aFile;

	PRINT((_L("e_cmetadatawriter_write_adddatatobuffer 1")));
    TInt error = AddDataToBuffer( aFileNumber, aBuf );
    if ( error != KErrNone )
        {
        PRINT((_L("CMetaDataFileWriter::Write() buffer write error: %d"), error));         
        return error;
        }
	PRINT((_L("e_cmetadatawriter_write_adddatatobuffer 0")));

    PRINT((_L("CMetaDataFileWriter::Write() Write Buffer, Status: Full:%d Empty:%d "), 
                    iOutputBufferQueue.Count(), iEmptyBufferQueue.Count() ));

    if ( iAsyncWritingOngoing )
        {
        if ( iOutputBufferQueue.Count() >= KFileWriterHardBufLimit )
            {
            PRINT((_L("CMetaDataFileWriter::Write() Waiting async write to complete")));
			PRINT((_L("e_cmetadatawriter_write_waitasync 1")));            
            User::WaitForRequest( iStatus );
			PRINT((_L("e_cmetadatawriter_write_waitasync 0")));            
            PRINT((_L("CMetaDataFileWriter::Write() Async write done")));
            TRAP(error, RunL());
            if (error != KErrNone)
            	{
            	PRINT((_L("CMetaDataFileWriter::Write() runL leave, error: %d"), error));         
                return error;
            	}
            }
        }
    else
        {
        if ( iOutputBufferQueue.Count() )
            {
            PRINT(_L("CMetaDataFileWriter::Write() writing async"));       

			PRINT((_L("e_cmetadatawriter_write_startwrite 1")));
			
            iOutputFile[iOutputBufferQueue[0]->iOutputFileNum]->Write( *(iOutputBufferQueue[0]->iData), iStatus );
			PRINT((_L("e_cmetadatawriter_write_startwrite 0")));            
            iAsyncWritingOngoing = ETrue;
            if ( !IsActive() )
                {
                SetActive();
                }
            }
        }

    PRINT(_L("CMetaDataFileWriter::Write() out"));
    PRINT((_L("e_cmetadatawriter_write 0")));    
    return error;
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::Flush( )
// Flush internal buffers to disk.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMetaDataFileWriter::Flush( )
    {
    PRINT(_L("CMetaDataFileWriter::Flush() in"));
    PRINT((_L("e_cmetadatawriter_flush 1")));
    PRINT((_L("CMetaDataFileWriter::Flush() FullCount: %d "), iOutputBufferQueue.Count()));

    TInt error = KErrNone;
    iFlush = ETrue;

    if ( iAsyncWritingOngoing )
        {
        PRINT((_L("CMetaDataFileWriter::Flush() Waiting async write to complete")));
        PRINT((_L("e_cmetadatawriter_flush_waitasyncstop 1")));
        User::WaitForRequest( iStatus );
		PRINT((_L("e_cmetadatawriter_flush_waitasyncstop 0")));        
        PRINT((_L("CMetaDataFileWriter::Flush() Async write done, flushing")));
        TRAP(error, RunL());
        if (error != KErrNone)
        	{
        	PRINT((_L("CMetaDataFileWriter::Flush() call runL leave, error: %d"), error));         
            return error;
        	}
        }

    while ( iOutputBufferQueue.Count() )
        {
        PRINT((_L("e_cmetadatawriter_flush_writesync 1")));
        
        error = iOutputFile[iOutputBufferQueue[0]->iOutputFileNum]->Write( *(iOutputBufferQueue[0]->iData) );
        if ( error == KErrNone )
            {
            error = iEmptyBufferQueue.Append(iOutputBufferQueue[0]);
            if (error == KErrNone)
            	{                   
            	iOutputBufferQueue[0]->iData->Des().Zero();
            	iOutputBufferQueue[0]->iOutputFileNum = -1;
            	iOutputBufferQueue.Remove(0);
            	}
            else
            	{
            	PRINT((_L("CMetaDataFileWriter::Flush() iEmptyBufferQueue.Append failed, error: %d"), error));
            	return error;
            	}
            }
        else
            {
            PRINT((_L("CMetaDataFileWriter::Flush() fullBufQueue write failed, error: %d"), error));
            iFlush = EFalse;
            return error;
            }
		PRINT((_L("e_cmetadatawriter_flush_writesync 0")));            
        }

    if ( !iFlushDone ) // Flush only once
        {
        iFlushDone = ETrue;
        for ( TInt i=0; i < KMetaDataWriterInputBufCount; i++ )
            {
            if ( iOutputFile[i] )
                {
		    	PRINT((_L("e_cmetadatawriter_flush_write_tempfiles 1")));
                error = iOutputFile[i]->Flush();
    			PRINT((_L("e_cmetadatawriter_flush_write_tempfiles 0")));
                PRINT((_L("CMetaDataFileWriter::Flush() inputbuf[%d] flush return code: %d"), i, error));
                }
	        }
        }

    iFlush = EFalse;
    PRINT((_L("CMetaDataFileWriter::Flush() FullCount: %d <= Should be 0"), iOutputBufferQueue.Count()));
    PRINT(_L("CMetaDataFileWriter::Flush() out"));
    PRINT((_L("e_cmetadatawriter_flush 0")));
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::AddDataToBuffer( const TDesC8& aBuf )
// Writes incoming data to internal buffers and buffer queues..
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CMetaDataFileWriter::AddDataToBuffer(const TInt aFileNumber, const TDesC8& aBuf )
    {
    PRINT(_L("CMetaDataFileWriter::AddDataToBuffer() in"));

    TInt byteswritten = 0;
    TInt numbytes = 0;
    TInt available = 0; // Available bytes in write buffer
    TInt error = KErrNone;
    
    HBufC8* inputBuf = iInputBufferArray[aFileNumber]->iData;

    if ( iError != KErrNone )
        {
        PRINT((_L("CMetaDataFileWriter::AddDataToBuffer() out, RunL iError: %d"), iError));
        return iError;
        }

    PRINT((_L("CMetaDataFileWriter::AddDataToBuffer() Save Buffer, Size: %d "),  aBuf.Length() ));

    while (byteswritten < aBuf.Length() )
        {
        available = (inputBuf->Des()).MaxLength() - inputBuf->Length();

        if (available > 0)
            {
            numbytes = aBuf.Length() - byteswritten;
            if (numbytes > available)
                {
                numbytes = available;
                }
            inputBuf->Des().Append( aBuf.Mid( byteswritten, numbytes ) );
            byteswritten += numbytes;
            }
        else // Buffer is full, move it to outputqueue and use empty/new buf as input.
            {
            if ( iEmptyBufferQueue.Count() == 0 )
                {
                CMetaDataWriterBuffer* emptyInputBuffer = 0;

                emptyInputBuffer = new CMetaDataWriterBuffer;
                if ( !emptyInputBuffer )
                    {
                    PRINT((_L("CMetaDataFileWriter::AddDataToBuffer(), memory alloc failed")));
                    iError = KErrNoMemory;
                    break;
                    }

                TRAP(error, emptyInputBuffer->iData = HBufC8::NewL( KMetaDataWriterBufferSize ));
                if ( error != KErrNone )
                    {
                    PRINT((_L("CMetaDataFileWriter::AddDataToBuffer(), memory alloc failed: %d"), error));
                    delete emptyInputBuffer;
                    emptyInputBuffer = NULL;
                    iError = error;
                    break;
                    }
                else
                    {                    
                    error = iOutputBufferQueue.Append(iInputBufferArray[aFileNumber]);
                    if (error != KErrNone)
                    	{
                        PRINT((_L("CMetaDataFileWriter::AddDataToBuffer(), memory alloc failed: %d"), error));
                        delete emptyInputBuffer;
                        emptyInputBuffer = NULL;
                        iError = error;
                        break;
                    	}
                    
                	// old full buffer to output queue.
                    emptyInputBuffer->iOutputFileNum = aFileNumber;
                    
                    // new buffer to input.
                    iInputBufferArray[aFileNumber] = emptyInputBuffer;
                    }
                }
            else
                {
                // old full buffer to output queue.
                TInt err = iOutputBufferQueue.Append( iInputBufferArray[aFileNumber] );
                if (err != KErrNone)
                	{
                	PRINT((_L("CMetaDataFileWriter::AddDataToBuffer(), iOutputBufferQueue.Append failed: %d"), err));
                	iError = err;
                	break;
                	}
                
                // empty buffer from empty queue to input.
                iInputBufferArray[aFileNumber] = iEmptyBufferQueue[0];
                iInputBufferArray[aFileNumber]->iData->Des().Zero();
                iInputBufferArray[aFileNumber]->iOutputFileNum = aFileNumber;
                iEmptyBufferQueue.Remove(0);                
                }

            inputBuf = iInputBufferArray[aFileNumber]->iData;
            }
        }

    PRINT((_L("CMetaDataFileWriter::AddDataToBuffer() out, error: %d"), error));
    return error;
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::DoCancel()
// From CActive Cancels async request.
// -----------------------------------------------------------------------------
//
void CMetaDataFileWriter::DoCancel()
    {
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::RunL()
// From CActive Called when async request completes.
// -----------------------------------------------------------------------------
//
void CMetaDataFileWriter::RunL()
    {
    PRINT(_L("CMetaDataFileWriter::RunL() in"));
	PRINT((_L("e_cmetadatawriter_runl 1")));
    iAsyncWritingOngoing = EFalse;

    if ( iStatus == KErrNone )
        {
        iEmptyBufferQueue.AppendL( iOutputBufferQueue[0] );        
        iOutputBufferQueue[0]->iData->Des().Zero();
        iOutputBufferQueue[0]->iOutputFileNum = -1;
        iOutputBufferQueue.Remove( 0 );
        }
    else
        {
        PRINT((_L("CMetaDataFileWriter::RunL() Write error in previous async: %d "), iStatus.Int() ));
        iError = iStatus.Int();
        return;
        }

    PRINT((_L("CMetaDataFileWriter::RunL() Buffer written, Status: Full:%d Empty:%d "), iOutputBufferQueue.Count(), iEmptyBufferQueue.Count() ));
    
    if ( iFlush )
        {
        PRINT(_L("CMetaDataFileWriter::RunL() out, flushing"));
        PRINT((_L("e_cmetadatawriter_runl 0")));
        return;
        }

    if ( iOutputBufferQueue.Count() >= KFileWriterHardBufLimit )
        {
        while ( iOutputBufferQueue.Count() > KFileWriterSoftBufLimit )
            {
        	PRINT((_L("e_cmetadatawriter_runl1_write 1")));
            iError = iOutputFile[iOutputBufferQueue[0]->iOutputFileNum]->Write( *(iOutputBufferQueue[0]->iData));
        	PRINT((_L("e_cmetadatawriter_runl1_write 0")));
            if ( iError == KErrNone )
                {
                iEmptyBufferQueue.AppendL( iOutputBufferQueue[0] );
                iOutputBufferQueue[0]->iData->Des().Zero();
                iOutputBufferQueue[0]->iOutputFileNum = -1;                
                iOutputBufferQueue.Remove( 0 );
                }   
            else
                {
                PRINT((_L("CMetaDataFileWriter::RunL() Write error: %d "), iError));
                return;
                }   
            }
        }

    if ( iOutputBufferQueue.Count() >= KFileWriterSoftBufLimit )
        {
      	PRINT((_L("e_cmetadatawriter_runl2_write 1")));
        iError = iOutputFile[iOutputBufferQueue[0]->iOutputFileNum]->Write(  *(iOutputBufferQueue[0]->iData));
      	PRINT((_L("e_cmetadatawriter_runl2_write 0")));
        if ( iError == KErrNone )
            {
            iEmptyBufferQueue.AppendL( iOutputBufferQueue[0] );            
            iOutputBufferQueue[0]->iData->Des().Zero();
            iOutputBufferQueue[0]->iOutputFileNum = -1;
            iOutputBufferQueue.Remove( 0 );
            }   
        else
            {
            PRINT((_L("CMetaDataFileWriter::RunL() Write error: %d "), iError));
            return;
            }
        }

    if ( iOutputBufferQueue.Count() )
        {
      	PRINT((_L("e_cmetadatawriter_runl3_write 1")));
        iOutputFile[iOutputBufferQueue[0]->iOutputFileNum]->Write( *(iOutputBufferQueue[0]->iData), iStatus );
      	PRINT((_L("e_cmetadatawriter_runl3_write 0")));
        iAsyncWritingOngoing = ETrue;
        if ( !IsActive() )
            {
            SetActive();
            }
        }

	PRINT((_L("e_cmetadatawriter_runl 0")));
    PRINT(_L("CMetaDataFileWriter::RunL() out"));
    }

// -----------------------------------------------------------------------------
// CMetaDataFileWriter::RunError
// -----------------------------------------------------------------------------
//
 TInt CMetaDataFileWriter::RunError(TInt aError)
	 {
	 //RunL can leave.
	 iError = aError;
	 return KErrNone ;
	 }
 
// -----------------------------------------------------------------------------
// CMetaDataFileWriter::ReadBuffer
// -----------------------------------------------------------------------------
//
TInt CMetaDataFileWriter::ReadBuffer( const TInt aFileNumber, TDes8& aBuf, TInt bytestoread )
    {
    PRINT(_L("CMetaDataFileWriter::ReadBuffer() in"));
	PRINT((_L("e_cmetadatawriter_readbuffer 1")));
    TInt bytesread;
    
    PRINT((_L("CMetaDataFileWriter::ReadBuffer() iInputBufferArray[%d]->iData->Length(): %d, requested %d"), aFileNumber, iInputBufferArray[aFileNumber]->iData->Length(), bytestoread));
    if ( !iInputBufferArray[aFileNumber]->iData->Length() )
        {
        bytesread = 0;
        }
    else if ( (iInputBufferArray[aFileNumber]->iData->Length() -
        iInputBufferArrayDelivered[aFileNumber]) >= bytestoread )
        {
        bytesread = bytestoread;
        aBuf.Append( iInputBufferArray[aFileNumber]->iData->Mid( iInputBufferArrayDelivered[aFileNumber], bytesread ) );
        iInputBufferArrayDelivered[aFileNumber] += bytesread;
        
        // If the buffer is read empty, release it
        if ( iInputBufferArray[aFileNumber]->iData->Length() == iInputBufferArrayDelivered[aFileNumber] )
            {
            PRINT((_L("CMetaDataFileWriter::ReadBuffer() iInputBufferArray[%d] %d delivered"), aFileNumber, iInputBufferArray[aFileNumber]->iData->Length()));
            iInputBufferArray[aFileNumber]->iData->Des().Zero();
            }
        }
    else
        {
        bytesread = iInputBufferArray[aFileNumber]->iData->Length() - iInputBufferArrayDelivered[aFileNumber];
        aBuf.Append( iInputBufferArray[aFileNumber]->iData->Mid( iInputBufferArrayDelivered[aFileNumber], bytesread ) );
        iInputBufferArrayDelivered[aFileNumber] += bytesread;

        PRINT((_L("CMetaDataFileWriter::ReadBuffer() iInputBufferArray[%d] %d bytes delivered"), aFileNumber, iInputBufferArray[aFileNumber]->iData->Length()));
        iInputBufferArray[aFileNumber]->iData->Des().Zero();
        }
        
	PRINT((_L("e_cmetadatawriter_readbuffer 0")));
    PRINT(_L("CMetaDataFileWriter::ReadBuffer() out"));

    return ( bytesread );
    }

//  End of File