videoeditorengine/vedengine/videoprocessor/src/activequeue.cpp
author Mikael Laine <mikael.laine@ixonos.com>
Fri, 29 Jan 2010 14:08:33 +0200
changeset 0 951a5db380a0
permissions -rw-r--r--
Committing the Video Editor package under the Eclipse Public License

/*
* Copyright (c) 2010 Ixonos Plc.
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the "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:
* Ixonos Plc
*
* Description:  
* Data buffering and queuing support definitions, class CActiveQueue.
*
*/


//  EXTERNAL RESOURCES  


//  Include Files  

#include "dataprocessor.h"
#include "activequeue.h"


//  MEMBER FUNCTIONS


//=============================================================================


/*
-----------------------------------------------------------------------------

    CActiveQueue

    CActiveQueue()

    Standard C++ constructor

-----------------------------------------------------------------------------
*/

CActiveQueue::CActiveQueue(TUint aNumberOfBlocks, TUint aBlockLength)
{
    // Remember the number of blocks and initial new block length
    iInitialBlocks = aNumberOfBlocks;
    iNewBlockLength = aBlockLength;   
    iStreamEnd = EFalse;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    ~CActiveQueue()

    Standard C++ destructor

-----------------------------------------------------------------------------
*/

CActiveQueue::~CActiveQueue()
{
    // Deallocate all blocks:
    while ( iBlocks )
    {
        TRAPD( error, FreeBlockL(iBlocks) );
        if (error != KErrNone) { }
    }

    __ASSERT_DEBUG(iNumBlocks == 0,
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    ConstructL()

    Standard Symbian OS second-phase constructor, prepares the object for use

-----------------------------------------------------------------------------
*/

void CActiveQueue::ConstructL()
{
    // Allocate initial blocks
    while ( iInitialBlocks-- )
    {
        // Get block
        TActiveQueueBlock *block = AllocateBlockL();

        // Add it to the free block list
        block->iNextList = iFreeList;
        iFreeList = block;
        iNumFreeBlocks++;
    }
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    SetReader()

    Sets a reader for the queue

-----------------------------------------------------------------------------
*/

void CActiveQueue::SetReader(CDataProcessor *aReader, TAny *aUserPointer)
{
    iReader = aReader;
    iReaderUserPointer = aUserPointer;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    RemoveReader()

    Removes a reader from the queue

-----------------------------------------------------------------------------
*/

void CActiveQueue::RemoveReader()
{
    __ASSERT_DEBUG(iReader, User::Panic(_L("CActiveQueue"), ENoReader));
    iReader = 0;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    SetWriter()

    Sets a writer for the queue

-----------------------------------------------------------------------------
*/

void CActiveQueue::SetWriter(CDataProcessor *aWriter, TAny *aUserPointer)
{
    iWriter = aWriter;
    iWriterUserPointer = aUserPointer;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    RemoveWriter()

    Removes a writer from the queue

-----------------------------------------------------------------------------
*/

void CActiveQueue::RemoveWriter()
{
    __ASSERT_DEBUG(iWriter, User::Panic(_L("CActiveQueue"), ENoWriter));
    iWriter = 0;
}

/*
-----------------------------------------------------------------------------

    CActiveQueue

    ResetStreamEnd()

    Reset the status of the queue

-----------------------------------------------------------------------------
*/

void CActiveQueue::ResetStreamEnd()
{
    iStreamEnd = EFalse;
    // we should not have any blocks in full queue if we have reached stream end
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    NumFreeBlocks()

    Get the number of free blocks available for new data

-----------------------------------------------------------------------------
*/

TUint CActiveQueue::NumFreeBlocks()
{
    return iNumFreeBlocks;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    NumDataBlocks()

    Get the number of blocks with data queued

-----------------------------------------------------------------------------
*/

TUint CActiveQueue::NumDataBlocks()
{
    return iNumDataBlocks;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    GetFreeBlockL()

    Get a free block for writing data into the queue (writer)

-----------------------------------------------------------------------------
*/

TPtr8 *CActiveQueue::GetFreeBlockL(TUint aBlockLength)
{
    __ASSERT_DEBUG(iWriter, User::Panic(_L("CActiveQueue"), ENoWriter));
    TActiveQueueBlock *block = 0;
    
    // If the requested block size is larger than the currently used length
    // for new blocks, use the new size for all new blocks
    if ( aBlockLength > iNewBlockLength )
        iNewBlockLength = aBlockLength;

    // Do we have free blocks?
    if ( iNumFreeBlocks )
    {
        // Yes, get a block from the queue:
        __ASSERT_DEBUG(iFreeList != 0,
                       User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
        block = iFreeList;
        iFreeList = block->iNextList;
        iNumFreeBlocks--;

        // If the block isn't large enough, discard it so that we'll allocate a
        // new one. Don't discard more than one block to keep the number of
        // blocks allocated constant.
        if ( block->MaxLength() < (TInt) aBlockLength )
        {
            FreeBlockL(block);
            block = 0;
        }
    }

    // If we didn't get a suitable block, allocate a new one
    if ( !block )
        block = AllocateBlockL();

    __ASSERT_DEBUG(block->MaxLength() >= (TInt) aBlockLength,
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));

    block->SetLength(0);

    return block;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    WriteBlock()

    Add a data block to the queue (writer)

-----------------------------------------------------------------------------
*/

void CActiveQueue::WriteBlock(TPtr8 *aBlock)
{
    __ASSERT_DEBUG(iWriter, User::Panic(_L("CActiveQueue"), ENoWriter));
    __ASSERT_DEBUG(!iStreamEnd,
                   User::Panic(_L("CActiveQueue"), EWriteAfterStreamEnd));
                   
    // The block is really a TActiveQueueBlock
    TActiveQueueBlock *block = (TActiveQueueBlock*) aBlock;


    // Add the block to the queue:
    if ( iDataQueueTail )
    {
        // The queue is not empty
        __ASSERT_DEBUG(iDataQueueHead && iNumDataBlocks,
                       User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
        iDataQueueTail->iNextList = block;
        iDataQueueTail = block;
        block->iNextList = 0;
    }
    else
    {
        // The queue is empty -> this will be the first block
        __ASSERT_DEBUG((!iDataQueueHead) && (!iNumDataBlocks),
                       User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
        iDataQueueHead = block;
        iDataQueueTail = block;
        block->iNextList = 0;
    }
    iNumDataBlocks++;

    // If we have a reader, notify it about the new data
    if ( iReader )
        iReader->InputDataAvailable(iReaderUserPointer);
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    ReadBlock()

    Read a data block from the queue (reader)

-----------------------------------------------------------------------------
*/

TPtr8 *CActiveQueue::ReadBlock()
{
    __ASSERT_DEBUG(iReader, User::Panic(_L("CActiveQueue"), ENoReader));
    __ASSERT_DEBUG(((iNumDataBlocks && iDataQueueHead) ||
                    ((!iNumDataBlocks) && (!iDataQueueHead))),
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));

    // If we don't have a block, return NULL
    if ( !iNumDataBlocks )
        return 0;

    // Get the block from the queue head
    TActiveQueueBlock *block = iDataQueueHead;
    iDataQueueHead = block->iNextList;
    iNumDataBlocks--;
    if ( !iNumDataBlocks )
    {
        // It was the only block in the queue
        __ASSERT_DEBUG((!iDataQueueHead) && (iDataQueueTail == block),
                       User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
        iDataQueueTail = 0;                       
    }
    __ASSERT_DEBUG((iDataQueueHead != block) && (iDataQueueTail != block),
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));

    // If it was the last block and the stream end has been signaled, notify
    // the reader
    if ( iStreamEnd && (!iNumDataBlocks) )
        iReader->StreamEndReached(iReaderUserPointer);

    // Return the block
    return ((TPtr8*) block);
}


/*
-----------------------------------------------------------------------------

    CActiveQueue

    ReturnBlock()

    Return a read block back to the empty block list (reader)

-----------------------------------------------------------------------------
*/

void CActiveQueue::ReturnBlock(TPtr8 *aBlock)
{
    __ASSERT_DEBUG(iReader, User::Panic(_L("CActiveQueue"), ENoReader));
                   
    // The block is really a TActiveQueueBlock
    TActiveQueueBlock *block = (TActiveQueueBlock*) aBlock;


    // Add it to the free list:
    __ASSERT_DEBUG((((!iNumFreeBlocks) && (!iFreeList)) ||
                    (iNumFreeBlocks && iFreeList)),
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));

    if ( block->MaxLength() == 0 )
    {
        block->MaxLength();
    }

    block->iNextList = iFreeList;
    iFreeList = block;
    iNumFreeBlocks++;

    // If we have a writer, notify it about the empty block
    if ( iWriter )
        iWriter->OutputSpaceAvailable(iWriterUserPointer);
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    WriteStreamEnd()

    Notify that the stream has ended (writer)

-----------------------------------------------------------------------------
*/

void CActiveQueue::WriteStreamEnd()
{
    __ASSERT_DEBUG(iWriter, User::Panic(_L("CActiveQueue"), ENoWriter));

    // Mark that the stream has ended
    iStreamEnd = ETrue;

    // If we have a reader and there are no more blocks in the queue, signal
    // the reader
    if ( iReader && (!iNumDataBlocks) )
        iReader->StreamEndReached(iReaderUserPointer);
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    StreamEnded()

    Check if the writer has notified that the stream has ended (reader)

-----------------------------------------------------------------------------
*/

TBool CActiveQueue::StreamEnded()
{
    return iStreamEnd;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    AllocateBlockL()

    Allocates a new data block of size iNewBlockLengh

-----------------------------------------------------------------------------
*/

TActiveQueueBlock *CActiveQueue::AllocateBlockL()
{
    // Allocate the data area for the block
    TUint8 *data = (TUint8*) User::AllocLC(iNewBlockLength);    

    // Allocate the block
    TActiveQueueBlock *block = new (ELeave) TActiveQueueBlock(data,
                                                              iNewBlockLength);

    CleanupStack::Pop(data);

    // Add the block to the list of all blocks:
    if ( iBlocks )
    {
        block->iNextBlock = iBlocks;
        block->iPrevBlock = 0;
        iBlocks->iPrevBlock = block;
        iBlocks = block;
    }
    else
    {
        block->iNextBlock = 0;
        block->iPrevBlock = 0;
        iBlocks = block;
    }

    __ASSERT_DEBUG((iBlocks &&
                    ((iBlocks->iNextBlock == 0) ||
                     (iBlocks->iNextBlock != iBlocks))),
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));

    return block;
}



/*
-----------------------------------------------------------------------------

    CActiveQueue

    FreeBlockL()

    Deallocates a block allocated with AllocateBlockL()

-----------------------------------------------------------------------------
*/

void CActiveQueue::FreeBlockL(TActiveQueueBlock *aBlock)
{
    __ASSERT_DEBUG((((aBlock->iPrevBlock != aBlock->iNextBlock) ||
                     (aBlock->iNextBlock == 0)) &&
                    ((aBlock == iBlocks) || (aBlock->iPrevBlock != 0))),
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
    
    // Remove the block from the list of all blocks:
    if ( aBlock->iPrevBlock )
        aBlock->iPrevBlock->iNextBlock = aBlock->iNextBlock;
    else
        iBlocks = aBlock->iNextBlock;
    if ( aBlock->iNextBlock )
        aBlock->iNextBlock->iPrevBlock = aBlock->iPrevBlock;

    // Free the data area
    TUint8 *data = (TUint8*) aBlock->Ptr();    
    User::Free(data);

    // Free the block:
    delete aBlock;

    __ASSERT_DEBUG(((!iBlocks) ||
                    (((iBlocks->iNextBlock == 0) ||
                      (iBlocks->iNextBlock != iBlocks)) &&
                     (iBlocks->iPrevBlock == 0))),
                   User::Panic(_L("CActiveQueue"), EInternalAssertionFailure));
}





// End of File