--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/omxil/video/omxilgraphicsink/src/omxilgraphicsinkprocessingfunction.cpp Fri May 07 16:25:23 2010 +0100
@@ -0,0 +1,1352 @@
+/*
+* 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 "log.h"
+
+#include "omxilgraphicsinkprocessingfunction.h"
+#include "omxilgraphicsinktrace.h"
+#include "omxilgraphicsinkpanics.h"
+#include "omxilgraphicsinkvpb0port.h"
+#include "omxilcallbackmanager.h"
+#include <hal.h>
+#include <graphics/suerror.h>
+#include "omxilgraphicsinkextensionsindexes.h"
+#include <platform/openmax/il/shai/OMX_Symbian_ComponentExt.h>
+
+// Constant numbers
+#ifndef __WINSCW__
+const TInt KRefGfxAlignment = RSurfaceManager::EPageAligned;
+#else
+const TInt KRefGfxAlignment = 2;
+#endif
+static const TBool KRefGfxContiguous = ETrue;
+static const TInt KSurfaceUpdateNumOfMessageSlots = 4;
+static const TUint32 KNullTickCount = 0xFFFFFFFF;
+
+
+/**
+Create a new processing function object.
+
+@param aCallbacks The callback manager interface for processing function.
+
+@return A pointer to the processing function object to be created.
+*/
+COmxILGraphicSinkProcessingFunction*
+COmxILGraphicSinkProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks)
+ {
+ COmxILGraphicSinkProcessingFunction* self =
+ new (ELeave)COmxILGraphicSinkProcessingFunction(aCallbacks);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+/**
+Second phase construction for the processing function. Loads the device driver for surface manager and initializes the surface attributes.
+*/
+void
+COmxILGraphicSinkProcessingFunction::ConstructL()
+ {
+ iTransitionToPauseWait = new(ELeave) CActiveSchedulerWait();
+ User::LeaveIfError(iTransitionToPauseWaitSemaphore.CreateLocal(0));
+
+ //record the ID of the creator thread for later use
+ iOwnerThreadId = RThread().Id();
+
+ iGraphicSurfaceAccess = CGraphicSurfaceAccess::NewL(*this);
+ iPFHelper = CPFHelper::NewL(*this, *iGraphicSurfaceAccess);
+
+ User::LeaveIfError(iBufferMutex.CreateLocal());
+ InitSurfaceAttributes();
+ iState = OMX_StateLoaded;
+ }
+
+/**
+Constructor of the class.
+
+@param aCallbacks The callback manager interface for processing function.
+*/
+COmxILGraphicSinkProcessingFunction::COmxILGraphicSinkProcessingFunction(
+ MOmxILCallbackNotificationIf& aCallbacks)
+ :
+ COmxILProcessingFunction(aCallbacks)
+ {
+ HAL::Get(HALData::EFastCounterFrequency,iFastCounterFrequency);
+ }
+
+/**
+Destructor of the class.
+*/
+COmxILGraphicSinkProcessingFunction::~COmxILGraphicSinkProcessingFunction()
+ {
+ delete iTransitionToPauseWait;
+ iTransitionToPauseWaitSemaphore.Close();
+
+ // Check in case the driver has not been closed. That would happen in
+ // an scenario where the component is deleted while being in
+ // OMX_StateExecuting state.
+ if(iPFHelper &&
+ (iState == OMX_StateInvalid ||
+ iState == OMX_StateExecuting ||
+ iState == OMX_StatePause))
+ {
+ // Ignore error if the following call fails
+ iPFHelper->StopSync();
+ }
+
+ delete iPFHelper;
+ delete iGraphicSurfaceAccess;
+
+ iSurfaceManager.Close();
+
+ // Buffer headers are not owned by the processing function
+ iBuffersToEmpty.Close();
+
+ iBufferMutex.Close();
+ }
+
+/**
+This method provides the state change information within the processing function so that appropriate action can be taken.
+This state change information is provided by the FSM on behalf of the IL Client.
+
+@param aNewState The new state of FSM.
+
+@return OMX_ErrorNone if successful
+ OMX_ErrorInsufficientResources if fail to start GraphicSink frame acceptor
+ OMX_ErrorIncorrectStateTransition if unsupported state
+ Any other OpenMAX IL wide error code
+*/
+OMX_ERRORTYPE
+COmxILGraphicSinkProcessingFunction::StateTransitionIndication(COmxILFsm::TStateIndex aNewState)
+ {
+ switch(aNewState)
+ {
+ case COmxILFsm::EStateExecuting:
+ {
+ return iPFHelper->ExecuteAsync();
+ }
+ case COmxILFsm::EStateInvalid:
+ {
+ return iPFHelper->StopAsync();
+ }
+ case COmxILFsm::EStatePause:
+ {
+ // must be done immediately
+ OMX_ERRORTYPE omxErr = iPFHelper->Pause();
+ if(omxErr == OMX_ErrorNone)
+ {
+ WaitForTransitionToPauseToFinish();
+ }
+ return omxErr;
+ }
+ case COmxILFsm::EStateIdle:
+ {
+ iBufferMutex.Wait();
+ iBuffersToEmpty.Reset();
+ iBufferMutex.Signal();
+ iState = OMX_StateIdle;
+ return OMX_ErrorNone;
+ }
+ case COmxILFsm::EStateLoaded:
+ case COmxILFsm::EStateWaitForResources:
+ {
+ return iPFHelper->StopAsync();
+ }
+ case COmxILFsm::ESubStateLoadedToIdle:
+ {
+ // Open a channel to the surface manager logical device driver.
+ TInt err = iSurfaceManager.Open();
+ if ( err != KErrNone)
+ {
+ return OMX_ErrorHardware;
+ }
+
+ if (iPFHelper->OpenDevice() != KErrNone)
+ {
+ return OMX_ErrorInsufficientResources;
+ }
+ /*
+ if (iGraphicSinkPort->ValidateStride() != OMX_ErrorNone)
+ {
+ return OMX_ErrorUnsupportedSetting;
+ }
+ return OMX_ErrorNone;
+ */
+ return iGraphicSinkPort->ValidateStride();
+ }
+ case COmxILFsm::ESubStateIdleToLoaded:
+ {
+ return iPFHelper->CloseDevice();
+ }
+ case COmxILFsm::ESubStateExecutingToIdle:
+ {
+ // must be done immediately
+ return iPFHelper->StopAsync();
+ }
+ case COmxILFsm::ESubStatePauseToIdle:
+ {
+ // Ignore these transitions...
+ return OMX_ErrorNone;
+ }
+ default:
+ {
+ return OMX_ErrorIncorrectStateTransition;
+ }
+ };
+ }
+
+/**
+Flushes all the buffers retained by the processing function and sends it to either IL Client or the Tunelled component, as the case may be.
+
+@param aPortIndex Port index used to flush buffers from a given port of the component.
+@param aDirection This describes the direction of the port.
+
+@return OMX_ErrorNone if successful;
+ Any other OpenMAX IL wide error code;
+*/
+OMX_ERRORTYPE
+COmxILGraphicSinkProcessingFunction::BufferFlushingIndication(
+ TUint32 aPortIndex,
+ OMX_DIRTYPE aDirection)
+ {
+ iBufferMutex.Wait();
+ if ((aPortIndex == OMX_ALL && aDirection == OMX_DirMax) ||
+ (aPortIndex == 0 && aDirection == OMX_DirInput))
+ {
+ // Send BufferDone notifications for each buffer...
+ if(iBufferOnScreen != NULL)
+ {
+ // TODO error handling
+ iCallbacks.BufferDoneNotification(iBufferOnScreen, 0, OMX_DirInput);
+ iBufferOnScreen = NULL;
+ }
+ const TUint bufferCount = iBuffersToEmpty.Count();
+ OMX_BUFFERHEADERTYPE* pBufferHeader = 0;
+ for (TUint i=0; i<bufferCount; i++)
+ {
+ pBufferHeader = iBuffersToEmpty[i];
+ pBufferHeader->nTickCount = KNullTickCount;
+ iCallbacks.
+ BufferDoneNotification(
+ pBufferHeader,
+ pBufferHeader->nInputPortIndex,
+ OMX_DirInput
+ );
+ }
+ // Empty buffer lists...
+ iBuffersToEmpty.Reset();
+
+ iBufferMutex.Signal();
+ return OMX_ErrorNone;
+ }
+ else
+ {
+ iBufferMutex.Signal();
+ return OMX_ErrorBadParameter;
+ }
+ }
+
+/**
+Update the structure corresponding to the given index which belongs to the static parameters list.
+
+@param aParamIndex The index representing the desired structure to be updated.
+@param aComponentParameterStructure A pointer to structure which has the desired settings that will be used to update the Processing function.
+
+@return OMX_ErrorNone if successful;
+ OMX_ErrorUnsupportedIndex if unsupported index;
+ OMX_ErrorUnsupportedSetting if pixel format is EUidPixelFormatUnknown;
+ Any other OpenMAX IL wide error code;
+*/
+OMX_ERRORTYPE
+COmxILGraphicSinkProcessingFunction::ParamIndication(
+ OMX_INDEXTYPE aParamIndex,
+ const TAny* apComponentParameterStructure)
+ {
+ DEBUG_PRINTF(_L8("COmxILGraphicSinkProcessingFunction::PortParamIndication"));
+
+ switch(aParamIndex)
+ {
+ case OMX_IndexParamPortDefinition:
+ {
+ const OMX_PARAM_PORTDEFINITIONTYPE* portDefinition = static_cast<const OMX_PARAM_PORTDEFINITIONTYPE*>(apComponentParameterStructure);
+
+ //
+ // All the fields in SurfaceAttribute structure should be updated.
+ //
+ iGraphicSurfaceSettings.iSurfaceAttributes.iSize.iWidth = portDefinition->format.video.nFrameWidth;
+ iGraphicSurfaceSettings.iSurfaceAttributes.iSize.iHeight = portDefinition->format.video.nFrameHeight;
+
+ // Need to convert OMX Color Format to TUidPixelFormat.
+ TUidPixelFormat pixelFormat = ConvertPixelFormat(portDefinition->format.video.eColorFormat);
+ if(pixelFormat == EUidPixelFormatUnknown)
+ {
+ return OMX_ErrorUnsupportedSetting;
+ }
+ else
+ {
+ iGraphicSurfaceSettings.iSurfaceAttributes.iPixelFormat = pixelFormat;
+ }
+
+ iGraphicSurfaceSettings.iSurfaceAttributes.iBuffers = portDefinition->nBufferCountActual;
+ iGraphicSurfaceSettings.iSurfaceAttributes.iStride = portDefinition->format.video.nStride;
+ break;
+ }
+ case OMX_IndexParamVideoPortFormat:
+ {
+ const OMX_VIDEO_PARAM_PORTFORMATTYPE* videoPortFormat = static_cast<const OMX_VIDEO_PARAM_PORTFORMATTYPE*>(apComponentParameterStructure);
+
+ // only OMX_COLOR_FORMATTYPE eColorFormat to be used for SurfaceAttributes.iPixelFormat
+ TUidPixelFormat pixelFormat = ConvertPixelFormat(videoPortFormat->eColorFormat);
+ if(pixelFormat == EUidPixelFormatUnknown)
+ {
+ return OMX_ErrorUnsupportedSetting;
+ }
+ else
+ {
+ iGraphicSurfaceSettings.iSurfaceAttributes.iPixelFormat = pixelFormat;
+ }
+ break;
+ }
+ default:
+ {
+ return OMX_ErrorUnsupportedIndex;
+ }
+ }
+ return OMX_ErrorNone;
+ }
+
+/**
+Update the structure corresponding to the given index which belongs to the dynamic configuration list.
+
+@param aConfigIndex The index representing the desired structure to be updated.
+@param aComponentConfigStructure A pointer to structure which has the desired settings that will be used to update the Processing function.
+
+@return OMX_ErrorNone if successful;
+ OMX_ErrorUnsupportedIndex if unsupported index;
+ OMX_ErrorUnsupportedSetting if SurfaceConfiguration returns error;
+ Any other OpenMAX IL wide error code;
+*/
+OMX_ERRORTYPE
+COmxILGraphicSinkProcessingFunction::ConfigIndication(OMX_INDEXTYPE aConfigIndex,
+ const TAny* apComponentConfigStructure)
+ {
+ DEBUG_PRINTF(_L8("COmxILGraphicSinkProcessingFunction::ConfigIndication"));
+
+ TInt err = KErrNone;
+
+ switch(aConfigIndex)
+ {
+ case OMX_SymbianIndexConfigSharedChunkMetadata:
+ {
+ const OMX_SYMBIAN_CONFIG_SHAREDCHUNKMETADATATYPE*
+ pSharedChunkMetadata
+ = static_cast<
+ const OMX_SYMBIAN_CONFIG_SHAREDCHUNKMETADATATYPE*>(
+ apComponentConfigStructure);
+
+ iGraphicSurfaceAccess->iSharedChunkHandleId = pSharedChunkMetadata->nHandleId;
+ iGraphicSurfaceAccess->iSharedChunkThreadId = pSharedChunkMetadata->nOwnerThreadId;
+
+ iGraphicSurfaceAccess->iIsLocalChunk = EFalse;
+ break;
+ }
+ case OMX_IndexConfigCommonScale:
+ {
+ const OMX_CONFIG_SCALEFACTORTYPE* scaleFactor = static_cast<const OMX_CONFIG_SCALEFACTORTYPE*>(apComponentConfigStructure);
+
+ err = iGraphicSurfaceSettings.iSurfaceConfig.SetExtent(TRect(TSize(scaleFactor->xWidth, scaleFactor->xHeight)));
+ if(err != KErrNone)
+ {
+ return OMX_ErrorUnsupportedSetting;
+ }
+
+ break;
+ }
+ case OMX_IndexConfigCommonOutputSize:
+ {
+ const OMX_FRAMESIZETYPE* frameSize = static_cast<const OMX_FRAMESIZETYPE*>(apComponentConfigStructure);
+
+ err = iGraphicSurfaceSettings.iSurfaceConfig.SetExtent(TRect(TSize(frameSize->nWidth, frameSize->nHeight)));
+ if(err != KErrNone)
+ {
+ return OMX_ErrorUnsupportedSetting;
+ }
+
+ break;
+ }
+ case OMX_IndexConfigCommonInputCrop:
+ case OMX_IndexConfigCommonOutputCrop:
+ case OMX_IndexConfigCommonExclusionRect:
+ {
+ const OMX_CONFIG_RECTTYPE* rec = static_cast<const OMX_CONFIG_RECTTYPE*>(apComponentConfigStructure);
+
+ err = iGraphicSurfaceSettings.iSurfaceConfig.SetExtent(TRect(TPoint(rec->nTop, rec->nLeft), TSize(rec->nWidth, rec->nHeight)));
+ if(err != KErrNone)
+ {
+ return OMX_ErrorUnsupportedSetting;
+ }
+
+ break;
+ }
+ default:
+ {
+ return OMX_ErrorUnsupportedIndex;
+ }
+ }
+
+ return OMX_ErrorNone;
+ }
+
+void COmxILGraphicSinkProcessingFunction::SetSharedChunkBufConfig(TMMSharedChunkBufConfig aSharedChunkBufConfig)
+ {
+ iGraphicSurfaceAccess->iSharedChunkBufConfig = aSharedChunkBufConfig;
+ }
+
+void COmxILGraphicSinkProcessingFunction::GetSharedChunkMetadata(
+ OMX_U32& aHandleId,
+ OMX_U64& aThreadId) const
+ {
+ aHandleId = iGraphicSurfaceAccess->iSharedChunkHandleId;
+ aThreadId = iGraphicSurfaceAccess->iSharedChunkThreadId;
+ }
+
+/**
+This method is invoked whenever the component is requested to emtpy/display the contents of the buffers passed as function arguments.
+
+@param apBufferHeader A pointer to buffer header.
+@param aDirection provides the direction either input or output. This can be used as a further check whether buffers received are valid or not.
+
+@return OMX_ErrorNone if successful;
+ Any other OpenMAX IL wide error code;
+*/
+OMX_ERRORTYPE
+COmxILGraphicSinkProcessingFunction::BufferIndication(
+ OMX_BUFFERHEADERTYPE* apBufferHeader,
+ OMX_DIRTYPE aDirection)
+ {
+ if (aDirection != OMX_DirInput)
+ {
+ return OMX_ErrorBadParameter;
+ }
+ //The nTickCount is just internal here, stored temporarily. So it is count not time period.
+ apBufferHeader->nTickCount = User::FastCounter();
+ iBufferMutex.Wait();
+ OMX_ERRORTYPE ret = OMX_ErrorNone;
+ if (iBuffersToEmpty.Append(apBufferHeader) != KErrNone)
+ {
+ apBufferHeader->nTickCount = KNullTickCount;
+ ret = OMX_ErrorInsufficientResources;
+ }
+ else if (iState != OMX_StateExecuting)
+ {
+ // If Component not in an executing state delay processing buffer
+ ret = OMX_ErrorNone;
+ }
+ else if (iPFHelper->BufferIndication() != KErrNone)
+ {
+ apBufferHeader->nTickCount = KNullTickCount;
+ ret = OMX_ErrorInsufficientResources;
+ }
+ iBufferMutex.Signal();
+ return ret;
+ }
+
+/**
+This method is used to check whether the required buffer is held by the processing function or not.
+
+@param apBufferHeader A pointer to buffer header being searched.
+@param aDirection provides the direction either input or output. This can be used as a further check whether buffers received are valid or not.
+
+@return OMX_TRUE if find the buffer;
+ OMX_FALSE if fail to find the buffer;
+*/
+OMX_BOOL
+COmxILGraphicSinkProcessingFunction::BufferRemovalIndication(
+ OMX_BUFFERHEADERTYPE* apBufferHeader,
+ OMX_DIRTYPE /* aDirection */)
+ {
+ TBool headerDeletionResult = ETrue;
+
+ TInt headerIndexInArray = KErrNotFound;
+ iBufferMutex.Wait();
+ if (KErrNotFound !=
+ (headerIndexInArray =
+ iBuffersToEmpty.Find(apBufferHeader)))
+ {
+ iBuffersToEmpty.Remove(headerIndexInArray);
+ }
+ else if(iBufferOnScreen == apBufferHeader)
+ {
+ iBufferOnScreen = NULL;
+ }
+ else
+ {
+ headerDeletionResult = EFalse;
+ }
+ iBufferMutex.Signal();
+ return (headerDeletionResult ? OMX_TRUE : OMX_FALSE);
+ }
+
+/**
+This method creates COmxILMMBuffer class object. Also creates surface and allocates the chunks based on the number of buffers,
+maps the surface in the given process. It also allocates the resources like creating the message queue and other necessary C
+class objects. This method gets called when the component acts as buffer supplier.
+
+@param aPortSpecificBuffer gives the starting address of the specific buffer.
+@param aPortPrivate gives the private data which is COmxILMMBuffer pointer in this case.
+
+@leave OMX_ErrorNone if successful;
+@leave OMX_ErrorInsufficientResources if function returns KErrNoMemory;
+@leave OMX_ErrorBadParameter if function returns errors except KErrNoMemory;
+@leave Any other OpenMAX IL wide error code;
+*/
+void COmxILGraphicSinkProcessingFunction::CreateBufferL(OMX_U8*& aPortSpecificBuffer, OMX_PTR& aPortPrivate, OMX_U32 aBufferCountActual)
+ {
+ iGraphicSurfaceAccess->CreateBufferL(aPortSpecificBuffer, aPortPrivate, aBufferCountActual);
+ }
+
+/**
+Destroy MM buffer, close surface, and deallocate other resources like message queue and C class objects. This is called when component
+acts as buffer supplier.
+@param apPortPrivate gives the private data which is COmxILMMBuffer pointer in this case.
+*/
+void COmxILGraphicSinkProcessingFunction::DestroyBuffer(OMX_PTR /*apPortPrivate*/)
+ {
+ iGraphicSurfaceAccess->iBufferIdGenerator--;
+ // to reset surface id in case client requests different settings.
+ if(iGraphicSurfaceAccess && iGraphicSurfaceAccess->iBufferIdGenerator == 0)
+ {
+ iGraphicSurfaceAccess->ResetSurfaceId();
+ iGraphicSurfaceAccess->CloseChunk();
+ }
+ }
+
+/**
+Creates the surface by utilizing the buffers passed via application private data. It then maps the surface in the given process.
+It also allocates the resources like creating the message queue and other necessary C class objects. This method gets called when
+the component acts as non buffer supplier.
+
+@param apBuffer gives the starting address of the specific buffer.
+@param aAppPrivate provides the private data which is COmxILMMBuffer pointer in this case and holds details of buffers already allocated.
+@param aBufferCountActual The actual number of buffers.
+
+@leave OMX_ErrorNone if successful;
+@leave OMX_ErrorInsufficientResources if aPortPrivate is null or functions return KErrNoMemory;
+@leave OMX_ErrorBadParameter if functions return errors except KErrNoMemory;
+@leave Any other OpenMAX IL wide error code;
+*/
+void COmxILGraphicSinkProcessingFunction::InitBufferL(OMX_U8* apBuffer, OMX_U32 aBufferCountActual)
+ {
+ iGraphicSurfaceAccess->InitBufferL(apBuffer, aBufferCountActual);
+ }
+
+/**
+Deallocate resources like message queue and C class objects. This is called when component acts as non buffer supplier.
+*/
+void COmxILGraphicSinkProcessingFunction::DeInitBuffer()
+ {
+ // to reset surface id in case client requests different settings.
+ if(iGraphicSurfaceAccess)
+ {
+ iGraphicSurfaceAccess->ResetSurfaceId();
+ iGraphicSurfaceAccess->CloseChunk();
+ }
+ }
+
+/**
+Initialise surface attribute structure.
+*/
+void COmxILGraphicSinkProcessingFunction::InitSurfaceAttributes()
+ {
+ RSurfaceManager::TSurfaceCreationAttributes* attr = &iGraphicSurfaceSettings.iSurfaceAttributes;
+
+ attr->iAlignment = KRefGfxAlignment;
+ attr->iContiguous = KRefGfxContiguous;;
+ attr->iCacheAttrib = RSurfaceManager::ENotCached;
+ attr->iMappable = ETrue;
+ }
+
+TUidPixelFormat COmxILGraphicSinkProcessingFunction::ConvertPixelFormat(OMX_COLOR_FORMATTYPE aColorFormat)
+ {
+ switch(aColorFormat)
+ {
+ // OMX "Planar" formats not currently supported by GraphicSink since data comes in more than one buffer.
+ // "PackedPlanar" formats can be added easily provided the GCE backend supports them.
+
+ case OMX_COLOR_Format16bitRGB565:
+ return EUidPixelFormatRGB_565;
+
+ case OMX_COLOR_Format32bitARGB8888:
+ return EUidPixelFormatARGB_8888;
+
+ case OMX_COLOR_FormatYCrYCb:
+ return EUidPixelFormatYUV_422Reversed;
+
+ case OMX_COLOR_FormatCbYCrY:
+ return EUidPixelFormatYUV_422Interleaved;
+
+ // Need to map color format to Symbian pixel format.
+ default:
+ {
+ return EUidPixelFormatUnknown;
+ }
+ }
+ }
+
+void COmxILGraphicSinkProcessingFunction::WaitForTransitionToPauseToFinish()
+ {
+ if(RThread().Id() == iOwnerThreadId)
+ {
+ //if the owner thread is the same thread as the one created the active objects in this processing function
+ //then we can wait by using CActiveSchedulerWait
+ DEBUG_PRINTF(_L8("GraphicSinkProcessingFunction::WaitForTransitionToPauseToFinish - blocking transition to pause with active scheduler wait now"));
+ iTransitionToPauseWait->Start();
+ }
+ else
+ {
+ //if this is a thread different from the creator thread then semaphore is needed to block this thread until the transition
+ //to paused state completes
+ DEBUG_PRINTF(_L8("GraphicSinkProcessingFunction::WaitForTransitionToPauseToFinish - blocking thread with semaphore now"));
+ iTransitionToPauseWaitSemaphore.Wait();
+ }
+ }
+
+void COmxILGraphicSinkProcessingFunction::TransitionToPauseFinished()
+ {
+ if(iTransitionToPauseWait->IsStarted())
+ {
+ DEBUG_PRINTF(_L8("GraphicSinkProcessingFunction::TransitionToPauseFinished - unblocking transition to pause (active scheduler wait) now"));
+ iTransitionToPauseWait->AsyncStop();
+ }
+ else
+ {
+ DEBUG_PRINTF(_L8("GraphicSinkProcessingFunction::TransitionToPauseFinished - unblocking transition to pause (semaphore) now"));
+ iTransitionToPauseWaitSemaphore.Signal();
+ }
+ }
+
+COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess* COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::NewL(COmxILGraphicSinkProcessingFunction& aParent)
+ {
+ return new (ELeave) CGraphicSurfaceAccess(aParent);
+ }
+
+COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::CGraphicSurfaceAccess(COmxILGraphicSinkProcessingFunction& aParent)
+: CActive(EPriorityStandard),
+ iIsLocalChunk(ETrue),
+ iParent(aParent)
+ {
+ CActiveScheduler::Add(this);
+ iSurfaceId = TSurfaceId::CreateNullId();
+ iOffsetArray.Reset();
+ }
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::CloseChunk()
+ {
+ if(iChunk.Handle())
+ {
+ iChunk.Close();
+ }
+ }
+
+COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::~CGraphicSurfaceAccess()
+ {
+ Cancel();
+
+ CloseChunk();
+
+ if (!iSurfaceId.IsNull())
+ {
+ iParent.SurfaceManager().CloseSurface(iSurfaceId); // ignore the error
+ }
+ #ifdef ILCOMPONENTCONFORMANCE
+ iArrayOffsets.Close();
+ #endif
+
+ iOffsetArray.Close();
+ iSurfaceUpdateSession.Close();
+
+ }
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::RunL()
+ {
+ // The buffer is not on the list implies that they have already been flushed/spotted
+ // via BufferFlushingIndication/BufferRemovalIndication
+ iParent.iBufferMutex.Wait();
+ TInt index = iParent.BuffersToEmpty().Find(iCurrentBuffer);
+ if (KErrNotFound != index)
+ {
+ switch(iStatus.Int())
+ {
+ case KErrNone:
+ {
+ // Consumed all data completely and setting nFilledLen to zero.
+ iCurrentBuffer->nFilledLen = 0;
+ break;
+ }
+ case KErrCancel:
+ default:
+ {
+ // Leave actual value of iCurrentBuffer->nFilledLen
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::RunL() err = %d"), iStatus.Int());
+ }
+ };
+
+ if(iStatus.Int() != KErrNone)
+ {
+ iCurrentBuffer->nTickCount = KNullTickCount;
+ }
+ else
+ {
+ TUint32 currentTickCount = User::FastCounter();
+
+ // On some hardware boards, tick count decrements as time increases so
+ // need to check which way the counter is going
+ if (currentTickCount >= iCurrentBuffer->nTickCount)
+ {
+ iCurrentBuffer->nTickCount = (currentTickCount - iCurrentBuffer->nTickCount) / iParent.GetFastCounterFrequency();
+ }
+ else
+ {
+ iCurrentBuffer->nTickCount = (iCurrentBuffer->nTickCount - currentTickCount) / iParent.GetFastCounterFrequency();
+ }
+ }
+
+
+ if(iCurrentBuffer->nFlags & OMX_BUFFERFLAG_EOS)
+ {
+ iParent.GetCallbacks().EventNotification(OMX_EventBufferFlag, iCurrentBuffer->nInputPortIndex, iCurrentBuffer->nFlags, NULL);
+ }
+
+ iCurrentBuffer->nFilledLen = 0;
+ iCurrentBuffer->nFlags = 0;
+ iCurrentBuffer->nOffset = 0;
+ iCurrentBuffer->nTimeStamp = 0;
+
+ // now sending back to framework..
+ if(iParent.iBufferOnScreen != NULL)
+ {
+ // TODO error handling
+ iParent.GetCallbacks().BufferDoneNotification(iParent.iBufferOnScreen, iParent.iBufferOnScreen->nInputPortIndex,OMX_DirInput);
+ }
+ iParent.iBufferOnScreen = iCurrentBuffer;
+
+ iParent.BuffersToEmpty().Remove(index);
+ iCurrentBuffer = NULL;
+
+ // check if any more buffers to be consumed..
+ if (ProcessNextBuffer() != KErrNone)
+ {
+ iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources);
+ }
+ }
+ iParent.iBufferMutex.Signal();
+ }
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::CreateBufferL(OMX_U8*& aPortSpecificBuffer, OMX_PTR& aPortPrivate, OMX_U32 aBufferCountActual)
+ {
+ if(iSurfaceId.IsNull())
+ {
+ // race condition on nBufferCountActual
+ if(aBufferCountActual != iParent.GraphicSurfaceSettings().iSurfaceAttributes.iBuffers)
+ {
+ iParent.GraphicSurfaceSettings().iSurfaceAttributes.iBuffers = aBufferCountActual;
+ }
+
+ User::LeaveIfError(iParent.SurfaceManager().CreateSurface(iParent.GraphicSurfaceSettings().iSurfaceAttributesBuf, iSurfaceId));
+
+ RChunk chunk;
+ CleanupClosePushL(chunk);
+ User::LeaveIfError(iParent.SurfaceManager().MapSurface(iSurfaceId, chunk));
+
+ //We need to change the chunk handle to be shared by the whole process.
+ RThread thread;
+ CleanupClosePushL(thread);
+ iChunk.SetHandle(chunk.Handle());
+ User::LeaveIfError(iChunk.Duplicate(thread));
+ CleanupStack::PopAndDestroy(2, &chunk);
+
+ // for SetConfig(OMX_SYMBIAN_CONFIG_SHARED_CHUNK_METADATA)
+ iSharedChunkHandleId = iChunk.Handle();
+ iSharedChunkThreadId = RThread().Id().Id();
+
+ switch(iParent.iGraphicSurfaceSettings.iSurfaceAttributes.iPixelFormat)
+ {
+ case EUidPixelFormatYUV_422Reversed:
+ {
+ // fill buffer 0 with black
+ TUint32* data = reinterpret_cast<TUint32*>(iChunk.Base());
+ TInt numPixelPairs = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iStride * iParent.GraphicSurfaceSettings().iSurfaceAttributes.iSize.iHeight / 4;
+ for(TInt offset = 0; offset < numPixelPairs; offset++)
+ {
+ data[offset] = 0x80108010;
+ }
+ }
+ break;
+ case EUidPixelFormatYUV_422Interleaved:
+ {
+ // fill buffer 0 with black
+ TUint32* data = reinterpret_cast<TUint32*>(iChunk.Base());
+ TInt numPixelPairs = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iStride * iParent.GraphicSurfaceSettings().iSurfaceAttributes.iSize.iHeight / 4;
+ for(TInt offset = 0; offset < numPixelPairs; offset++)
+ {
+ data[offset] = 0x10801080;
+ }
+ }
+ break;
+ case EUidPixelFormatRGB_565:
+ case EUidPixelFormatARGB_8888:
+ Mem::FillZ(iChunk.Base(), iParent.GraphicSurfaceSettings().iSurfaceAttributes.iStride * iParent.GraphicSurfaceSettings().iSurfaceAttributes.iSize.iHeight);
+ break;
+ default:
+#ifdef _DEBUG
+ // Panic in a debug build. It will make people think about how the error should be handled.
+ Panic(EUndefinedPixelFormat);
+#endif
+ break;
+ }
+
+ // Now, GFX needs to make sure that TSurfaceConfiguration has valid surface id
+ // so that IL Client can use RSurfaceManager::SetBackroundSurface()
+ User::LeaveIfError(iParent.GraphicSurfaceSettings().iSurfaceConfig.SetSurfaceId(iSurfaceId));
+ iParent.iCallbacks.EventNotification(OMX_EventPortSettingsChanged, OMX_NokiaIndexParamGraphicSurfaceConfig, 0, NULL);
+
+ chunk.Close();
+ #ifdef ILCOMPONENTCONFORMANCE
+ iIsBufferSupplier = ETrue;
+ #endif
+ }
+
+ ASSERT(iChunk.Handle());
+
+
+ RSurfaceManager::TInfoBuf surfaceInfoBuf;
+ RSurfaceManager::TSurfaceInfoV01& surfaceInfo (surfaceInfoBuf());
+ User::LeaveIfError(iParent.SurfaceManager().SurfaceInfo(iSurfaceId, surfaceInfoBuf));
+ for (TInt i = 0 ; i < surfaceInfo.iBuffers ; i++)
+ {
+ TInt offset = 0;
+ User::LeaveIfError(iParent.SurfaceManager().GetBufferOffset(iSurfaceId, i, offset));
+
+ if(iBufferIdGenerator == 0)
+ {
+ iOffsetArray.AppendL(offset);
+ }
+ }
+
+ aPortSpecificBuffer = iChunk.Base() + iOffsetArray[iBufferIdGenerator];
+ aPortPrivate = NULL;
+
+ iBufferIdGenerator++;
+ }
+
+
+#ifndef ILCOMPONENTCONFORMANCE
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL(OMX_U8* apBuffer, OMX_U32 aBufferCountActual)
+{
+ // open chunk at the beginning
+ if(iChunk.Handle() == NULL)
+ {
+ // only support chunk extension otherwise error
+ if(iSharedChunkThreadId == NULL || iSharedChunkHandleId == NULL)
+ {
+ DEBUG_PRINTF(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL handles not valie"));
+ User::Leave(KErrBadHandle);
+ }
+
+ // race condition on nBufferCountActual
+ if(aBufferCountActual != iParent.GraphicSurfaceSettings().iSurfaceAttributes.iBuffers)
+ {
+ iParent.GraphicSurfaceSettings().iSurfaceAttributes.iBuffers = aBufferCountActual;
+ }
+
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL iSharedChunkThreadId = %Lu"), iSharedChunkThreadId);
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL iSharedChunkHandleId = %Lu"), iSharedChunkHandleId);
+
+ RThread chunkOwnerThread;
+ User::LeaveIfError(chunkOwnerThread.Open(TThreadId(iSharedChunkThreadId)));
+ CleanupClosePushL(chunkOwnerThread);
+
+ iChunk.SetHandle(iSharedChunkHandleId);
+ User::LeaveIfError(iChunk.Duplicate(chunkOwnerThread));
+ CleanupStack::PopAndDestroy(&chunkOwnerThread);
+ }
+
+ // differ creating surface id with chunk at last call
+ if(iSurfaceId.IsNull() && (((aBufferCountActual - 1) == iOffsetArray.Count())))
+ {
+ // offsetBetweenBuffer & iBufferSizeInBytes in chunkconfig must be same
+ TInt offsetBetweenBuffer;
+ if(aBufferCountActual == 1) // if only one buffer is used, use iBufferSizeInBytes instead..
+ {
+ offsetBetweenBuffer = iSharedChunkBufConfig.iBufferSizeInBytes;
+ }
+ else
+ {
+ offsetBetweenBuffer = iOffsetArray[1] - iOffsetArray[0];
+ }
+
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL offsetBetweenBuffer = %d"), offsetBetweenBuffer);
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL iBufferSizeInBytes = %d"), iSharedChunkBufConfig.iBufferSizeInBytes);
+
+ // update surface attributes
+ iParent.GraphicSurfaceSettings().iSurfaceAttributes.iOffsetBetweenBuffers = offsetBetweenBuffer;
+
+ TInt err = KErrGeneral;
+ // create surface id with chunk
+ err = iParent.SurfaceManager().CreateSurface(iParent.GraphicSurfaceSettings().iSurfaceAttributesBuf, iSurfaceId, iChunk);
+ if(err != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL createsurface err = %d"), err);
+ User::Leave(err);
+ }
+
+ // Now, GFX needs to make sure that TSurfaceConfiguration has valid surface id
+ err = iParent.GraphicSurfaceSettings().iSurfaceConfig.SetSurfaceId(iSurfaceId);
+ if(err != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL SetSurfaceId err = %d"), err);
+ User::Leave(err);
+ }
+
+ RSurfaceManager::TInfoBuf surfaceInfoBuf;
+ RSurfaceManager::TSurfaceInfoV01& surfaceInfo (surfaceInfoBuf());
+ surfaceInfo.iSize = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iSize;
+ surfaceInfo.iBuffers = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iBuffers;
+ surfaceInfo.iPixelFormat = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iPixelFormat;
+ surfaceInfo.iStride = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iStride;
+ surfaceInfo.iContiguous = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iContiguous;
+ surfaceInfo.iCacheAttrib = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iCacheAttrib;
+ surfaceInfo.iMappable = iParent.GraphicSurfaceSettings().iSurfaceAttributes.iMappable;
+
+ err = iParent.SurfaceManager().SurfaceInfo(iSurfaceId, surfaceInfoBuf);
+ if(err != KErrNone)
+ {
+ DEBUG_PRINTF2(_L8("COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL SurfaceInfo err = %d"), err);
+ User::Leave(err);
+ }
+
+ // everything is fine and now ready to rock and roll...
+ iParent.iCallbacks.EventNotification(OMX_EventPortSettingsChanged, OMX_NokiaIndexParamGraphicSurfaceConfig, 0, NULL);
+ }
+
+ // save offsets
+ TInt offset = apBuffer - iChunk.Base();
+ iOffsetArray.AppendL(offset);
+ }
+
+#else
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::InitBufferL(OMX_U8* /*apBuffer*/, OMX_U32 aBufferCountActual)
+ {
+ if(iSurfaceId.IsNull())
+ {
+ User::LeaveIfError(iParent.SurfaceManager().CreateSurface(iParent.GraphicSurfaceSettings().iSurfaceAttributesBuf, iSurfaceId));
+
+ RChunk chunk;
+ User::LeaveIfError(iParent.SurfaceManager().MapSurface(iSurfaceId, chunk));
+ CleanupClosePushL(chunk);
+
+ //We need to change the chunk handle to be shared by the whole process.
+ RThread thread;
+ CleanupClosePushL(thread);
+ iChunk.SetHandle(chunk.Handle());
+ User::LeaveIfError(iChunk.Duplicate(thread));
+ CleanupStack::PopAndDestroy(2, &chunk);
+
+ // Now, GFX needs to make sure that TSurfaceConfiguration has valid surface id
+ // so that IL Client can use RSurfaceManager::SetBackroundSurface()
+ User::LeaveIfError(iParent.GraphicSurfaceSettings().iSurfaceConfig.SetSurfaceId(iSurfaceId));
+ iParent.iCallbacks.EventNotification(OMX_EventPortSettingsChanged, OMX_NokiaIndexParamGraphicSurfaceConfig, 0, NULL);
+
+ iIsBufferSupplier = EFalse;
+
+ for(TInt i = 0 ; i < aBufferCountActual ; i++)
+ {
+ TInt offset = 0;
+ User::LeaveIfError(iParent.SurfaceManager().GetBufferOffset(iSurfaceId, i, offset));
+ iArrayOffsets.AppendL(offset);
+ }
+ }
+
+ }
+#endif //ILCOMPONENTCONFORMANCE
+
+TInt COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::ProcessNextBuffer()
+ {
+ __ASSERT_DEBUG(iParent.iBufferMutex.IsHeld(), User::Invariant());
+
+ TInt err = KErrNone;
+
+ if ((iParent.BuffersToEmpty().Count()>0) && !IsActive() && iParent.State() == OMX_StateExecuting)
+ {
+ iCurrentBuffer = iParent.BuffersToEmpty()[0];
+ TInt bufferId = KErrNotFound;
+
+ if (iCurrentBuffer->nFilledLen == 0)
+ {
+ // Nothing in the buffer so no need to display it. The buffer might have a flag
+ // that needs processing though. Self complete to keep the state machine running.
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ return KErrNone;
+ }
+
+#ifdef ILCOMPONENTCONFORMANCE
+ if (iIsBufferSupplier)
+ {
+#endif
+ TInt offset = iCurrentBuffer->pBuffer - iChunk.Base();
+ bufferId = iOffsetArray.Find(offset);
+#ifdef ILCOMPONENTCONFORMANCE
+ }
+ else
+ {
+ // Copy data from IL Conformance Suite in to Chunk address at specific address.
+ TPtr8 ptr(iChunk.Base(),iCurrentBuffer->nFilledLen ,iCurrentBuffer->nAllocLen);
+ ptr.Copy(iCurrentBuffer->pBuffer + iCurrentBuffer->nOffset, iCurrentBuffer->nFilledLen);
+ // isn't nOffset likely going to be 0? better to map buffer pointer to buffer id directly
+ bufferId = iArrayOffsets.Find(iCurrentBuffer->nOffset);
+ // nOffset is not ideal for identifying buffer area since it's likely each buffer header
+ // will have a unique pBuffer and nOffset == 0. We could calculate buffer ID by finding
+ // the buffer header on the buffer header array in the port, but this isn't how bufferID
+ // is calculated in the rest of the code. (we could just store the buffer ID on the
+ // pInputPortPrivate but we have a habit of trying to export GS specific info into COmxILMMBuffer)
+ __ASSERT_ALWAYS(bufferId == 0, User::Invariant());
+ }
+#endif
+
+ if(KErrNotFound == bufferId)
+ {
+ // An error here means that the buffer will not be displayed and RunL() will not be
+ // invoked. However the buffer might have a flag that needs processing. Self complete
+ // to keep the state machine running.
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNotFound);
+ return KErrNotFound;
+ }
+
+ // due to COmxMMILBuffer dependency. to be removed
+ if (iIsLocalChunk)
+ {
+ // copy data into local chunk
+ TPtr8 ptr(iCurrentBuffer->pBuffer,iCurrentBuffer->nFilledLen ,iCurrentBuffer->nAllocLen);
+ ptr.Copy(iChunk.Base() + offset, iCurrentBuffer->nFilledLen);
+ }
+
+ iSurfaceUpdateSession.NotifyWhenDisplayed(iStatus, iTimeStamp);
+ SetActive();
+
+ err = iSurfaceUpdateSession.SubmitUpdate(KAllScreens, iSurfaceId, bufferId);
+ if(err)
+ {
+ // An error here means that the buffer will not be displayed and RunL() will not be
+ // invoked. However the buffer might have a flag that needs processing. Self complete
+ // to keep the state machine running.
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, err);
+ }
+ }
+
+ return err;
+ }
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::DoCancel()
+ {
+ if (iSurfaceUpdateSession.Handle() != KNullHandle)
+ {
+ iSurfaceUpdateSession.CancelAllUpdateNotifications();
+ }
+
+ iCurrentBuffer = NULL;
+ }
+
+TInt COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::OpenDevice()
+ {
+ TInt err = iSurfaceUpdateSession.Connect(KSurfaceUpdateNumOfMessageSlots);
+
+ if (err == KErrNotFound || err != KErrNone)
+ {
+#ifdef __WINSCW__
+ DEBUG_PRINTF(_L8("Make sure SYMBIAN_GRAPHICS_USE_GCE ON is specified in epoc.ini"));
+#else
+ DEBUG_PRINTF(_L8("Make sure SYMBIAN_GRAPHICS_USE_GCE is defined in ROM build"));
+#endif
+ }
+
+ return err;
+ }
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::CloseDevice()
+ {
+ iSurfaceUpdateSession.CancelAllUpdateNotifications();
+
+ if (!iSurfaceId.IsNull())
+ {
+ iParent.SurfaceManager().CloseSurface(iSurfaceId); // ignore the error
+ }
+
+ iSurfaceUpdateSession.Close();
+ // RSurface::Open() happened in context of caller.
+ iParent.SurfaceManager().Close();
+
+ iOffsetArray.Reset();
+ }
+
+TInt COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::Execute()
+ {
+ iParent.SetState(OMX_StateExecuting);
+ iFirstFrameDisplayed = EFalse;
+ TInt r = ProcessNextBuffer();
+ return r;
+ }
+
+TInt COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::Pause()
+ {
+ iParent.SetState(OMX_StatePause);
+ iFirstFrameDisplayed = EFalse;
+ Cancel();
+ iParent.TransitionToPauseFinished();
+ return KErrNone;
+ }
+
+TInt COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::Stop()
+ {
+ if(iParent.State() == OMX_StateExecuting || iParent.State() == OMX_StatePause)
+ {
+ // Cancel and flush the device driver
+ Cancel();
+ iParent.SetState(OMX_StateIdle);
+ iFirstFrameDisplayed = EFalse;
+ }
+ return KErrNone;
+ }
+
+void COmxILGraphicSinkProcessingFunction::CGraphicSurfaceAccess::ResetSurfaceId()
+ {
+ iSurfaceId = TSurfaceId::CreateNullId();
+ }
+
+COmxILGraphicSinkProcessingFunction::CPFHelper* COmxILGraphicSinkProcessingFunction::CPFHelper::NewL(COmxILGraphicSinkProcessingFunction& aParent, CGraphicSurfaceAccess& aGraphicSurfaceAccess)
+ {
+ CPFHelper* self = new (ELeave) CPFHelper(aParent, aGraphicSurfaceAccess);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+COmxILGraphicSinkProcessingFunction::CPFHelper::CPFHelper(COmxILGraphicSinkProcessingFunction& aParent, CGraphicSurfaceAccess& aSurfaceAccess)
+: CActive(EPriorityUserInput),
+ iParent(aParent),
+ iGraphicSurfaceAccess(aSurfaceAccess)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void COmxILGraphicSinkProcessingFunction::CPFHelper::ConstructL()
+ {
+ User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
+ SetActive();
+ iMsgQueue.NotifyDataAvailable(iStatus);
+ }
+
+COmxILGraphicSinkProcessingFunction::CPFHelper::~CPFHelper()
+ {
+ Cancel();
+ iMsgQueue.Close();
+ }
+
+void COmxILGraphicSinkProcessingFunction::CPFHelper::RunL()
+ {
+ iParent.iBufferMutex.Wait();
+ if (ProcessQueue() != KErrNone)
+ {
+ iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources);
+ }
+
+ // setup for next callbacks
+ SetActive();
+ iMsgQueue.NotifyDataAvailable(iStatus);
+ iParent.iBufferMutex.Signal();
+ }
+
+void COmxILGraphicSinkProcessingFunction::CPFHelper::DoCancel()
+ {
+ if (iMsgQueue.Handle())
+ {
+ ProcessQueue(); // TODO: ignore the error?
+ iMsgQueue.CancelDataAvailable();
+ }
+ }
+
+TInt COmxILGraphicSinkProcessingFunction::CPFHelper::ProcessQueue()
+ {
+ TMessageType msg;
+ TInt err = iMsgQueue.Receive(msg);
+ while (err == KErrNone)
+ {
+ switch (msg)
+ {
+ case EOpenDevice:
+ {
+ err = iGraphicSurfaceAccess.OpenDevice();
+ break;
+ }
+ case ECloseDevice:
+ {
+ iGraphicSurfaceAccess.CloseDevice();
+ break;
+ }
+
+ case EExecuteCommand:
+ {
+ err = iGraphicSurfaceAccess.Execute();
+ break;
+ }
+
+ case EStopCommand:
+ {
+ err = iGraphicSurfaceAccess.Stop();
+ break;
+ }
+
+ case EPauseCommand:
+ {
+ err = iGraphicSurfaceAccess.Pause();
+ break;
+ }
+
+ case EBufferIndication:
+ {
+ // Add buffer to list waiting to process.
+ // While we could send zero length buffers straight back, this would cause a
+ // problem if that buffer has a flag on it that needs processing. So we still
+ // pass them on and the graphics surface access code will not display them.
+ if (iParent.State() == OMX_StateExecuting || iParent.State() == OMX_StatePause)
+ {
+ err = iGraphicSurfaceAccess.ProcessNextBuffer();
+ }
+ break;
+ }
+ default:
+ {
+ DEBUG_PRINTF2(_L8("\nMsqQue >> %d"),msg);
+ break;
+ }
+ }
+
+ if (err)
+ {
+ break;
+ }
+
+ err = iMsgQueue.Receive(msg);
+ }
+
+ if ( err == KErrUnderflow)
+ {
+ err = KErrNone;
+ }
+
+ return err;
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::OpenDevice()
+ {
+ TMessageType message;
+ message = EOpenDevice;
+ return ConvertError(iMsgQueue.Send(message));
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::CloseDevice()
+ {
+ TMessageType message;
+ message = ECloseDevice;
+ return ConvertError(iMsgQueue.Send(message));
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::ExecuteAsync()
+ {
+ TMessageType message;
+ message = EExecuteCommand;
+ return ConvertError(iMsgQueue.Send(message));
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::StopAsync()
+ {
+ TMessageType message;
+ message = EStopCommand;
+ return ConvertError(iMsgQueue.Send(message));
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::StopSync()
+ {
+ // Cancel to process the existing queue before handling this command
+ if (IsActive())
+ {
+ Cancel();
+ }
+
+ TInt err = iGraphicSurfaceAccess.Stop();
+
+ // setup for next callbacks
+ SetActive();
+ iMsgQueue.NotifyDataAvailable(iStatus);
+
+ return ConvertError(err);
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::Pause()
+ {
+ TMessageType message;
+ message = EPauseCommand;
+ return ConvertError(iMsgQueue.Send(message));
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::BufferIndication()
+ {
+ TMessageType message;
+ message = EBufferIndication;
+ return ConvertError(iMsgQueue.Send(message));
+ }
+
+OMX_ERRORTYPE COmxILGraphicSinkProcessingFunction::CPFHelper::ConvertError(TInt aError)
+ {
+ if(aError == KErrNone)
+ {
+ return OMX_ErrorNone;
+ }
+ else if(aError == KErrOverflow)
+ {
+ return OMX_ErrorInsufficientResources;
+ }
+
+ // default
+ return OMX_ErrorUndefined;
+ }