diff -r c1e808730d6c -r eedf2dcd43c6 omxil/video/omxilclock/src/comxilclockprocessingfunction.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omxil/video/omxilclock/src/comxilclockprocessingfunction.cpp Fri May 07 16:25:23 2010 +0100 @@ -0,0 +1,318 @@ +/* +* Copyright (c) 2008-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: +* +*/ + + +/** +@file +@internalComponent +*/ + +#include "omxilutil.h" +#include "comxilclockprocessingfunction.h" +#include "comxilclockcomponent.h" +#include "clocksupervisor.h" +#include "omxilcallbacknotificationif.h" +#include "clockpanics.h" +#include "omxilclock.hrh" + +#include "omxilspecversion.h" + + +OMX_ERRORTYPE SymbianErrorToOmx(TInt aError); + +COmxILClockProcessingFunction* COmxILClockProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks, + COmxILClockComponent& aComponent) + { + COmxILClockProcessingFunction* self = new (ELeave) COmxILClockProcessingFunction(aCallbacks, aComponent); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +COmxILClockProcessingFunction::COmxILClockProcessingFunction(MOmxILCallbackNotificationIf& aCallbacks, + COmxILClockComponent& aComponent) : + COmxILProcessingFunction(aCallbacks), iComponent(aComponent) + { + } + +void COmxILClockProcessingFunction::ConstructL() + { + iClock = CClockSupervisor::NewL(*this); + iThreadNotifier = CClockThreadNotifier::NewL(iClock); + iThreadNotifier->IssueRequest(); + User::LeaveIfError(iBufferMutex.CreateLocal()); + // create a buffer queue for each port and add it to the iBufferQueues array + for(TInt portIndex = 0; portIndex < KNumPorts; portIndex++) + { + CCirBuf* queue = new(ELeave) CCirBuf(); + CleanupStack::PushL(queue); + iBufferQueues.AppendL(queue); + CleanupStack::Pop(queue); + } + } + +COmxILClockProcessingFunction::~COmxILClockProcessingFunction() + { + delete iClock; + delete iThreadNotifier; + iBufferMutex.Close(); + // empty iBufferQueues and delete any CCirBuf objects + // the CCirBuf objects don't own any buffers they contain, so we don't delete those here + iBufferQueues.ResetAndDestroy(); + } + +OMX_ERRORTYPE COmxILClockProcessingFunction::StateTransitionIndication(COmxILFsm::TStateIndex aNewState) + { + OMX_ERRORTYPE omxError = OMX_ErrorNone; + + switch(aNewState) + { + case COmxILFsm::ESubStateLoadedToIdle: + { + // allocate space for the buffer queues now the buffer count on each port is known + for(TInt portIndex = 0; portIndex < KNumPorts; portIndex++) + { + TInt length = iComponent.PortBufferCount(portIndex); + TRAPD(error, iBufferQueues[portIndex]->SetLengthL(length)); + // error not actually a problem if queue was originally longer than we need + if(error != KErrNone && iBufferQueues[portIndex]->Length() < length) + { + omxError = OMX_ErrorInsufficientResources; + break; + } + } + break; + } + + case COmxILFsm::EStateExecuting: + { + iExecuting = ETrue; + break; + } + + case COmxILFsm::EStateIdle: + { + iExecuting = EFalse; + break; + } + + case COmxILFsm::EStatePause: + { + // NOTE we do not change iExecuting + // The value of iExecuting maintains the direction from which + // Paused was entered (i.e. from Idle or Executing). + // This is because we wan't to know whether buffers are available, + // regardless of whether we are paused or not. + // TODO TBD is there an implicit stopping of the clock (e.g. set scale to 0)? + break; + } + default: + { + break; + } + } + + return omxError; + } + +OMX_ERRORTYPE COmxILClockProcessingFunction::BufferFlushingIndication(TUint32 aPortIndex, + OMX_DIRTYPE /*aDirection*/) + { + __ASSERT_DEBUG(aPortIndex == OMX_ALL || aPortIndex < KNumPorts, Panic(EBufferFlushingInvalidPort)); + + if (aPortIndex == OMX_ALL || aPortIndex < KNumPorts) + { + iBufferMutex.Wait(); + + if (aPortIndex == OMX_ALL) + { + for (TInt portIndex = 0; portIndex < KNumPorts; portIndex++) + { + DoBufferFlushingIndication(portIndex); + } + } + else + { + DoBufferFlushingIndication(aPortIndex); + } + + iBufferMutex.Signal(); + } + + return OMX_ErrorNone; + } + +void COmxILClockProcessingFunction::DoBufferFlushingIndication(TUint32 aPortIndex) + { + CCirBuf& queue = *iBufferQueues[aPortIndex]; + + while(queue.Count() > 0) + { + OMX_BUFFERHEADERTYPE* buffer; + // ignore error, we just checked Count() > 0 and we have the mutex, so a buffer + // should definitely be there + queue.Remove(&buffer); + OMX_ERRORTYPE error = iCallbacks.BufferDoneNotification(buffer, aPortIndex, OMX_DirOutput); + // the callback manager should return OMX_ErrorNone + // the callback manager ignores any error code from the callee component since it is the component's responsibility + // to respond to errors generated internally + __ASSERT_DEBUG(error == OMX_ErrorNone, Panic(ECallbackManagerBufferError)); + } + } + +OMX_ERRORTYPE COmxILClockProcessingFunction::ParamIndication(OMX_INDEXTYPE /*aParamIndex*/, + const TAny* /*apComponentParameterStructure*/) + { + return OMX_ErrorNone; + } + +OMX_ERRORTYPE COmxILClockProcessingFunction::ConfigIndication(OMX_INDEXTYPE /*aConfigIndex*/, + const TAny* /*apComponentConfigStructure*/) + { + return OMX_ErrorNone; + } + +OMX_ERRORTYPE COmxILClockProcessingFunction::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, + OMX_DIRTYPE /*aDirection*/) + { + // add buffer to the appropriate port queue + + CCirBuf& queue = *iBufferQueues[apBufferHeader->nOutputPortIndex]; + TOmxILUtil::ClearBufferContents(apBufferHeader); + apBufferHeader->nOffset = 0; + iBufferMutex.Wait(); + TInt added = queue.Add(&apBufferHeader); + // don't expect 0 (not added) as total number of buffers is known + __ASSERT_DEBUG(added, Panic(EBufferQueueOverflow)); + + iBufferMutex.Signal(); + return OMX_ErrorNone; + } + +/** + * Finds and removes an item from a CCirBuf. + * NOTE items are NOT guaranteed to be in their original position! + * The queue must be protected from concurrent access when calling this + * function. + * + * @param aQueue queue to modify + * @param aRemoveItem item to remove + * @return ETrue if item was found and removed from the queue, EFalse otherwise. + */ +template +static TBool RemoveFromPool(CCirBuf&aQueue, T aRemoveItem) + { + TInt numItems = aQueue.Count(); + for(TInt index = 0; index < numItems; index++) + { + T item; + TInt removed = aQueue.Remove(&item); // ignore error since queue cannot be empty (numItems > 0) + __ASSERT_DEBUG(removed == 1, Panic(EBufferUnderflow)); + if(item == aRemoveItem) + { + return ETrue; + } + else + { + TInt added = aQueue.Add(&item); // ignore error since always space for 1 item as one has just been removed + __ASSERT_DEBUG(added == 1, Panic(EBufferQueueOverflow)); + } + } + return EFalse; + } + +OMX_BOOL COmxILClockProcessingFunction::BufferRemovalIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, + OMX_DIRTYPE /*aDirection*/) + { + CCirBuf& queue = *iBufferQueues[apBufferHeader->nOutputPortIndex]; + iBufferMutex.Wait(); + // note queue may be reordered, but that's OK since these are empty buffers + TBool removed = RemoveFromPool(queue, apBufferHeader); + iBufferMutex.Signal(); + + return removed ? OMX_TRUE : OMX_FALSE; + } + +/** + * Returns a free buffer from the queue for the specified port. + * If no buffer is ready, this method returns NULL + * This method does not block for a buffer to become available. + */ +OMX_BUFFERHEADERTYPE* COmxILClockProcessingFunction::AcquireBuffer(TInt aPortIndex) + { + CCirBuf& queue = *iBufferQueues[aPortIndex]; + iBufferMutex.Wait(); + OMX_BUFFERHEADERTYPE* buffer; + TInt count = queue.Remove(&buffer); + iBufferMutex.Signal(); + if(count > 0) + { + return buffer; + } + else + { + return NULL; + } + } + +/** + * Sends a buffer out on a port. + */ +void COmxILClockProcessingFunction::SendBuffer(OMX_BUFFERHEADERTYPE* aBuffer) + { + OMX_ERRORTYPE error = iCallbacks.BufferDoneNotification(aBuffer, aBuffer->nOutputPortIndex, OMX_DirOutput); + // the callback manager should return OMX_ErrorNone + // the callback manager ignores any error code from the callee component since it is the component's responsibility + // to respond to errors generated internally + __ASSERT_DEBUG(error == OMX_ErrorNone, Panic(ECallbackManagerBufferError)); + } + +OMX_ERRORTYPE COmxILClockProcessingFunction::ProduceRequest(OMX_INDEXTYPE aIdx, CClockSupervisor::TEntryPoint aEntryPoint, TAny* pComponentConfigStructure) + { + return iClock->ProduceRequest(aIdx, aEntryPoint, pComponentConfigStructure); + } + +/** + * Returns true iff the specified port is currently enabled. + */ +TBool COmxILClockProcessingFunction::PortEnabled(TInt aPortIndex) const + { + return iComponent.PortEnabled(aPortIndex); + } + +TBool COmxILClockProcessingFunction::IsExecuting() const + { + return iExecuting; + } + +/** + * Called when CClockSupervisor encounters a fatal error and needs to transition the + * component to OMX_StateInvalid. + */ +void COmxILClockProcessingFunction::InvalidateComponent() + { + OMX_ERRORTYPE error = iCallbacks.ErrorEventNotification(OMX_ErrorInvalidState); + // the callback manager should return OMX_ErrorNone + // the callback manager ignores any error code from the client since it is the client's responsibility to respond + // to errors generated internally + __ASSERT_DEBUG(error == OMX_ErrorNone, Panic(ECallbackManagerEventError)); + // TODO this sends the invalidated event up to the IL client, but does not alter + // the internal state of the component to reflect being invalid. It seems you need + // access to private, non-exported FsmTransition to do that? + } +