--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/omxil/generic/omxilfilesource/src/omxilfilesourceprocessingfunction.cpp Fri May 07 16:25:23 2010 +0100
@@ -0,0 +1,656 @@
+// 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 <uri8.h>
+#include "omxilcallbackmanager.h"
+#include "omxilfilesourceprocessingfunction.h"
+
+const TInt KMaxMsgQueueEntries = 25;
+
+
+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;
+ iFileSourceAccess = CFileSourceAccess::NewL(*this);
+ iPFHelper = CPFHelper::NewL(*this, *iFileSourceAccess);
+ }
+
+COmxILFileSourceProcessingFunction::~COmxILFileSourceProcessingFunction()
+ {
+ if(iPFHelper &&
+ (iState == OMX_StateInvalid ||
+ iState == OMX_StateExecuting ||
+ iState == OMX_StatePause))
+ {
+ iPFHelper->StopSync();
+ }
+
+ delete iPFHelper;
+ delete iFileSourceAccess;
+ delete iUri;
+ delete iFileName;
+
+ // Buffer headers are not owned by the processing function
+ iBuffersToFill.Close();
+ }
+
+OMX_ERRORTYPE COmxILFileSourceProcessingFunction::StateTransitionIndication(COmxILFsm::TStateIndex aNewState)
+ {
+ OMX_ERRORTYPE err = OMX_ErrorNone;
+ switch(aNewState)
+ {
+ case COmxILFsm::EStateExecuting:
+ {
+ if (iPFHelper->ExecuteAsync() != KErrNone)
+ {
+ err = OMX_ErrorInsufficientResources;
+ }
+ }
+ break;
+
+ case COmxILFsm::EStateInvalid:
+ {
+ if (iPFHelper && iPFHelper->StopAsync() != KErrNone)
+ {
+ err = OMX_ErrorInsufficientResources;
+ }
+
+ }
+ break;
+
+ case COmxILFsm::EStatePause:
+ {
+ iPFHelper->PauseAsync();
+ }
+ break;
+
+ case COmxILFsm::EStateIdle:
+ {
+ iPFHelper->IdleAsync();
+ }
+ break;
+
+ case COmxILFsm::EStateLoaded:
+ case COmxILFsm::EStateWaitForResources:
+ {
+ if (iPFHelper && iPFHelper->StopAsync() != KErrNone)
+ {
+ err = OMX_ErrorInsufficientResources;
+ }
+ }
+ break;
+
+ case COmxILFsm::ESubStateExecutingToIdle:
+ {
+ iPFHelper->StopAsync();
+ }
+ break;
+ case COmxILFsm::ESubStatePauseToIdle:
+ case COmxILFsm::ESubStateLoadedToIdle:
+ case COmxILFsm::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))
+ {
+ // Send BufferDone notifications for each bufer...
+ for (TUint i=0, bufferCount=iBuffersToFill.Count(); i<bufferCount; ++i)
+ {
+ OMX_BUFFERHEADERTYPE* pBufferHeader = iBuffersToFill[i];
+ iCallbacks.BufferDoneNotification(pBufferHeader,
+ pBufferHeader->nOutputPortIndex,
+ OMX_DirOutput);
+ }
+ // Empty buffer lists...
+ iBuffersToFill.Reset();
+ }
+ 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<const OMX_PARAM_PORTDEFINITIONTYPE*>(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<const OMX_PARAM_CONTENTURITYPE*>(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 (iPFHelper->BufferIndication(apBufferHeader) != KErrNone)
+ {
+ return OMX_ErrorInsufficientResources;
+ }
+ }
+ else
+ {
+ return OMX_ErrorBadParameter;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+OMX_BOOL COmxILFileSourceProcessingFunction::BufferRemovalIndication(OMX_BUFFERHEADERTYPE* apBufferHeader, OMX_DIRTYPE /*aDirection*/)
+ {
+ OMX_BOOL headerDeletionResult = OMX_TRUE;
+
+ TInt headerIndexInArray = KErrNotFound;
+ if (KErrNotFound !=(headerIndexInArray = iBuffersToFill.Find(apBufferHeader)))
+ {
+ iBuffersToFill.Remove(headerIndexInArray);
+ }
+ else
+ {
+ headerDeletionResult = OMX_FALSE;
+ }
+
+ return headerDeletionResult;
+ }
+
+MOmxILCallbackNotificationIf& COmxILFileSourceProcessingFunction::GetCallbacks()
+ {
+ return iCallbacks;
+ }
+
+OMX_ERRORTYPE COmxILFileSourceProcessingFunction::SetFileName(const OMX_PARAM_CONTENTURITYPE* aContentUriType)
+ {
+ ASSERT(aContentUriType);
+ delete iFileName;
+ iFileName = NULL;
+ delete iUri;
+ iUri = 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, iFileName = parser.GetFileNameL());
+ if (err != KErrNone)
+ {
+ break;
+ }
+
+ // Remove Null charcter '\0' if any.
+ TPtr filePtr(iFileName->Des());
+ TInt index = filePtr.LocateReverse('\0');
+ if (index != KErrNotFound && index == filePtr.Length()-1)
+ {
+ filePtr.Delete(index,1);
+ }
+
+ uriDes.Set(reinterpret_cast<const TUint8 *>(aContentUriType), aContentUriType->nSize );
+ iUri = uriDes.Alloc();
+ if (!iUri)
+ {
+ err = KErrNoMemory;
+ break;
+ }
+
+ return OMX_ErrorNone;
+ }
+ while (EFalse);
+
+ // Something failed.
+ ASSERT(err != KErrNone);
+ delete iFileName;
+ iFileName = NULL;
+ delete iUri;
+ iUri = NULL;
+ return (err == KErrNoMemory ? OMX_ErrorInsufficientResources : OMX_ErrorBadParameter);
+ }
+
+
+const HBufC* COmxILFileSourceProcessingFunction::FileName() const
+ {
+ return iFileName;
+ }
+
+const HBufC8* COmxILFileSourceProcessingFunction::Uri() const
+ {
+ return iUri;
+ }
+
+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)
+ {
+ 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);
+ }
+ 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)
+ {
+ SetActive();
+ TRequestStatus* status(&iStatus);
+ User::RequestComplete(status, KErrNone);
+ }
+ else
+ {
+ iFileHandle.Read(iReadBuffer, iCurrentBuffer->nAllocLen, iStatus);
+ SetActive();
+ }
+ }
+
+ return err;
+ }
+
+void COmxILFileSourceProcessingFunction::CFileSourceAccess::DoCancel()
+ {
+ if (iFileHandle.SubSessionHandle() != 0)
+ {
+ iFileHandle.Close();
+ }
+ iCurrentBuffer = NULL;
+ }
+
+TInt COmxILFileSourceProcessingFunction::CFileSourceAccess::Execute()
+ {
+ 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::Stop()
+ {
+ if(iParent.iState == OMX_StateExecuting || iParent.iState == OMX_StatePause)
+ {
+ Cancel();
+ iParent.iState = OMX_StateIdle;
+ }
+ }
+
+COmxILFileSourceProcessingFunction::CPFHelper* COmxILFileSourceProcessingFunction::CPFHelper::NewL(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess)
+ {
+ CPFHelper* self = new (ELeave) CPFHelper(aParent, aFileSourceAccess);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+COmxILFileSourceProcessingFunction::CPFHelper::CPFHelper(COmxILFileSourceProcessingFunction& aParent, CFileSourceAccess& aFileSourceAccess)
+: CActive(EPriorityStandard),
+ iParent(aParent),
+ iFileSourceAccess(aFileSourceAccess)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void COmxILFileSourceProcessingFunction::CPFHelper::ConstructL()
+ {
+ User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
+ SetActive();
+ iMsgQueue.NotifyDataAvailable(iStatus);
+ }
+
+COmxILFileSourceProcessingFunction::CPFHelper::~CPFHelper()
+ {
+ Cancel();
+ iMsgQueue.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);
+ }
+ else
+ {
+//#define KHRONOS_CONFORMANCE
+// The KHRONOS_CONFORMANCE is required to pass the following khronos conformance component tests (FlushTest,
+// BaseMultiThreadedTest, StateTransitionTest, PortDisableEnableTest, IncompleteStopTest and PortCommunicationTest)
+// that expects no error to be returned when a filesource filename is not set.
+
+#ifdef KHRONOS_CONFORMANCE
+// do nothing, don't report any error
+#else
+ err = KErrPathNotFound;
+#endif
+ }
+ if ( err == KErrNone)
+ {
+ err = iFileSourceAccess.Execute();
+ }
+ break;
+ }
+
+ case EStopCommand:
+ {
+ iFileSourceAccess.Stop();
+ break;
+ }
+
+ case EPauseCommand:
+ {
+ iFileSourceAccess.Pause();
+ break;
+ }
+
+ case EIdleCommand:
+ {
+ iFileSourceAccess.Idle();
+ break;
+ }
+ case EBufferIndication:
+ {
+ OMX_BUFFERHEADERTYPE* bufferHeader = reinterpret_cast<OMX_BUFFERHEADERTYPE*>(msg.iPtr);
+
+ if ( bufferHeader && (iParent.iState == OMX_StateExecuting ||
+ iParent.iState == OMX_StatePause || iParent.iState == OMX_StateIdle) )
+ {
+ err = iParent.iBuffersToFill.Append(bufferHeader);
+ if(err == KErrNone)
+ {
+ if(iParent.iState != OMX_StateIdle)
+ {
+ err = iFileSourceAccess.ProcessNextBuffer();
+ }
+ }
+ else
+ {
+ // to prevent potential buffer leakage if the Append operation fails
+ iParent.GetCallbacks().BufferDoneNotification(bufferHeader, bufferHeader->nOutputPortIndex,OMX_DirOutput);
+ }
+ }
+ 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);
+ }
+
+
+TInt COmxILFileSourceProcessingFunction::CPFHelper::BufferIndication(OMX_BUFFERHEADERTYPE* apBufferHeader)
+ {
+ TProcMessage message;
+ message.iType = EBufferIndication;
+ message.iPtr = apBufferHeader;
+ 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);
+ }
+
+
+/**
+ 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;
+ }