diff -r 735348f59235 -r 948c7f65f6d4 imagingandcamerafws/imagingfws/src/ThreadRelay.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imagingandcamerafws/imagingfws/src/ThreadRelay.cpp Wed Sep 01 12:38:50 2010 +0100 @@ -0,0 +1,1573 @@ +// Copyright (c) 2001-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: +// + +#include +using namespace ContentAccess; +#include "ThreadRelay.h" +#include "icl/ImageConstruct.h" +#include "icl/ImagePlugin.h" +#include "ImageClientMain.h" +#include "icl/ICL_UIDS.hrh" +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#include +#endif +#include "fwextconstants.h" +#include "iclextproxystubutil.h" + +// +// CBufferCopyListener +// +/** + * Factory function for this class. + * + * @param "const RThread* aSubThread" + * Thread to signal when buffer copy has been completed + */ +CBufferCopyListener* CBufferCopyListener::NewL(const RThread* aSubThread) + { + CBufferCopyListener* self; + self = new (ELeave) CBufferCopyListener(aSubThread); + return self; + } + +/** + * Constructor for this class. + * + * @param "const RThread* aSubThread" + * Thread to signal when buffer copy has been completed + */ +CBufferCopyListener::CBufferCopyListener(const RThread* aSubThread) : + CActive(EPriorityIdle) + { + iSubThread = aSubThread; + CActiveScheduler::Add(this); + } +/** + * Activate the buffer copy listener to listen for copy requests. + * + */ +void CBufferCopyListener::Prime() + { + ASSERT(IsActive() == EFalse); + iStatus = KRequestPending; + SetActive(); + } + +/** + * Initilise the listener for a buffer copy. + * + * @param "TRequestStatus& aCallerStatus" + * Request to signal when copy has been comlpeted. Signalled in thread + * passed to the listener at construction. + * @param "TDes8& aBuffer" + * Destination buffer for copy. + * @param "const TDesC8& aSource" + * Source descriptor for copy. + * @param "TInt aPosition" + * Position in buffer to start copy. + * @param "TInt aSize" + * Number of elements to copy. + */ +void CBufferCopyListener::CopyBufferToDescriptor(TRequestStatus& aCallerStatus, TDes8& aBuffer, const TDesC8& aSource, TInt aPosition, TInt aSize) + { + Prime(); + iCallerStatus = &aCallerStatus; + iBuffer = &aBuffer; + iSource = &aSource; + iPosition = aPosition; + iSize = aSize; + } + +/** + * + * Perform the buffer copy. + * + */ +void CBufferCopyListener::RunL() + { + ASSERT(iStatus==KErrNone); + DoBufferCopy(); + } + +/** + * + * Perform the buffer copy and signal the requesting thread when the copy has completed. + * + */ +void CBufferCopyListener::DoBufferCopy() + { + ASSERT(iStatus == KErrNone); + ASSERT(iSource != NULL); + ASSERT(iBuffer != NULL); + ASSERT(iSubThread != NULL); + + *iBuffer = iSource->Mid(iPosition, iSize); + + TRequestStatus *status = iCallerStatus; + iSubThread->RequestComplete(status,KErrNone); + } + +/** + * + * Cancel an outstanding copy request. + * + */ +void CBufferCopyListener::DoCancel() + { + } +/** + * + * Destructor for this class. + * + */ +CBufferCopyListener::~CBufferCopyListener() + { + } + +// +// CThreadDecoderRelay +// +/** + * Actual factory function for this class + * + * @param "CImageDecodeConstruct* aConstruct" + * A object to construct a decoder. + * @return "CThreadDecoderRelay*" + * A pointer to the constructed object + */ +CThreadDecoderRelay* CThreadDecoderRelay::NewL(CImageDecodeConstruct* aConstruct) + { + CThreadDecoderRelay* self; + self = new (ELeave) CThreadDecoderRelay(aConstruct); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** + * Second phase constructor for this class. + * Create a buffer copy listener and send it and a factory function + * to create a decoder as parameters to the thread. + * + */ +void CThreadDecoderRelay::ConstructL() + { + //Start a buffer copy listener and prime it to listen for requests + iBufferCopyListener = CBufferCopyListener::NewL(SubThread()); + + //Package the parameters to create a CSubThreadDecoderRelay + TThreadDecoderRelayParam params; + + //Send the status of the buffer copy AO to the sub thread + params.iBufferCopyListener = iBufferCopyListener; + + //Add the CImageDecodeConstruct object that will create the decoder + params.iConstruct = iConstruct; + + CThreadRelay::ConstructL(CSubThreadDecoderRelay::NewL, ¶ms); + + iSubThreadDecoderRelay = STATIC_CAST(CSubThreadDecoderRelay*, SubThreadRelay()); + iBody = iSubThreadDecoderRelay->iBody; + iExtensionCache = CImageConvExtensionCache::NewL(); + } + +/** + * Constructor for this class. + * + */ +CThreadDecoderRelay::CThreadDecoderRelay(CImageDecodeConstruct* aConstruct) : + iConstruct(aConstruct) + { + } + +/** + * Destructor for this class. + * If a buffer copy listener was created cancel and delete it. + * If ownership for the construct object was passed, delete it. + * + */ +CThreadDecoderRelay::~CThreadDecoderRelay() + { + delete iExtensionCache; + if(iBufferCopyListener) + { + iBufferCopyListener->Cancel(); + delete iBufferCopyListener; + } + + if(iOwnConstruct) + delete iConstruct; + } + +/** + * Run a function that should not leave in the codec thread. + * Let the thread know a function call will follow (to allow the thread to do + * local buffer copies) and request the function to run. If the function does leave + * panic the current thread. + * + * @param "TInt aFunctionCode" + * The function to run in the codec thread. + * @param "TAny* aParameters" + * The parameters to the function. + * @panic "KInvalidFunctionLeave" + * If the function in the codec thread leaves. + */ +void CThreadDecoderRelay::RunFunction(TInt aFunctionCode, TAny* aParameters) + { + ASSERT(iSubThreadDecoderRelay!=NULL); + iSubThreadDecoderRelay->SetFunctionInProgress(); + TInt error = CThreadRelay::RunFunction(aFunctionCode, aParameters); + iSubThreadDecoderRelay->ResetFunctionInProgress(); + + if(error!=KErrNone) + Panic(EInvalidFunctionLeave); + } + +/** + * Run a function that can leave in the codec thread. + * Let the thread know a function call will follow (to allow the thread to do + * local buffer copies) and request the function ro run. If the function do leave + * leave in this thread with the same error code. + * + * @param "TInt aFunctionCode" + * The function to run in the codec thread. + * @param "TAny* aParameters" + * The parameters to the function. + */ +void CThreadDecoderRelay::RunFunctionL(TInt aFunctionCode, TAny* aParameters) + { + ASSERT(iSubThreadDecoderRelay!=NULL); + iSubThreadDecoderRelay->SetFunctionInProgress(); + TInt error = CThreadRelay::RunFunction(aFunctionCode, aParameters); + iSubThreadDecoderRelay->ResetFunctionInProgress(); + + if(error!=KErrNone) + User::Leave(error); + } +/** + * Cancel the threaded decoding in progress. + * Use a straight call to request plugins that do not use AO functionallity + * to abort and then request a normal decoding cancel in the codec thread. + */ +void CThreadDecoderRelay::Cancel() + { + //Use straight call to inform decoder to cancel + iSubThreadDecoderRelay->AbortDecode(); + //Up the decoding thread's priority for increased Cancel() response + SetPriority(RThread().Priority()); + //Cancel need no parameters + RunFunction(CSubThreadDecoderRelay::EFunctionCancel, NULL); + //Restore the priority + SetPriority(KSubThreadPriority); + } + +void CThreadDecoderRelay::SetFileL(RFs& /*aFs*/, const TDesC& aSourceFilename, const CImageDecoder::TOptions aOptions) + { + TDecodeSetFileParams params; + params.iSourceFilename = &aSourceFilename; + params.iOptions = aOptions; + + RunFunctionL(CSubThreadDecoderRelay::EFunctionSetFile, ¶ms); + } + +void CThreadDecoderRelay::SetFileL(RFile& aFile, const CImageDecoder::TOptions aOptions) + { + TDecodeSetFileHandleParams params; + params.iFile = &aFile; + params.iOptions = aOptions; + + RunFunctionL(CSubThreadDecoderRelay::EFunctionSetFileHandle, ¶ms); + } + + +void CThreadDecoderRelay::SetDataL(RFs& /*aFs*/, const TDesC8& aSourceData, const CImageDecoder::TOptions aOptions) + { + TDecodeSetDataParams params; + params.iSourceData = &aSourceData; + params.iOptions = aOptions; + + RunFunctionL(CSubThreadDecoderRelay::EFunctionSetData, ¶ms); + } + +CImageDecoderPlugin* CThreadDecoderRelay::Plugin() const + { + return iBody->Plugin(); + } + +void CThreadDecoderRelay::HandleNewlyOpenedImageL() + { + RunFunctionL(CSubThreadDecoderRelay::EFunctionHandleNewImage, NULL); + } + +void CThreadDecoderRelay::Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, TInt aFrameNumber) + { + *aRequestStatus = KRequestPending; + TDecodeConvertParams params; + params.iRequestStatus = aRequestStatus; + params.iDestinationHandle = aDestination.Handle(); + params.iFrameNumber = aFrameNumber; + + RunFunction(CSubThreadDecoderRelay::EFunctionConvert, ¶ms); + } + +void CThreadDecoderRelay::Convert(TRequestStatus* aRequestStatus, CFbsBitmap& aDestination, CFbsBitmap& aDestinationMask, TInt aFrameNumber) + { + *aRequestStatus = KRequestPending; + TDecodeConvertParams params; + params.iRequestStatus = aRequestStatus; + params.iDestinationHandle = aDestination.Handle(); + params.iDestinationMaskHandle = aDestinationMask.Handle(); + params.iFrameNumber = aFrameNumber; + + RunFunction(CSubThreadDecoderRelay::EFunctionConvertMask, ¶ms); + } + +void CThreadDecoderRelay::ContinueConvert(TRequestStatus* aRequestStatus) + { + *aRequestStatus = KRequestPending; + TDecodeConvertParams params; + params.iRequestStatus = aRequestStatus; + + RunFunction(CSubThreadDecoderRelay::EFunctionContinueConvert, ¶ms); + } + +void CThreadDecoderRelay::ContinueProcessingHeaderL() + { + RunFunctionL(CSubThreadDecoderRelay::EFunctionContinueHeader, NULL); + } + +void CThreadDecoderRelay::SetImageTypeL(TInt aImageType) + { + iBody->SetImageTypeL(aImageType); + } + +const TFrameInfo& CThreadDecoderRelay::FrameInfo(TInt aFrameNumber) const + { + iSubThreadDecoderRelay->Lock(); + const TFrameInfo& frameInfo = iBody->FrameInfo(aFrameNumber); + iSubThreadDecoderRelay->Unlock(); + return frameInfo; + } + +const CFrameImageData& CThreadDecoderRelay::FrameData(TInt aFrameNumber) const + { + iSubThreadDecoderRelay->Lock(); + const CFrameImageData& frameData = iBody->FrameData(aFrameNumber); + iSubThreadDecoderRelay->Unlock(); + return frameData; + } + +TInt CThreadDecoderRelay::NumberOfImageComments() const + { + iSubThreadDecoderRelay->Lock(); + TInt noOfImageComments = iBody->Plugin()->NumberOfImageComments(); + iSubThreadDecoderRelay->Unlock(); + return noOfImageComments; + } + +HBufC* CThreadDecoderRelay::ImageCommentL(TInt aCommentNumber) const + { + iSubThreadDecoderRelay->Lock(); + HBufC* imageComment = iBody->Plugin()->ImageCommentL(aCommentNumber); + iSubThreadDecoderRelay->Unlock(); + return imageComment; + } + +TInt CThreadDecoderRelay::NumberOfFrameComments(TInt aFrameNumber) const + { + iSubThreadDecoderRelay->Lock(); + TInt noOfFrameComments = iBody->Plugin()->NumberOfFrameComments(aFrameNumber); + iSubThreadDecoderRelay->Unlock(); + return noOfFrameComments; + } + +HBufC* CThreadDecoderRelay::FrameCommentL(TInt aFrameNumber, TInt aCommentNumber) const + { + iSubThreadDecoderRelay->Lock(); + HBufC* frameComment = iBody->Plugin()->FrameCommentL(aFrameNumber, aCommentNumber); + iSubThreadDecoderRelay->Unlock(); + return frameComment; + } + +CFrameInfoStrings* CThreadDecoderRelay::FrameInfoStringsLC(TInt aFrameNumber) + { + return iBody->FrameInfoStringsLC(aFrameNumber); + } + +TUid CThreadDecoderRelay::ImplementationUid() const + { + return iBody->ImplementationUid(); + } + +TInt CThreadDecoderRelay::FrameCount() const + { + return iSubThreadDecoderRelay->FrameCount(); + } + +TBool CThreadDecoderRelay::IsImageHeaderProcessingComplete() const + { + return iBody->IsImageHeaderProcessingComplete(); + } + +void CThreadDecoderRelay::CustomSyncL(TInt aParam) + { + TCustomSyncParams params; + params.iParam = aParam; + + RunFunctionL(CSubThreadDecoderRelay::EFunctionCustomSync, ¶ms); + } + +void CThreadDecoderRelay::CustomAsync(TRequestStatus* aRequestStatus, TInt aParam) + { + *aRequestStatus = KRequestPending; + TCustomSyncParams params; + params.iRequestStatus = aRequestStatus; + params.iParam = aParam; + + RunFunction(CSubThreadDecoderRelay::EFunctionCustomAsync, ¶ms); + } + +void CThreadDecoderRelay::TransferConstructOwnership() + { + iOwnConstruct = ETrue; + } + +void CThreadDecoderRelay::SetIntent(TIntent aIntent) + { + iBody->SetIntent(aIntent); + } + +void CThreadDecoderRelay::SetUniqueIdL(const TDesC& aUniqueId) + { + iBody->SetUniqueIdL(aUniqueId); + } + +TInt CThreadDecoderRelay::SetAgentProperty(ContentAccess::TAgentProperty aProperty, TInt aValue) + { + return iBody->SetAgentProperty(aProperty, aValue); + } + +TInt CThreadDecoderRelay::ReductionFactor(const TSize& aOriginalSize, const TSize& aReducedSize) const + { + return iBody->ReductionFactor(aOriginalSize, aReducedSize); + } + +TInt CThreadDecoderRelay::ReducedSize(const TSize& aOriginalSize, TInt aReductionFactor, TSize& aReducedSize) const + { + return iBody->ReducedSize(aOriginalSize, aReductionFactor, aReducedSize); + } + +TInt CThreadDecoderRelay::SetDecoderThreadPriority(TThreadPriority aPriority) + { + SetPriority(aPriority); + return KErrNone; + } + +void CThreadDecoderRelay::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr) + { + __ASSERT_ALWAYS(aExtPtr == NULL, Panic(ENonNullImageConvExtension)); + + CImageConvProxyBase* proxy = ProxyStubUtility::GetNewProxyL(aExtUid, this); + CleanupStack::PushL(proxy); + + TGetExtensionParams params; + params.iUid = aExtUid; + params.iExtension = &aExtPtr; + RunFunctionL(CSubThreadDecoderRelay::EFunctionGetExtension, ¶ms); + proxy->SetupExtension(aExtPtr); + iExtensionCache->SetProxyL(proxy); + CleanupStack::Pop(proxy); + //aExtPtr contains pointer to the proxy + } + +void CThreadDecoderRelay::SetClippingRectL(const TRect* aClipRect) + { + iBody->SetClippingRectL(aClipRect); + } + +TInt CThreadDecoderRelay::GetDestinationSize(TSize& aSize, TInt aFrameNumber) + { + return iBody->Plugin()->GetDestinationSize(aSize, aFrameNumber); + } + +CImageConvExtensionCache& CThreadDecoderRelay::ExtensionCache() + { + return *iExtensionCache; + } + +void CThreadDecoderRelay::ExecuteCommand(TExecuteCommandParamsBase& aExecuteCommandBase) + { + RunFunction(CSubThreadDecoderRelay::EFunctionExecuteCommandL, &aExecuteCommandBase); + } + +void CThreadDecoderRelay::ExecuteCommandL(TExecuteCommandParamsBase& aExecuteCommandBase) + { + RunFunctionL(CSubThreadDecoderRelay::EFunctionExecuteCommandL, &aExecuteCommandBase); + } + +void CThreadDecoderRelay::ExecuteAsyncCommand(TExecuteCommandParamsBase& aExecuteCommandBase) + { + RunFunction(CSubThreadDecoderRelay::EFunctionExecuteAsyncCommand, &aExecuteCommandBase); + } + +// +// CThreadEncoderRelay +// +/** + * Actual factory function for this class + * + * @param "CImageEncodeConstruct* aConstruct" + * A object to construct an encoder. + * @return "CThreadEncoderRelay*" + * A pointer to the constructed object + */ +CThreadEncoderRelay* CThreadEncoderRelay::NewL(CImageEncodeConstruct* aConstruct) + { + CThreadEncoderRelay* self; + self = new (ELeave) CThreadEncoderRelay(aConstruct); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +/** + * Constructor for this class. + * + */ +CThreadEncoderRelay::CThreadEncoderRelay(CImageEncodeConstruct* aConstruct) : + iConstruct(aConstruct) + { + } + +/** + * Second phase constructor for this class. + * Send a factory function to create an encoder is as a parameter to the thread. + * + */ +void CThreadEncoderRelay::ConstructL() + { + //Package the parameters to create a CSubThreadDecoderRelay + TThreadEncoderRelayParam params; + + //Add the CImageEncodeConstruct object that will create the encoder + params.iConstruct = iConstruct; + + CThreadRelay::ConstructL(CSubThreadEncoderRelay::NewL, ¶ms); + + iSubThreadEncoderRelay = STATIC_CAST(CSubThreadEncoderRelay*, SubThreadRelay()); + iBody = iSubThreadEncoderRelay->iBody; + iExtensionCache = CImageConvExtensionCache::NewL(); + } + +void CThreadEncoderRelay::Cancel() + { + //Use straight call to inform encoder to cancel + iSubThreadEncoderRelay->AbortEncode(); + //Up the encoding thread's priority for increased Cancel() response + SetPriority(RThread().Priority()); + //Cancel needs no parameters + RunFunction(CSubThreadEncoderRelay::EFunctionCancel, NULL); + //Restore the priority + SetPriority(KSubThreadPriority); + } + +void CThreadEncoderRelay::SetFileL(RFs& /*aFs*/, const TDesC& aDestinationFilename, const CImageEncoder::TOptions aOptions) + { + TEncodeSetFileParams params; + params.iDestinationFilename = &aDestinationFilename; + params.iOptions = aOptions; + + RunFunctionL(CSubThreadEncoderRelay::EFunctionSetFile, ¶ms); + } + +void CThreadEncoderRelay::SetFileL(RFile& aFile, const CImageEncoder::TOptions aOptions) + { + TEncodeSetFileHandleParams params; + params.iFile = &aFile; + params.iOptions = aOptions; + RunFunctionL(CSubThreadEncoderRelay::EFunctionSetFileHandle, ¶ms); + } + +void CThreadEncoderRelay::SetDataL(HBufC8*& aDestinationData, const CImageEncoder::TOptions aOptions) + { + TEncodeSetDataParams params; + params.iDestinationData = &aDestinationData; + params.iOptions = aOptions; + + RunFunctionL(CSubThreadEncoderRelay::EFunctionSetData, ¶ms); + } + +CImageEncoderPlugin* CThreadEncoderRelay::Plugin() const + { + return iBody->Plugin(); + } + +void CThreadEncoderRelay::Convert(TRequestStatus* aRequestStatus, const CFbsBitmap& aSource, const CFrameImageData* aFrameImageData) + { + *aRequestStatus = KRequestPending; + TEncodeConvertParams params; + params.iRequestStatus = aRequestStatus; + params.iSourceHandle = aSource.Handle(); + params.iFrameImageData = aFrameImageData; + + RunFunction(CSubThreadEncoderRelay::EFunctionConvert, ¶ms); + } + +TUid CThreadEncoderRelay::ImplementationUid() const + { + return iBody->ImplementationUid(); + } + +void CThreadEncoderRelay::CustomSyncL(TInt aParam) + { + TCustomSyncParams params; + params.iParam = aParam; + + RunFunctionL(CSubThreadEncoderRelay::EFunctionCustomSync, ¶ms); + } + +void CThreadEncoderRelay::CustomAsync(TRequestStatus* aRequestStatus, TInt aParam) + { + *aRequestStatus = KRequestPending; + TCustomSyncParams params; + params.iRequestStatus = aRequestStatus; + params.iParam = aParam; + + RunFunction(CSubThreadEncoderRelay::EFunctionCustomAsync, ¶ms); + } + +void CThreadEncoderRelay::TransferConstructOwnership() + { + iOwnConstruct = ETrue; + } + +void CThreadEncoderRelay::RunFunction(TInt aFunctionCode, TAny* aParameters) + { + ASSERT(iSubThreadEncoderRelay!=NULL); + TInt error = CThreadRelay::RunFunction(aFunctionCode, aParameters); + if(error!=KErrNone) + Panic(EInvalidFunctionLeave); + } + +void CThreadEncoderRelay::RunFunctionL(TInt aFunctionCode, TAny* aParameters) + { + ASSERT(iSubThreadEncoderRelay!=NULL); + TInt error = CThreadRelay::RunFunction(aFunctionCode, aParameters); + if(error!=KErrNone) + User::Leave(error); + } + +CThreadEncoderRelay::~CThreadEncoderRelay() + { + delete iExtensionCache; + if(iOwnConstruct) + delete iConstruct; + } +void CThreadEncoderRelay::SetThumbnail(TBool aDoGenerateThumbnail) + { + iBody->SetThumbnail(aDoGenerateThumbnail); + } + +TInt CThreadEncoderRelay::SetEncoderThreadPriority(TThreadPriority aPriority) + { + SetPriority( aPriority ); + return KErrNone; + } + +void CThreadEncoderRelay::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr) + { + __ASSERT_ALWAYS(aExtPtr == NULL, Panic(ENonNullImageConvExtension)); + + CImageConvProxyBase* proxy = ProxyStubUtility::GetNewProxyL(aExtUid, this); + CleanupStack::PushL(proxy); + + TGetExtensionParams params; + params.iUid = aExtUid; + params.iExtension = &aExtPtr; + RunFunctionL(CSubThreadEncoderRelay::EFunctionGetExtension, ¶ms); + proxy->SetupExtension(aExtPtr); + iExtensionCache->SetProxyL(proxy); + CleanupStack::Pop(proxy); + //aExtPtr contains pointer to the proxy + } + +CImageConvExtensionCache& CThreadEncoderRelay::ExtensionCache() + { + return *iExtensionCache; + } + +void CThreadEncoderRelay::ExecuteCommand(TExecuteCommandParamsBase& aExecuteCommandBase) + { + RunFunction(CSubThreadEncoderRelay::EFunctionExecuteCommandL, &aExecuteCommandBase); + } + +void CThreadEncoderRelay::ExecuteCommandL(TExecuteCommandParamsBase& aExecuteCommandBase) + { + RunFunctionL(CSubThreadEncoderRelay::EFunctionExecuteCommandL, &aExecuteCommandBase); + } + +void CThreadEncoderRelay::ExecuteAsyncCommand(TExecuteCommandParamsBase& aExecuteCommandBase) + { + RunFunction(CSubThreadEncoderRelay::EFunctionExecuteAsyncCommand, &aExecuteCommandBase); + } + +// +// CSubThreadDecoderRelay +// +/** + * Actual factory function for this class + * Decode the parameters and call the constructors. + * + */ +CSubThreadRelay* CSubThreadDecoderRelay::NewL(TThreadId aMainThreadId, TAny* aDecoderParam) + { + CSubThreadDecoderRelay* self; + TThreadDecoderRelayParam* decoderParam; + + decoderParam = STATIC_CAST(TThreadDecoderRelayParam*, aDecoderParam); + + self = new (ELeave) CSubThreadDecoderRelay(decoderParam->iBufferCopyListener); + CleanupStack::PushL(self); + self->ConstructL(aMainThreadId, decoderParam->iConstruct); + + CleanupStack::Pop(self); + return self; + } + +/** + * Constructor for this class. + * + */ +CSubThreadDecoderRelay::CSubThreadDecoderRelay(CBufferCopyListener* aBufferCopyListener) : + iBufferCopyListener(aBufferCopyListener) + { + } + +/** + * Second phase constructor for this class. + * Create a local file server session (shareable between threads) and mutexes + * to lock the frame tables and buffer copies. + * + * @param "TThreadId aMainThreadId" + * The id of the main thread. Open a local connection to the main thread. + * @param "CImageDecodeConstruct* aConstruct" + * A construct object to create the decoder. + */ +void CSubThreadDecoderRelay::ConstructL(TThreadId aMainThreadId, CImageDecodeConstruct* aConstruct) + { + CSubThreadRelay::ConstructL(aMainThreadId); + + //Open a file server session + User::LeaveIfError(iFileSession.Connect()); + //Make the session shareable for all threads +#ifdef __IPC_V2_PRESENT__ + User::LeaveIfError(iFileSession.ShareAuto()); +#else + User::LeaveIfError(iFileSession.Share(RSessionBase::EAutoAttach)); +#endif + + //Create a mutex for the frame tables + User::LeaveIfError(iFrameTableMutex.CreateLocal()); + //Create a mutex for buffer copies in main thread + User::LeaveIfError(iBufferCopyMutex.CreateLocal()); + + iBody = CImageDecoderPriv::NewL(aConstruct, this); + iBody->CreatePluginL(); + } + +/** + * Destructor for this class. + * + */ +CSubThreadDecoderRelay::~CSubThreadDecoderRelay() + { + Cancel(); + iStubs.ResetAndDestroy(); + if(iBody) + { + CancelBody(); + delete iBody; + } + iFrameTableMutex.Close(); + iBufferCopyMutex.Close(); + delete iDestination; + delete iDestinationMask; + iFileSession.Close(); + } + +/** + * Wait on buffer copy mutex for buffer copy in main thread + * to finish and change the state to a function call in progress. + * The codec subthread will use local buffer copies until ResetFunctionInProgress() + * is called. + * + */ +void CSubThreadDecoderRelay::SetFunctionInProgress() + { + //Note: assumes that this executes in the main thread. + ASSERT(RThread().Id() == iMainThread.Id()); + + //this will block until codec subthread has primed the buffer copy AO + iBufferCopyMutex.Wait(); + if (iBufferCopyListener->IsActive()) + { + iBufferCopyListener->Cancel(); + + //Do copy now + *iBuffer = iSource->Mid(iPosition, iSize); + + //Signal codec subthread that the copy is complete + TRequestStatus* status = iCallerStatus; + iSubThread->RequestComplete(status, KErrNone); + } + iFunctionCallInProgress = ETrue; + iBufferCopyMutex.Signal(); + } + +/** + * Wait on buffer copy mutex while the codec thread check in which thread to + * do the buffer copy and cancel the function call state. + * The thread will do buffer copies in the main thread, using the buffer copy + * listener after this call. + * + */ +void CSubThreadDecoderRelay::ResetFunctionInProgress() + { + iBufferCopyMutex.Wait(); + iFunctionCallInProgress = EFalse; + iBufferCopyMutex.Signal(); + } + +/** + * Run a function in the decoder thread. + * + * @param "TInt aFunctionCode" + * The function to execute. + * @param "TAny* aParameters" + * Parameters to the function. + * @leave "KErrArgument" + * Invalid function requested. + */ +void CSubThreadDecoderRelay::RunFunctionL(TInt aFunctionCode, TAny* aParameters) + { + + union + { + TAny* iFunctionParams; + TDecodeSetFileParams* iSetFile; + TDecodeSetFileHandleParams* iSetFileHandle; + TDecodeSetDataParams* iSetData; + TDecodeConvertParams* iConvert; + TCustomSyncParams* iCustomSync; + TGetExtensionParams* iGetExtension; + TExecuteCommandParamsBase* iExecuteCommandBase; + TExecuteCommandParamsAsyncBase* iExecuteCommandAsyncBase; + } functionParams; + + functionParams.iFunctionParams = aParameters; + + switch(aFunctionCode) + { + case EFunctionSetFile: + { + ASSERT(functionParams.iFunctionParams != NULL); + SetFileL(*functionParams.iSetFile->iSourceFilename, + functionParams.iSetFile->iOptions); + break; + } + + case EFunctionSetData: + { + ASSERT(functionParams.iFunctionParams != NULL); + SetDataL(*functionParams.iSetData->iSourceData, + functionParams.iSetData->iOptions); + break; + } + + case EFunctionContinueHeader: + { + ContinueProcessingHeaderL(); + break; + } + + case EFunctionConvert: + { + ASSERT(functionParams.iFunctionParams != NULL); + Convert(functionParams.iConvert->iRequestStatus, + functionParams.iConvert->iDestinationHandle, + functionParams.iConvert->iFrameNumber); + break; + } + + case EFunctionConvertMask: + { + ASSERT(functionParams.iFunctionParams != NULL); + Convert(functionParams.iConvert->iRequestStatus, + functionParams.iConvert->iDestinationHandle, + functionParams.iConvert->iDestinationMaskHandle, + functionParams.iConvert->iFrameNumber); + break; + } + + case EFunctionContinueConvert: + { + ASSERT(functionParams.iFunctionParams != NULL); + ContinueConvert(functionParams.iConvert->iRequestStatus); + break; + } + + case EFunctionHandleNewImage: + { + HandleNewlyOpenedImageL(); + break; + } + + case EFunctionCustomSync: + { + ASSERT(functionParams.iFunctionParams != NULL); + CustomSyncL(functionParams.iCustomSync->iParam); + break; + } + + case EFunctionCustomAsync: + { + ASSERT(functionParams.iFunctionParams != NULL); + CustomAsync(functionParams.iCustomSync->iRequestStatus, + functionParams.iCustomSync->iParam); + break; + } + + case EFunctionCancel: + { + CancelBody(); + break; + } + case EFunctionSetFileHandle: + { + ASSERT(functionParams.iFunctionParams != NULL); + SetFileL(*functionParams.iSetFileHandle->iFile, + functionParams.iSetFileHandle->iOptions); + break; + } + case EFunctionGetExtension: + { + ASSERT(functionParams.iFunctionParams != NULL); + GetExtensionL(functionParams.iGetExtension->iUid, + *functionParams.iGetExtension->iExtension); + break; + } + case EFunctionExecuteCommandL: + { + ASSERT(functionParams.iFunctionParams != NULL); + HandleExecuteCommandL(*functionParams.iExecuteCommandBase); + break; + } + case EFunctionExecuteAsyncCommand: + { + ASSERT(functionParams.iFunctionParams != NULL); + HandleExecuteAsyncCommand(*functionParams.iExecuteCommandAsyncBase); + break; + } + + default: + { + User::Leave(KErrArgument); + } + } + } + +/** + * Always use a buffer for copies in thread. + * + */ +TBool CSubThreadDecoderRelay::MustUseBufferWithDescriptor() const + { + return ETrue; + } + +/** + * Do a buffer copy. If the main thread is busy with a function call to this + * thread, do a local copy, else request a copy from the buffer copy listener + * in the main thread. The call will wait on the buffer copy mutex if the main thread + * is busy to change the state to a function call in progress. + * + * @param "TDes8& aBuffer" + * The destination buffer for the copy. + * @param "const TDesC8& aSource" + * The source descriptor for the copy. + * @param "TInt aPosition" + * Position to start copy. + * @param "TInt aSize" + * Number of elements to copy. + */ +void CSubThreadDecoderRelay::CopyBufferToDescriptor(TDes8& aBuffer, const TDesC8& aSource, TInt aPosition, TInt aSize) + { + //Note: assumes that this executes in the codec subthread. + ASSERT(RThread().Id() == iSubThread->Id()); + + //Wait for iFunctionCallInProgress change to complete with + //SetFunctionInProgress() or ResetFunctionInProgress() + iBufferCopyMutex.Wait(); + if(iFunctionCallInProgress) + {//Do copy in this thread + //We do not need to keep the mutex if copy is done locally + iBufferCopyMutex.Signal(); + //Do a local copy + aBuffer = aSource.Mid(aPosition, aSize); + } + else + { + //Do a copy in the main thread + ASSERT(iBufferCopyListener != NULL); + TRequestStatus status = KRequestPending; + + //Prime AO in the main thread to do a buffer copy + iBufferCopyListener->CopyBufferToDescriptor(status, aBuffer, aSource, aPosition, aSize); + + //Remember parameters in case we need to bypass the copy in main thread's AO + iCallerStatus = &status; + iBuffer = &aBuffer; + iSource = &aSource; + iPosition = aPosition; + iSize = aSize; + + // Force main thread AO to be eligible for RunL() next time control is returned to it's AS + TRequestStatus *bufferCopyStatus = &iBufferCopyListener->iStatus; + iMainThread.RequestComplete(bufferCopyStatus, KErrNone); + + //If a function call is made (in the main thread) before the CBufferCopyListener AO completes + //then, SetFunctionInProgress() waits for this signal in the main thread because we don't + //want to run a function while a buffer copy is in progess. + // + //We MUST now release the mutex BEFORE we suspend (this codec subthread) to allow the buffer copy + //to progress in the main thread - either via CBufferCopyListener AO or in SetFunctionInProgress(). + iBufferCopyMutex.Signal(); + + //Wait until main thread signals that buffer copy is complete + User::WaitForRequest(status); + } + } + +/** + * @return "TBool" + * Always ETrue since we are in a thread. + */ +TBool CSubThreadDecoderRelay::AmInThread() const + { + return ETrue; + } + +/** + * Inform the decoder to cancel decoding if it does not use + * ActiveObject functionallity. The decoder should constantly + * check ShouldAbort() and cancel decoding as quickly possible + * if the flag is set. + * + */ +void CSubThreadDecoderRelay::AbortDecode() + { + iAbortDecode = ETrue; + } + +/** + * Cancel the decoding operation if one is in progress + * + */ +void CSubThreadDecoderRelay::CancelBody() + { + if(iBody) + iBody->Cancel(); + } + +/** + * Indicate to the plugin that the client requested a decode to terminate. + * + * @return "TBool" + * ETrue if the plugin must terminate the decode process. + */ +TBool CSubThreadDecoderRelay::ShouldAbort() const + { + return iAbortDecode; + } + +void CSubThreadDecoderRelay::Lock() + { + iFrameTableMutex.Wait(); + } + +void CSubThreadDecoderRelay::Unlock() + { + iFrameTableMutex.Signal(); + } + +TInt CSubThreadDecoderRelay::FrameCount() const + { + return iFrameCount; + } + +void CSubThreadDecoderRelay::SaveFrameCount(TInt aFrameCount) + { + iFrameCount = aFrameCount; + } +/** + * Run CImageDecoderPriv::SetFileL() in the decoder thread, + * using the thread's local file server session. + * + */ +void CSubThreadDecoderRelay::SetFileL(const TDesC& aSourceFilename, const CImageDecoder::TOptions aOptions) + { + //Use sub thread RFs + iBody->SetFileL(iFileSession, aSourceFilename, aOptions); + } +void CSubThreadDecoderRelay::SetFileL(RFile& aFile, const CImageDecoder::TOptions aOptions) + { + iBody->SetFileL(aFile, aOptions); + } + +/** + * Run CImageDecoderPriv::SetDataL() in the decoder thread, + * using the thread's local file server session. + * + */ +void CSubThreadDecoderRelay::SetDataL(const TDesC8& aSourceData, const CImageDecoder::TOptions aOptions) + { + //Use sub thread RFs + iBody->SetDataL(iFileSession, aSourceData, aOptions); + } + +/** + * Run CImageDecoderPriv::Convert() in the decoder thread, + * duplicating the client's image bitmap. + * + */ +void CSubThreadDecoderRelay::Convert(TRequestStatus* aRequestStatus, TInt aDestinationHandle, TInt aFrameNumber) + { + iAbortDecode = EFalse; + + //Create a bitmap in the sub thread + delete iDestination; iDestination = NULL; + iDestination = new CFbsBitmap; + if(iDestination == NULL) + { + iMainThread.RequestComplete(aRequestStatus, KErrNoMemory); + return; + } + + //Duplicate the client bitmap + TInt error = iDestination->Duplicate(aDestinationHandle); + if(error != KErrNone) + { + iMainThread.RequestComplete(aRequestStatus, error); + return; + } + + iBody->Convert(iMainThread, aRequestStatus, *iDestination, aFrameNumber); + + } + +/** + * Run CImageDecoderPriv::Convert() in the decoder thread, + * duplicating the client's image and mask bitmap. + * + */ +void CSubThreadDecoderRelay::Convert(TRequestStatus* aRequestStatus, TInt aDestinationHandle, TInt aDestinationMaskHandle, TInt aFrameNumber) + { + iAbortDecode = EFalse; + + //Create a bitmap in the sub thread + delete iDestination; iDestination = NULL; + iDestination = new CFbsBitmap; + if(iDestination == NULL) + { + iMainThread.RequestComplete(aRequestStatus, KErrNoMemory); + return; + } + + //Duplicate the client bitmap + TInt error = iDestination->Duplicate(aDestinationHandle); + if(error != KErrNone) + { + iMainThread.RequestComplete(aRequestStatus, error); + return; + } + + //Create a mask bitmap in the sub thread + delete iDestinationMask; iDestinationMask = NULL; + iDestinationMask = new CFbsBitmap; + if(iDestinationMask == NULL) + { + iMainThread.RequestComplete(aRequestStatus, KErrNoMemory); + return; + } + + //Duplicate the mask client bitmap + error = iDestinationMask->Duplicate(aDestinationMaskHandle); + if(error != KErrNone) + { + iMainThread.RequestComplete(aRequestStatus, error); + return; + } + + iBody->Convert(iMainThread, aRequestStatus, *iDestination, *iDestinationMask, aFrameNumber); + } + +void CSubThreadDecoderRelay::ContinueConvert(TRequestStatus* aRequestStatus) + { + iAbortDecode = EFalse; + iBody->ContinueConvert(iMainThread, aRequestStatus); + } + +void CSubThreadDecoderRelay::HandleNewlyOpenedImageL() + { + iBody->HandleNewlyOpenedImageL(); + } + +void CSubThreadDecoderRelay::ContinueProcessingHeaderL() + { + iBody->ContinueProcessingHeaderL(); + } + +void CSubThreadDecoderRelay::CustomSyncL(TInt aParam) + { + iBody->CustomSyncL(aParam); + } + +void CSubThreadDecoderRelay::CustomAsync(TRequestStatus* aRequestStatus, TInt aParam) + { + iBody->CustomAsync(iMainThread, aRequestStatus, aParam); + } + +void CSubThreadDecoderRelay::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr) + { + // Get the actual extension + iBody->GetExtensionL(aExtUid, aExtPtr); + CImageConvStubBase* stub = NULL; + TRAPD(err, stub = ProxyStubUtility::NewStubL(aExtUid, aExtPtr, iBody, iMainThread)); + if(err != KErrNone) + { + delete stub; + aExtPtr->Release(); + aExtPtr = NULL; + User::Leave(err); + } + CleanupStack::PushL(stub); + iStubs.AppendL(stub); + CleanupStack::Pop(stub); + aExtPtr = NULL; + } + +void CSubThreadDecoderRelay::HandleExecuteCommandL(TExecuteCommandParamsBase& aExecuteCommandBase) + { + for(TInt i = 0; i < iStubs.Count(); i++) + { + if((iStubs[i])->Uid() == aExecuteCommandBase.iUid) + { + (iStubs[i])->HandleExecuteCommandL(aExecuteCommandBase); + return; + } + } + ASSERT(EFalse); + } + +void CSubThreadDecoderRelay::HandleExecuteAsyncCommand(TExecuteCommandParamsAsyncBase& aExecuteCommandBase) + { + for(TInt i = 0; i < iStubs.Count(); i++) + { + if((iStubs[i])->Uid() == aExecuteCommandBase.iUid) + { + (iStubs[i])->HandleExecuteAsyncCommand(aExecuteCommandBase); + return; + } + } + ASSERT(EFalse); + } + +// +//CSubThreadEncoderRelay +// +CSubThreadRelay* CSubThreadEncoderRelay::NewL(TThreadId aMainThreadId, TAny* aEncoderParam) + { + CSubThreadEncoderRelay* self; + TThreadEncoderRelayParam* encoderParam; + + encoderParam = STATIC_CAST(TThreadEncoderRelayParam*, aEncoderParam); + + self = new (ELeave) CSubThreadEncoderRelay(); + CleanupStack::PushL(self); + self->ConstructL(aMainThreadId, encoderParam->iConstruct); + + CleanupStack::Pop(self); + return self; + + } + +CSubThreadEncoderRelay::CSubThreadEncoderRelay() + { + } + +void CSubThreadEncoderRelay::ConstructL(TThreadId aMainThreadId, CImageEncodeConstruct* aConstruct) + { + CSubThreadRelay::ConstructL(aMainThreadId); + + //Open a file server session + User::LeaveIfError(iFileSession.Connect()); + //Make the session shareable for all threads +#ifdef __IPC_V2_PRESENT__ + User::LeaveIfError(iFileSession.ShareAuto()); +#else + User::LeaveIfError(iFileSession.Share(RSessionBase::EAutoAttach)); +#endif + iBody = CImageEncoderPriv::NewL(aConstruct, this); + iBody->CreatePluginL(); + } + +/** + * Inform the encoder to cancel encoding if it does not use + * ActiveObject functionallity. The encoder should constantly + * check ShouldAbort() and cancel encoding as quickly possible + * if the flag is set. + * + */ +void CSubThreadEncoderRelay::AbortEncode() + { + iAbortEncode = ETrue; + } + +void CSubThreadEncoderRelay::CancelBody() + { + if(iBody) + iBody->Cancel(); + } + +CSubThreadEncoderRelay::~CSubThreadEncoderRelay() + { + iStubs.ResetAndDestroy(); + if(iBody) + { + CancelBody(); + delete iBody; + } + delete iSource; + iFileSession.Close(); + } + +TBool CSubThreadEncoderRelay::AmInThread() const + { + return ETrue; + } + +TBool CSubThreadEncoderRelay::ShouldAbort() const + { + return iAbortEncode; + } + +void CSubThreadEncoderRelay::RunFunctionL(TInt aFunctionCode, TAny* aParameters) + { + union + { + TAny* iFunctionParams; + TEncodeSetFileParams* iSetFile; + TEncodeSetFileHandleParams* iSetFileHandle; + TEncodeSetDataParams* iSetData; + TEncodeConvertParams* iConvert; + TCustomSyncParams* iCustomSync; + TGetExtensionParams* iGetExtension; + TExecuteCommandParamsBase* iExecuteCommandBase; + TExecuteCommandParamsAsyncBase* iExecuteCommandAsyncBase; + } functionParams; + + functionParams.iFunctionParams = aParameters; + + switch(aFunctionCode) + { + case EFunctionSetFile: + { + ASSERT(functionParams.iFunctionParams != NULL); + SetFileL(*functionParams.iSetFile->iDestinationFilename, + functionParams.iSetFile->iOptions); + break; + } + + case EFunctionSetData: + { + ASSERT(functionParams.iFunctionParams != NULL); + SetDataL(*functionParams.iSetData->iDestinationData, + functionParams.iSetData->iOptions); + break; + } + + case EFunctionConvert: + { + ASSERT(functionParams.iFunctionParams != NULL); + Convert(functionParams.iConvert->iRequestStatus, + functionParams.iConvert->iSourceHandle, + functionParams.iConvert->iFrameImageData); + break; + } + + case EFunctionCustomSync: + { + ASSERT(functionParams.iFunctionParams != NULL); + CustomSyncL(functionParams.iCustomSync->iParam); + break; + } + + case EFunctionCustomAsync: + { + ASSERT(functionParams.iFunctionParams != NULL); + CustomAsync(functionParams.iCustomSync->iRequestStatus, + functionParams.iCustomSync->iParam); + break; + } + + case EFunctionCancel: + { + CancelBody(); + break; + } + case EFunctionSetFileHandle: + { + ASSERT(functionParams.iFunctionParams != NULL); + SetFileL(*functionParams.iSetFileHandle->iFile, + functionParams.iSetFile->iOptions); + break; + } + case EFunctionGetExtension: + { + ASSERT(functionParams.iFunctionParams != NULL); + GetExtensionL(functionParams.iGetExtension->iUid, + *functionParams.iGetExtension->iExtension); + break; + } + case EFunctionExecuteCommandL: + { + ASSERT(functionParams.iFunctionParams != NULL); + HandleExecuteCommandL(*functionParams.iExecuteCommandBase); + break; + } + case EFunctionExecuteAsyncCommand: + { + ASSERT(functionParams.iFunctionParams != NULL); + HandleExecuteAsyncCommand(*functionParams.iExecuteCommandAsyncBase); + break; + } + default: + { + User::Leave(KErrArgument); + } + } + } + +void CSubThreadEncoderRelay::SetFileL(const TDesC& aDestinationFilename, const CImageEncoder::TOptions aOptions) + { + //Use sub thread RFs + iBody->SetFileL(iFileSession, aDestinationFilename, aOptions); + } + +void CSubThreadEncoderRelay::SetFileL(RFile& aFile, const CImageEncoder::TOptions aOptions) + { + iBody->SetFileL(aFile, aOptions); + } + +void CSubThreadEncoderRelay::SetDataL(HBufC8*& aDestinationData, const CImageEncoder::TOptions aOptions) + { + iBody->SetDataL(aDestinationData, aOptions); + } + +void CSubThreadEncoderRelay::Convert(TRequestStatus* aRequestStatus, TInt aSourceHandle, const CFrameImageData* aFrameImageData) + { + TInt error = KErrNone; + + iAbortEncode = EFalse; + + //Create a bitmap in the sub thread + delete iSource; iSource = NULL; + TRAP(error,iSource = new (ELeave) CFbsBitmap); + if(error != KErrNone) + { + iMainThread.RequestComplete(aRequestStatus, error); + return; + } + + //Duplicate the client bitmap + error = iSource->Duplicate(aSourceHandle); + if(error != KErrNone) + { + iMainThread.RequestComplete(aRequestStatus, error); + return; + } + + iBody->Convert(iMainThread, aRequestStatus, *iSource, aFrameImageData); + } + +void CSubThreadEncoderRelay::CustomSyncL(TInt aParam) + { + iBody->CustomSyncL(aParam); + } + +void CSubThreadEncoderRelay::CustomAsync(TRequestStatus* aRequestStatus, TInt aParam) + { + iBody->CustomAsync(iMainThread, aRequestStatus, aParam); + } + +void CSubThreadEncoderRelay::GetExtensionL(TUid aExtUid, MImageConvExtension*& aExtPtr) + { + // Get the actual extension + iBody->GetExtensionL(aExtUid, aExtPtr); + CImageConvStubBase* stub = NULL; + TRAPD(err, stub = ProxyStubUtility::NewStubL(aExtUid, aExtPtr, iBody, iMainThread)); + if(err != KErrNone) + { + delete stub; + aExtPtr->Release(); + aExtPtr = NULL; + User::Leave(err); + } + CleanupStack::PushL(stub); + iStubs.AppendL(stub); + CleanupStack::Pop(stub); + aExtPtr = NULL; + } + +void CSubThreadEncoderRelay::HandleExecuteCommandL(TExecuteCommandParamsBase& aExecuteCommandBase) + { + for(TInt i = 0; i < iStubs.Count(); i++) + { + if((iStubs[i])->Uid() == aExecuteCommandBase.iUid) + { + (iStubs[i])->HandleExecuteCommandL(aExecuteCommandBase); + return; + } + } + ASSERT(EFalse); + } + +void CSubThreadEncoderRelay::HandleExecuteAsyncCommand(TExecuteCommandParamsAsyncBase& aExecuteCommandBase) + { + for(TInt i = 0; i < iStubs.Count(); i++) + { + if((iStubs[i])->Uid() == aExecuteCommandBase.iUid) + { + (iStubs[i])->HandleExecuteAsyncCommand(aExecuteCommandBase); + return; + } + } + ASSERT(EFalse); + } + +