diff -r 000000000000 -r 58be5850fb6c omxilcomp/omxilgeneric/filesource/src/omxilfilesourceprocessingfunction.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omxilcomp/omxilgeneric/filesource/src/omxilfilesourceprocessingfunction.cpp Thu Sep 02 20:13:57 2010 +0300 @@ -0,0 +1,892 @@ +// 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 + * @internalTechnology + */ + +#include +#include +#include "omxilfilesourceprocessingfunction.h" + +const TInt KMaxMsgQueueEntries = 25; +// This represents the number of times this component will respond to a client when the file handle is invalid +// (e.g a URI is not specified) before sending a OMX_BUFFERFLAG_EOS notification flag. This is to prevent +// the endless buffer passing. 250 is chosen as it is more than the number of buffers passed by Khronos conformance +// suite during port communication test. +const TInt KMaxBuffersWhenNoFileName =250; +const TInt KBufferSizeReturnedWhenNoFileName = 2; + +COmxILFileSourceProcessingFunction* COmxILFileSourceProcessingFunction::NewL(MOmxILCallbackNotificationIf& aCallbacks) + { + COmxILFileSourceProcessingFunction* self = new (ELeave) COmxILFileSourceProcessingFunction(aCallbacks); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +COmxILFileSourceProcessingFunction::COmxILFileSourceProcessingFunction(MOmxILCallbackNotificationIf& aCallbacks) +: COmxILProcessingFunction(aCallbacks) + { + } + +void COmxILFileSourceProcessingFunction::ConstructL() + { + iState = OMX_StateLoaded; + ipFileSourceAccess = CFileSourceAccess::NewL(*this); + ipBufferArrivalHandler = CBufferArrivalHandler::NewL(*this, *ipFileSourceAccess); + ipPFHelper = CPFHelper::NewL(*this, *ipFileSourceAccess, *ipBufferArrivalHandler); + } + +COmxILFileSourceProcessingFunction::~COmxILFileSourceProcessingFunction() + { + if(ipPFHelper && + (iState == OMX_StateInvalid || + iState == OMX_StateExecuting || + iState == OMX_StatePause)) + { + ipPFHelper->StopSync(); + } + + delete ipBufferArrivalHandler; + delete ipPFHelper; + delete ipFileSourceAccess; + delete ipUri; + delete ipFileName; + + // Buffer headers are not owned by the processing function + iBuffersToFill.Close(); + } + +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::StateTransitionIndication(TStateIndex aNewState) + { + OMX_ERRORTYPE err = OMX_ErrorNone; + switch(aNewState) + { + case EStateExecuting: + { + if (ipPFHelper->ExecuteAsync() != KErrNone) + { + err = OMX_ErrorInsufficientResources; + } + } + break; + + case EStateInvalid: + { + if (ipPFHelper && ipPFHelper->StopAsync() != KErrNone) + { + err = OMX_ErrorInsufficientResources; + } + + } + break; + + case EStatePause: + { + ipPFHelper->PauseAsync(); + } + break; + + case EStateIdle: + { + ipPFHelper->IdleAsync(); + } + break; + + case EStateLoaded: + case EStateWaitForResources: + { + if (ipPFHelper && ipPFHelper->StopAsync() != KErrNone) + { + err = OMX_ErrorInsufficientResources; + } + } + break; + + case ESubStateExecutingToIdle: + { + ipPFHelper->StopAsync(); + } + break; + case ESubStatePauseToIdle: + case ESubStateLoadedToIdle: + case ESubStateIdleToLoaded: + break; + + default: + { + err = OMX_ErrorIncorrectStateTransition; + } + }; + + return err; + } + +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::BufferFlushingIndication(TUint32 aPortIndex, OMX_DIRTYPE aDirection) + { + OMX_ERRORTYPE err = OMX_ErrorNone; + if ((aPortIndex == OMX_ALL && aDirection == OMX_DirMax) || + (aPortIndex == 0 && aDirection == OMX_DirOutput)) + { + err = CPFHelper::ConvertSymbianErrorType(ipPFHelper->FlushIndication()); + } + else + { + err = OMX_ErrorBadParameter; + } + return err; + } + +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::ParamIndication(OMX_INDEXTYPE aParamIndex, const TAny* apComponentParameterStructure) + { + OMX_ERRORTYPE err = OMX_ErrorNone; + switch(aParamIndex) + { + case OMX_IndexParamPortDefinition: + { + //const OMX_PARAM_PORTDEFINITIONTYPE* portDefinition = static_cast(apComponentParameterStructure); + //nothing to do + // + //the number of buffers may change depending on capture mode (single shot vs burst mode) + //in that case, we need to do something for PF... + break; + } + case OMX_IndexParamContentURI: + { + const OMX_PARAM_CONTENTURITYPE* contentUriType = reinterpret_cast(apComponentParameterStructure); + err = SetFileName(contentUriType); + break; + } + default: + { + err = OMX_ErrorUnsupportedIndex; + } + } + return err; + } + +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::ConfigIndication(OMX_INDEXTYPE /*aConfigIndex*/, const TAny* /*apComponentConfigStructure*/) + { + return OMX_ErrorNone; + } + +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE aDirection) + { + if (aDirection == OMX_DirOutput) + { + if (ipBufferArrivalHandler->BufferIndication(apBufferHeader) != KErrNone) + { + return OMX_ErrorInsufficientResources; + } + } + else + { + return OMX_ErrorBadParameter; + } + + return OMX_ErrorNone; + } + +OMX_BOOL COmxILFileSourceProcessingFunction::BufferRemovalIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE /*aDirection*/) + { + return ipPFHelper->RemoveBufferIndication(apBufferHeader); + } + +MOmxILCallbackNotificationIf& COmxILFileSourceProcessingFunction::GetCallbacks() + { + return iCallbacks; + } + +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::SetFileName(const OMX_PARAM_CONTENTURITYPE* aContentUriType) + { + ASSERT(aContentUriType); + delete ipFileName; + ipFileName = NULL; + delete ipUri; + ipUri = NULL; + + TInt sizeOfUri = aContentUriType->nSize - _FOFF(OMX_PARAM_CONTENTURITYPE, contentURI); //Actual size of URI + if (sizeOfUri <= 0) + { + return OMX_ErrorBadParameter; + } + + // Don't include the zero character at the end. + TPtrC8 uriDes(aContentUriType->contentURI,sizeOfUri); + + TInt err = KErrNone; + do + { + TUriParser8 parser; + err = parser.Parse(uriDes); + if (err != KErrNone) + { + break; + } + + TRAP(err, ipFileName = parser.GetFileNameL()); + if (err != KErrNone) + { + break; + } + + // Remove Null charcter '\0' if any. + TPtr filePtr(ipFileName->Des()); + TInt index = filePtr.LocateReverse('\0'); + if (index != KErrNotFound && index == filePtr.Length()-1) + { + filePtr.Delete(index,1); + } + + uriDes.Set(reinterpret_cast(aContentUriType), aContentUriType->nSize ); + ipUri = uriDes.Alloc(); + if (!ipUri) + { + err = KErrNoMemory; + break; + } + + return OMX_ErrorNone; + } + while (EFalse); + + // Something failed. + __ASSERT_DEBUG( (err == KErrNone), User::Panic(_L("UriParsing"), err) ); + + delete ipFileName; + ipFileName = NULL; + delete ipUri; + ipUri = NULL; + return (err == KErrNoMemory ? OMX_ErrorInsufficientResources : OMX_ErrorBadParameter); + } + + +const HBufC* COmxILFileSourceProcessingFunction::FileName() const + { + return ipFileName; + } + +const HBufC8* COmxILFileSourceProcessingFunction::Uri() const + { + return ipUri; + } + +COmxILFileSourceProcessingFunction::CFileSourceAccess* COmxILFileSourceProcessingFunction::CFileSourceAccess::NewL(COmxILFileSourceProcessingFunction& aParent) + { + CFileSourceAccess* self = new (ELeave) CFileSourceAccess(aParent); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +COmxILFileSourceProcessingFunction::CFileSourceAccess::CFileSourceAccess(COmxILFileSourceProcessingFunction& aParent) + : CActive(EPriorityStandard), + iParent(aParent), + iBufferOffset(0), + iReadBuffer(0,0), + iEOSFlag(EFalse) + { + CActiveScheduler::Add(this); + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::ConstructL() + { + User::LeaveIfError(iFs.Connect()); + } + +COmxILFileSourceProcessingFunction::CFileSourceAccess::~CFileSourceAccess() + { + Cancel(); + + iFileHandle.Close(); + iFs.Close(); + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::RunL() + { + // The buffer is not on the list implies that they have already been flushed/spotted + // via BufferFlushingIndication/BufferRemovalIndication + TInt index = iParent.iBuffersToFill.Find(iCurrentBuffer); + if (KErrNotFound != index) + { + switch(iStatus.Int()) + { + case KErrNone: + { + if (iReadBuffer.Length()==0) //the end of the file + { + iFileHandle.Close(); + iCurrentBuffer->nFlags |= OMX_BUFFERFLAG_EOS; + iParent.GetCallbacks().EventNotification(OMX_EventBufferFlag, iCurrentBuffer->nOutputPortIndex, OMX_BUFFERFLAG_EOS, NULL); + iEOSFlag = ETrue; + } + iCurrentBuffer->nFilledLen=iReadBuffer.Length(); + iCurrentBuffer->nOffset = 0; + break; + } + default: + { + User::Leave(iStatus.Int()); + } + }; + + iParent.GetCallbacks().BufferDoneNotification(iCurrentBuffer,iCurrentBuffer->nOutputPortIndex,OMX_DirOutput); + iParent.iBuffersToFill.Remove(index); + iCurrentBuffer = NULL; + } + + if(iFileHandle.SubSessionHandle() != 0) + { + ProcessNextBuffer(); + } + } + +TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::ProcessNextBuffer() + { + TInt err = KErrNone; + if ((iParent.iBuffersToFill.Count() > 0) && !IsActive() && iParent.iState == OMX_StateExecuting) + { + iCurrentBuffer = iParent.iBuffersToFill[0]; + iReadBuffer.Set(iCurrentBuffer->pBuffer, iCurrentBuffer->nAllocLen, iCurrentBuffer->nAllocLen); + if (iFileHandle.SubSessionHandle() == 0) + { + if(iEOSFlag == EFalse) + { + // This condition caters for when an IL client does not set the URI before trasitioning to + // executing state (like the Khronos conformance suite). The proposed way to deal with this is to keep + // sending BufferDone notification with blank buffers with size >0 for KMaxBuffersWhenNoFileName number + // of times before OMX_BUFFERFLAG_EOS flag is sent to client. This simulates a normal communication. + if( iEOSBufferNotificationCount <= KMaxBuffersWhenNoFileName ) + { + TUint nBufferSize = 0; + if (iEOSBufferNotificationCount < KMaxBuffersWhenNoFileName) + { + nBufferSize = KBufferSizeReturnedWhenNoFileName; + } + iReadBuffer.Set(iCurrentBuffer->pBuffer, nBufferSize, iCurrentBuffer->nAllocLen); + iEOSBufferNotificationCount++; + SetActive(); + TRequestStatus* status(&iStatus); + User::RequestComplete(status, KErrNone); + } + } + else + { + iReadBuffer.Set(iCurrentBuffer->pBuffer, iCurrentBuffer->nAllocLen, iCurrentBuffer->nAllocLen); + // do nothing. this menas that all operations have completed succesfully. + } + + } + else + { + iFileHandle.Read(iReadBuffer, iCurrentBuffer->nAllocLen, iStatus); + SetActive(); + } + } + return err; + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::DoCancel() + { + if (iFileHandle.SubSessionHandle() != 0) + { + iFileHandle.Close(); + } + iEOSFlag = EFalse; + iEOSBufferNotificationCount = 0; + + iCurrentBuffer = NULL; + } + +TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::Execute() + { + iEOSFlag = EFalse; + iEOSBufferNotificationCount = 0; + iParent.iState = OMX_StateExecuting; + return ProcessNextBuffer(); + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::Pause() + { + iParent.iState = OMX_StatePause; + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::Idle() + { + iParent.iState = OMX_StateIdle; + iParent.iBuffersToFill.Reset(); + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::CancelDataTransfer() + { + if(iFileHandle.SubSessionHandle() != 0) + { + iFileHandle.ReadCancel(); + } + } + +void COmxILFileSourceProcessingFunction::CFileSourceAccess::Stop() + { + if(iParent.iState == OMX_StateExecuting || iParent.iState == OMX_StatePause) + { + Cancel(); + iParent.iState = OMX_StateIdle; + } + } + +COmxILFileSourceProcessingFunction::CPFHelper* COmxILFileSourceProcessingFunction::CPFHelper::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess, CBufferArrivalHandler& aBufferArrivalHandler) + { + CPFHelper* self = new (ELeave) CPFHelper(aParent, aFileSourceAccess, aBufferArrivalHandler); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +COmxILFileSourceProcessingFunction::CPFHelper::CPFHelper(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess, CBufferArrivalHandler& aBufferArrivalHandler) +: CActive(CActive::EPriorityUserInput), + iParent(aParent), + iFileSourceAccess(aFileSourceAccess), + iBufferArrivalHandler(aBufferArrivalHandler) + { + CActiveScheduler::Add(this); + iRunLContext = RThread(); + } + +void COmxILFileSourceProcessingFunction::CPFHelper::ConstructL() + { + User::LeaveIfError(iWaitSemaphore.CreateLocal(0)); + User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries)); + SetActive(); + iMsgQueue.NotifyDataAvailable(iStatus); + } + +COmxILFileSourceProcessingFunction::CPFHelper::~CPFHelper() + { + Cancel(); + iMsgQueue.Close(); + iRunLContext.Close(); + iWaitSemaphore.Close(); + } + +void COmxILFileSourceProcessingFunction::CPFHelper::RunL() + { + TInt err = ProcessQueue(); + if (err != KErrNone) + { + iParent.GetCallbacks().ErrorEventNotification( ConvertSymbianErrorType(err) ); + } + + // setup for next callbacks + SetActive(); + iMsgQueue.NotifyDataAvailable(iStatus); + } + +void COmxILFileSourceProcessingFunction::CPFHelper::DoCancel() + { + if (iMsgQueue.Handle()) + { + ProcessQueue(); + iMsgQueue.CancelDataAvailable(); + } + } + +TInt COmxILFileSourceProcessingFunction::CPFHelper::ProcessQueue() + { + TProcMessage msg; + TInt err = KErrNone; + + while (iMsgQueue.Receive(msg) == KErrNone) + { + switch (msg.iType) + { + case EExecuteCommand: + { + const HBufC* fileName = iParent.FileName(); + if (fileName && iFileSourceAccess.iFileHandle.SubSessionHandle() == 0) + { + err = iFileSourceAccess.iFileHandle.Open(iFileSourceAccess.iFs, *fileName, EFileRead | EFileShareReadersOnly); + } + // Transition to execute only when opening the file succeeds or there is no file name at all + if ( err == KErrNone) + { + err = iFileSourceAccess.Execute(); + } + break; + } + + case EStopCommand: + { + iFileSourceAccess.Stop(); + break; + } + + case EPauseCommand: + { + iFileSourceAccess.Pause(); + break; + } + + case EIdleCommand: + { + iFileSourceAccess.Idle(); + break; + } + + case EFlushCommand: + { + // Carry out the flush and wake up the non-Active Scheduler client. + PerformFlush(); + iWaitSemaphore.Signal(); + break; + } + + case ERemoveBufferCommand: + { + // Carry out the buffer removal and wake up the non-Active Scheduler client. + TBufferRemovalArgs* args = reinterpret_cast(msg.iPtr); + *(args->iHdrRemoved) = PerformBufferRemoval(args->ipHeader); + iWaitSemaphore.Signal(); + break; + } + + default: + { + break; + } + } + + if (err) + { + break; + } + } + return err; + } + +TInt COmxILFileSourceProcessingFunction::CPFHelper::ExecuteAsync() + { + TProcMessage message; + message.iType = EExecuteCommand; + return iMsgQueue.Send(message); + } + +TInt COmxILFileSourceProcessingFunction::CPFHelper::StopAsync() + { + TProcMessage message; + message.iType = EStopCommand; + return iMsgQueue.Send(message); + } + +TInt COmxILFileSourceProcessingFunction::CPFHelper::PauseAsync() + { + TProcMessage message; + message.iType = EPauseCommand; + return iMsgQueue.Send(message); + } + +void COmxILFileSourceProcessingFunction::CPFHelper::StopSync() + { + // Cancel to process the existing queue before handling this command + Cancel(); + iFileSourceAccess.Stop(); + + // setup for next callbacks + SetActive(); + iMsgQueue.NotifyDataAvailable(iStatus); + } + +TInt COmxILFileSourceProcessingFunction::CPFHelper::IdleAsync() + { + TProcMessage message; + message.iType = EIdleCommand; + return iMsgQueue.Send(message); + } + +TInt COmxILFileSourceProcessingFunction::CPFHelper::FlushIndication() + { + TInt error = KErrNone; + RThread currentThread = RThread(); + if (currentThread.Id() == iRunLContext.Id()) + { + // Running in the same context as CFileSourceAccess::RunL() so + // sure of no concurrency issues. + PerformFlush(); + } + else + { + // Running in a different thread, meaning the client does + // not have an active scheduler. To avoid concurrency problems + // during the flush, switch to the thread in which the active objects' + // execution is handled. + TProcMessage message; + message.iType = EFlushCommand; + error = iMsgQueue.Send(message); + if (error == KErrNone) + { + iWaitSemaphore.Wait(); + } + } + currentThread.Close(); + return error; + } + +void COmxILFileSourceProcessingFunction::CPFHelper::PerformFlush() + { + // Running in the same context as CFileSourceAccess::RunL() so + // sure of no concurrency issues. + + // So that we don't continue to write to the buffer once it's returned. + iFileSourceAccess.CancelDataTransfer(); + + while (iParent.iBuffersToFill.Count() > 0) + { + OMX_BUFFERHEADERTYPE* pBufferHeader = iParent.iBuffersToFill[0]; + iParent.iBuffersToFill.Remove(0); + iParent.iCallbacks.BufferDoneNotification(pBufferHeader, + pBufferHeader->nOutputPortIndex, + OMX_DirOutput); + } + + iBufferArrivalHandler.FlushIndication(); + } + +OMX_BOOL COmxILFileSourceProcessingFunction::CPFHelper::RemoveBufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader) + { + TInt error = KErrNone; + RThread currentThread = RThread(); + if (currentThread.Id() == iRunLContext.Id()) + { + currentThread.Close(); + // Running in the same context as CFileSourceAccess::RunL() so + // sure of no concurrency issues. + return PerformBufferRemoval(apBufferHeader); + } + else + { + currentThread.Close(); + // Running in a different thread, meaning the client does + // not have an active scheduler. To avoid concurrency problems + // during the flush, switch to the thread in which the active objects' + // execution is handled. + TProcMessage message; + OMX_BOOL bufferFound; + TBufferRemovalArgs messageArgs; + messageArgs.ipHeader = apBufferHeader; + messageArgs.iHdrRemoved = &bufferFound; + message.iType = ERemoveBufferCommand; + message.iPtr = &messageArgs; + error = iMsgQueue.Send(message); + if (error == KErrNone) + { + iWaitSemaphore.Wait(); + return bufferFound; + } + iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources); + return OMX_FALSE; + } + } + +OMX_BOOL COmxILFileSourceProcessingFunction::CPFHelper::PerformBufferRemoval(OMX_BUFFERHEADERTYPE* apBufferHeader) + { + if (iParent.iBuffersToFill.Count() < 1) + { + return OMX_FALSE; + } + + if (iParent.iBuffersToFill[0] == apBufferHeader) + { + iFileSourceAccess.CancelDataTransfer(); + iParent.iBuffersToFill.Remove(0); + return OMX_TRUE; + } + + TInt count = iParent.iBuffersToFill.Count(); + for (TInt index = 1; index < count; ++index) + { + if (iParent.iBuffersToFill[index] == apBufferHeader) + { + iParent.iBuffersToFill.Remove(index); + return OMX_TRUE; + } + } + + return iBufferArrivalHandler.RemoveBufferIndication(apBufferHeader); + } + +/** + Converts a Symbian error code to an OpenMAX error code. + @param aError The Symbian error code. + @return The OpenMAX error code. + */ +OMX_ERRORTYPE COmxILFileSourceProcessingFunction::CPFHelper::ConvertSymbianErrorType(TInt aError) + { + // In the current implementation this function is only used for the return code in the + // callback methods. Currently the only expected errors KErrNone and KErrOverflow. + + OMX_ERRORTYPE err = OMX_ErrorNone; + switch (aError) + { + case KErrNone: + err = OMX_ErrorNone; + break; + case KErrOverflow: + case KErrNoMemory: + err = OMX_ErrorInsufficientResources; + break; + case KErrNotSupported: + err = OMX_ErrorNotImplemented; + break; + case KErrNotReady: + err = OMX_ErrorNotReady; + break; + case KErrGeneral: + default: + err = OMX_ErrorUndefined; + } + return err; + } + +COmxILFileSourceProcessingFunction::CBufferArrivalHandler* COmxILFileSourceProcessingFunction::CBufferArrivalHandler::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess) + { + CBufferArrivalHandler* self = new (ELeave) CBufferArrivalHandler(aParent, aFileSourceAccess); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +COmxILFileSourceProcessingFunction::CBufferArrivalHandler::CBufferArrivalHandler(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess) +: CActive(CActive::EPriorityStandard), + iParent(aParent), + iFileSourceAccess(aFileSourceAccess) + { + CActiveScheduler::Add(this); + } + +void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::ConstructL() + { + User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries)); + SetActive(); + iMsgQueue.NotifyDataAvailable(iStatus); + } + +COmxILFileSourceProcessingFunction::CBufferArrivalHandler::~CBufferArrivalHandler() + { + Cancel(); + iMsgQueue.Close(); // Queue should be emptied by now + } + +TInt COmxILFileSourceProcessingFunction::CBufferArrivalHandler::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader) + { + TBufferIndicationMessage msg; + msg.iBufferHdr = apBufferHeader; + return iMsgQueue.Send(msg); + } + +/* + * Bear in mind that this results in BufferDoneNotifications and so should be called at the end of of the + * flush sequence to ensure headers are completed in the order they were received. + */ +void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::FlushIndication() + { + TBufferIndicationMessage msg; + + while (iMsgQueue.Receive(msg) == KErrNone) + { + iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput); + } + } + +OMX_BOOL COmxILFileSourceProcessingFunction::CBufferArrivalHandler::RemoveBufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader) + { + RArray bufferedMsgs; + TBufferIndicationMessage msg; + + OMX_BOOL hdrFound = OMX_FALSE; + while (iMsgQueue.Receive(msg) == KErrNone) + { + if (msg.iBufferHdr == apBufferHeader) + { + hdrFound = OMX_TRUE; + } + else + { + TInt error = bufferedMsgs.Append(msg); + if (error != KErrNone) + { + // to prevent potential buffer leakage if the Append operation fails + iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput); + } + } + } + + TInt count = bufferedMsgs.Count(); + for (TInt index = 0; index < count; ++index) + { + // There's the potential here, in an environment when 3+ threads + // (which is possible in the case of a non-AS client and a multi-threaded + // tunneled component, e.g. Bellagio) are manipulatng the component, for + // a buffer to be inserted out of order if a FillThisBuffer() command comes + // in during the move to Idle and with particular thread scheduling + // sequences. However as we only have one port and this command is called as + // part of a move to Idle or port disablement then we should get a + // BufferRemovalNotification() for every buffer so in this instance it shouldn't + // be a problem. + iMsgQueue.Send(bufferedMsgs[index]); + } + return hdrFound; + } + +void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::RunL() + { + TBufferIndicationMessage msg; + TInt err = iMsgQueue.Receive(msg); + + if ((err == KErrNone) && (iParent.iState == OMX_StateExecuting || + iParent.iState == OMX_StatePause || + iParent.iState == OMX_StateIdle)) + { + err = iParent.iBuffersToFill.Append(msg.iBufferHdr); + + if(err == KErrNone) + { + if(iParent.iState != OMX_StateIdle) + { + err = iFileSourceAccess.ProcessNextBuffer(); + } + } + else + { + iParent.GetCallbacks().ErrorEventNotification(OMX_ErrorInsufficientResources); + // to prevent potential buffer leakage if the Append operation fails + iParent.GetCallbacks().BufferDoneNotification(msg.iBufferHdr, msg.iBufferHdr->nOutputPortIndex,OMX_DirOutput); + } + } + + SetActive(); + iMsgQueue.NotifyDataAvailable(iStatus); + } + +void COmxILFileSourceProcessingFunction::CBufferArrivalHandler::DoCancel() + { + iMsgQueue.CancelDataAvailable(); + }