omxilvideocomps/omxilvideoscheduler/src/buffercopier.cpp
author hgs
Fri, 08 Oct 2010 22:09:17 +0100
changeset 0 5d29cba61097
permissions -rw-r--r--
2010wk38_02

/*
* Copyright (c) 2008 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:
*
*/


/**
@file
@internalComponent
*/

#include "buffercopier.h"

_LIT(KBufferCopierPanic, "CBufferCopier");

CBufferCopier* CBufferCopier::NewL(MBufferCopierIf& aCallback, TInt aMaxBuffers)
	{
	CBufferCopier* self = new(ELeave) CBufferCopier(aCallback);
	CleanupStack::PushL(self);
	self->ConstructL(aMaxBuffers);
	CleanupStack::Pop(self);
	return self;
	}

CBufferCopier::CBufferCopier(MBufferCopierIf& aCallback):
CActive(EPriorityNormal),
iCallback(aCallback)
	{
	CActiveScheduler::Add(this);
	}

void CBufferCopier::ConstructL(TInt aMaxBuffers)
	{
	User::LeaveIfError(iInQueue.CreateLocal(aMaxBuffers));
	User::LeaveIfError(iOutQueue.CreateLocal(aMaxBuffers));
	User::LeaveIfError(iRemoveQueue.CreateLocal(aMaxBuffers));
	SetActive();
	iInQueue.NotifyDataAvailable(iStatus);
	}

CBufferCopier::~CBufferCopier()
	{
	Cancel();
	iInQueue.Close();
	iOutQueue.Close();
	iRemoveQueue.Close();
	}
	
void CBufferCopier::DeliverBuffer(OMX_BUFFERHEADERTYPE* aBuffer, OMX_DIRTYPE aDirection)
	{
	RMsgQueue<OMX_BUFFERHEADERTYPE*>& queue = aDirection == OMX_DirInput ? iInQueue : iOutQueue;
	TInt err = queue.Send(aBuffer);
	// do not expect error as maximum buffer count already allocated
	if(err != KErrNone)
		{
		User::Panic(KBufferCopierPanic, err);
		}
	}
	
void CBufferCopier::RunL()
	{
	if(iInBuffer == NULL)
		{
		// ignore error, if KErrUnderflow then we go back to waiting on iInQueue
		iInQueue.Receive(iInBuffer);
		}
	else
		{
		OMX_BUFFERHEADERTYPE* outBuffer = NULL;
		TInt err = iOutQueue.Receive(outBuffer);
		// if KErrUnderflow then we go back to waiting on iOutQueue
		if(err == KErrNone)
			{
			CopyBuffer(iInBuffer, outBuffer);
			iInBuffer = NULL;
			}
		}
	
	SetActive();
	if(iInBuffer == NULL)
		{
		iInQueue.NotifyDataAvailable(iStatus);
		}
	else
		{
		iOutQueue.NotifyDataAvailable(iStatus);
		}
	}

void CBufferCopier::DoCancel()
	{
	iInQueue.CancelDataAvailable();
	iOutQueue.CancelDataAvailable();
	}

void CBufferCopier::CopyBuffer(OMX_BUFFERHEADERTYPE* aInBuffer, OMX_BUFFERHEADERTYPE* aOutBuffer)
	{
	aOutBuffer->nOffset = 0;
	TPtr8 desPtr(aOutBuffer->pBuffer, aOutBuffer->nAllocLen);
 	desPtr.Copy(aInBuffer->pBuffer + aInBuffer->nOffset, aInBuffer->nFilledLen);
		
	aOutBuffer->nFilledLen			 = aInBuffer->nFilledLen;
	aOutBuffer->hMarkTargetComponent = aInBuffer->hMarkTargetComponent;
	aOutBuffer->pMarkData			 = aInBuffer->pMarkData;
	aOutBuffer->nTickCount			 = aInBuffer->nTickCount;
	aOutBuffer->nTimeStamp			 = aInBuffer->nTimeStamp;
	aOutBuffer->nFlags				 = aInBuffer->nFlags;			

	iCallback.MbcBufferCopied(aInBuffer, aOutBuffer);
	}

TBool CBufferCopier::RemoveBuffer(OMX_BUFFERHEADERTYPE* aBuffer, OMX_DIRTYPE aDirection)
	{
	switch(aDirection)
		{
	case OMX_DirInput:
		{
		if(aBuffer == iInBuffer)
			{
			// also check the slot used for storing the input buffer when waiting for an output buffer
			iInBuffer = NULL;
			return ETrue;
			}
		else
			{
			return RemoveFromQueue(iInQueue, aBuffer);
			}
		}
	case OMX_DirOutput:
		return RemoveFromQueue(iOutQueue, aBuffer);
	default:
		User::Panic(KBufferCopierPanic, KErrArgument);
		return EFalse;	// prevent compiler warning
		}
	}

void CBufferCopier::FlushBuffers(OMX_DIRTYPE aDirection)
	{
	OMX_BUFFERHEADERTYPE* buffer;
	if(aDirection == OMX_DirInput)
		{
        if(iInBuffer)
            {
            iCallback.MbcBufferFlushed(iInBuffer, OMX_DirInput);
            iInBuffer = NULL;
            }
		
		while(iInQueue.Receive(buffer) != KErrUnderflow)
			{
			iCallback.MbcBufferFlushed(buffer, OMX_DirInput);
			}
		}
	else if(aDirection == OMX_DirOutput)
		{
		while(iOutQueue.Receive(buffer) != KErrUnderflow)
			{
			iCallback.MbcBufferFlushed(buffer, OMX_DirOutput);
			}
		}
	else
		{
		User::Panic(KBufferCopierPanic, KErrArgument);
		}
	}

TBool CBufferCopier::RemoveFromQueue(RMsgQueue<OMX_BUFFERHEADERTYPE*>& aQueue, OMX_BUFFERHEADERTYPE* aBufferHeader)
	{
	TBool removed = EFalse;
	OMX_BUFFERHEADERTYPE* bufferHeader = NULL;
	while(aQueue.Receive(bufferHeader) != KErrUnderflow)
		{
		if(bufferHeader != aBufferHeader)
			{
			TInt err = iRemoveQueue.Send(bufferHeader);
			__ASSERT_DEBUG(err == KErrNone, User::Panic(KBufferCopierPanic, err));
			}
		else
			{
			removed = ETrue;
			}
		}
	while(iRemoveQueue.Receive(bufferHeader) != KErrUnderflow)
		{
		TInt err = aQueue.Send(bufferHeader);
		__ASSERT_DEBUG(err == KErrNone, User::Panic(KBufferCopierPanic, err));
		}
	return removed;
	}