// 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:
// omxilgenericifilbodyimpl.cpp
//
//
#include "omxilgenericilifbodyimpl.h"
#include "omxilcoreutils.h"
#include <e32base.h>
#include <e32msgqueue.h>
#include <mmf/server/mmfdatabuffer.h>
const TInt KMaxMsgQueueEntries = 10;
COmxBufferManager::COmxBufferManager(OMX_COMPONENTTYPE* aHandle)
: iHandle(aHandle)
{
}
COmxBufferManager::COmxBuffer::COmxBuffer()
{
}
COmxBufferManager::COmxBuffer* COmxBufferManager::COmxBuffer::NewL(OMX_BUFFERHEADERTYPE* aBufferHeader,
CMMFBuffer* aBuffer)
{
COmxBuffer* self = new (ELeave) COmxBuffer;
CleanupStack::PushL(self);
self->ConstructL(aBufferHeader, aBuffer);
CleanupStack::Pop(self);
return self;
}
COmxBufferManager::COmxBuffer::~COmxBuffer()
{
if (iOwnsMmfBuffer)
{
delete iMmfBuffer;
}
}
CMMFBuffer* COmxBufferManager::COmxBuffer::MmfBuffer() const
{
return iMmfBuffer;
}
OMX_BUFFERHEADERTYPE* COmxBufferManager::COmxBuffer::BufferHeader() const
{
return iBufferHeader;
}
void COmxBufferManager::COmxBuffer::SetPortObserver(MOmxILComponentIfObserver* aObserver)
{
iPortObserver = aObserver;
}
MOmxILComponentIfObserver* COmxBufferManager::COmxBuffer::PortObserver() const
{
return iPortObserver;
}
COmxBufferManager::COmxBuffer* COmxBufferManager::FindBuffer(const CMMFBuffer* aBuffer) const
{
COmxBuffer* buffer = NULL;
for (TInt i=0;i<iBuffers.Count() && !buffer;i++)
{
if (iBuffers[i]->MmfBuffer() == aBuffer)
{
buffer = iBuffers[i];
}
}
return buffer;
}
COmxBufferManager::COmxBuffer* COmxBufferManager::FindBuffer(OMX_BUFFERHEADERTYPE* aBuffer) const
{
return reinterpret_cast<COmxBuffer*>(aBuffer->pAppPrivate);
}
TInt COmxBufferManager::UseBuffer(CMMFBuffer& aBuffer, TUint aPortIndex)
{
if (CMMFBuffer::IsSupportedDataBuffer(aBuffer.Type()))
{
OMX_BUFFERHEADERTYPE* buffer;
CMMFDataBuffer& dataBuffer = static_cast<CMMFDataBuffer&>(aBuffer);
TDes8& aBufferDes = dataBuffer.Data();
OMX_ERRORTYPE error = iHandle->UseBuffer(static_cast<OMX_HANDLETYPE>(iHandle), &buffer, aPortIndex, (void*)&aBuffer, aBufferDes.MaxLength(), const_cast<TUint8*>(aBufferDes.Ptr()));
if (error != OMX_ErrorNone)
{
return ConvertOmxErrorType(error);
}
TRAPD(err, StoreBufferL(buffer, &aBuffer));
return err;
}
else
{
return KErrNotSupported;
}
}
CMMFBuffer* COmxBufferManager::AllocateBufferL(TUint aPortIndex,
TUint aSizeBytes)
{
OMX_BUFFERHEADERTYPE* buffer;
OMX_ERRORTYPE error = iHandle->AllocateBuffer(static_cast<OMX_HANDLETYPE>(iHandle), &buffer, aPortIndex, NULL, aSizeBytes);
User::LeaveIfError(ConvertOmxErrorType(error));
StoreBufferL(buffer,NULL); // transfers ownership
return FindBuffer(buffer)->MmfBuffer();
}
TInt COmxBufferManager::FreeBuffer(CMMFBuffer* aBuffer)
{
COmxBuffer* buffer;
for (TInt i=0;i<iBuffers.Count();i++)
{
buffer = iBuffers[i];
if (buffer->MmfBuffer() == aBuffer)
{
iBuffers.Remove(i);
OMX_ERRORTYPE err = iHandle->FreeBuffer(static_cast<OMX_HANDLETYPE>(iHandle), 0, buffer->BufferHeader());
delete buffer;
return err;
}
}
return KErrNotFound;
}
void COmxBufferManager::COmxBuffer::ConstructL(OMX_BUFFERHEADERTYPE* aBufferHeader,
CMMFBuffer* aBuffer)
{
// Now if CMMFBuffer is NULL, this is been called from allocate buffer, and we need to
// Allocate a ptr buffer to correspond to the buffer created by OMX
ASSERT(aBufferHeader);
iBufferHeader = aBufferHeader;
if (aBuffer == NULL)
{
TPtr8 ptr(iBufferHeader->pBuffer, iBufferHeader->nFilledLen, iBufferHeader->nAllocLen);
CMMFBuffer* mmfBuffer = CMMFPtrBuffer::NewL(ptr);
iMmfBuffer = mmfBuffer;
iOwnsMmfBuffer = ETrue;
}
else
{
iMmfBuffer = aBuffer;
}
// store pointer to element in array
iBufferHeader->pAppPrivate = this;
}
void COmxBufferManager::StoreBufferL(OMX_BUFFERHEADERTYPE* aBufferHeader,
CMMFBuffer* aBuffer)
{
COmxBuffer* buf = COmxBuffer::NewL(aBufferHeader, aBuffer);
CleanupStack::PushL(buf);
iBuffers.AppendL(buf);
CleanupStack::Pop(buf);
}
TInt COmxBufferManager::EmptyThisBuffer(const CMMFBuffer* aBuffer,
MOmxILComponentIfObserver* aObserver)
{
if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
{
COmxBuffer* omxBuffer = FindBuffer(aBuffer);
if (!omxBuffer)
{
return KErrNotFound;
}
omxBuffer->SetPortObserver(aObserver);
OMX_BUFFERHEADERTYPE* bufferHeader = omxBuffer->BufferHeader();
const CMMFDataBuffer* buf = static_cast<const CMMFDataBuffer*>(aBuffer);
const TDesC8& des = buf->Data();
bufferHeader->nFilledLen = des.Length();
bufferHeader->nFlags = 0;
if (aBuffer->LastBuffer())
{
bufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
}
else
{
bufferHeader->nFlags &= ~OMX_BUFFERFLAG_EOS;
}
return ConvertOmxErrorType(iHandle->EmptyThisBuffer(static_cast<OMX_HANDLETYPE>(iHandle), bufferHeader));
}
else
{
return KErrNotSupported;
}
}
TInt COmxBufferManager::FillThisBuffer(CMMFBuffer* aBuffer,
MOmxILComponentIfObserver* aObserver)
{
if (CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type()))
{
COmxBuffer* omxBuffer = FindBuffer(aBuffer);
if (!omxBuffer)
{
return KErrNotFound;
}
omxBuffer->SetPortObserver(aObserver);
OMX_BUFFERHEADERTYPE* bufferHeader = omxBuffer->BufferHeader();
bufferHeader->nFilledLen = 0;
// clear last buffer flag
bufferHeader->nFlags &= ~OMX_BUFFERFLAG_EOS;
return ConvertOmxErrorType(iHandle->FillThisBuffer(static_cast<OMX_HANDLETYPE>(iHandle), bufferHeader));
}
else
{
return KErrNotSupported;
}
}
COmxBufferManager::~COmxBufferManager()
{
for (TInt i=0;i<iBuffers.Count();i++)
{
COmxBuffer* omxBuffer = iBuffers[i];
iHandle->FreeBuffer(static_cast<OMX_HANDLETYPE>(iHandle), 0, omxBuffer->BufferHeader());
delete omxBuffer;
}
iBuffers.Close();
}
COmxCallbacks* COmxCallbacks::NewL(MOmxILComponentIfObserver& aObserver)
{
COmxCallbacks* self = new (ELeave) COmxCallbacks(aObserver);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void COmxCallbacks::ConstructL()
{
OMX_CALLBACKTYPE h =
{
&::EventHandler,
&::EmptyBufferDone,
&::FillBufferDone
};
iHandle = h;
CActiveScheduler::Add(this);
User::LeaveIfError(iMsgQueue.CreateLocal(KMaxMsgQueueEntries));
iMsgQueue.NotifyDataAvailable(iStatus);
SetActive();
}
COmxCallbacks::COmxCallbacks(MOmxILComponentIfObserver& aObserver)
: CActive(EPriorityStandard),
iParent(aObserver)
{
}
COmxCallbacks::operator OMX_CALLBACKTYPE*()
{
return &iHandle;
}
void COmxCallbacks::RunL()
{
TOmxMessage msg;
while (iMsgQueue.Receive(msg)==KErrNone)
{
switch (msg.iType)
{
case EEmptyBufferCallback:
{
MOmxILComponentIfObserver* callback = msg.iBuffer->PortObserver();
const CMMFBuffer* buffer = msg.iBuffer->MmfBuffer();
OMX_BUFFERHEADERTYPE* bufferHeader = msg.iBuffer->BufferHeader();
TInt portIndex = static_cast<TInt>(bufferHeader->nInputPortIndex);
User::LeaveIfError(callback->EmptyBufferDone(buffer, portIndex));
break;
}
case EFillBufferCallback:
{
CMMFBuffer* mmfBuffer = msg.iBuffer->MmfBuffer();
OMX_BUFFERHEADERTYPE* bufferHeader = msg.iBuffer->BufferHeader();
if (CMMFBuffer::IsSupportedDataBuffer(mmfBuffer->Type()))
{
CMMFDataBuffer* dataBuffer = static_cast<CMMFDataBuffer*>(mmfBuffer);
TDes8& aBufferDes = dataBuffer->Data();
aBufferDes.SetLength(bufferHeader->nFilledLen);
mmfBuffer->SetLastBuffer(bufferHeader->nFlags & OMX_BUFFERFLAG_EOS);
}
else
{
ASSERT(EFalse);
}
MOmxILComponentIfObserver* callback = msg.iBuffer->PortObserver();
bufferHeader = msg.iBuffer->BufferHeader();
TInt portIndex = static_cast<TInt>(bufferHeader->nOutputPortIndex);
User::LeaveIfError(callback->FillBufferDone(mmfBuffer, portIndex));
break;
}
case EEventCallback:
{
TInt err = KErrNone;
err = iParent.EventHandler(msg.iEventParams.iEvent,
msg.iEventParams.iData1,
msg.iEventParams.iData2,
msg.iEventParams.iExtraData);
if (err != KErrNone)
{
// Very possible the event is not supported by the IL Client.
// Ignore for now
// ASSERT(EFalse); // Uncomment this line if interested in catching this case on debug mode.
}
break;
}
default:
{
// This is an invalid state
ASSERT(EFalse);
}
};
}
// setup for next callbacks
iStatus = KRequestPending;
iMsgQueue.NotifyDataAvailable(iStatus);
SetActive();
}
COmxCallbacks::~COmxCallbacks()
{
Cancel();
iMsgQueue.Close();
}
void COmxCallbacks::DoCancel()
{
if (iMsgQueue.Handle()!=NULL)
{
iMsgQueue.CancelDataAvailable();
}
}
TInt COmxCallbacks::FillBufferDone(OMX_HANDLETYPE aComponent,
COmxBufferManager::COmxBuffer* aBuffer)
{
TOmxMessage message;
message.iType = EFillBufferCallback;
message.iComponent = aComponent;
message.iBuffer = aBuffer;
return iMsgQueue.Send(message);
}
TInt COmxCallbacks::EmptyBufferDone(OMX_HANDLETYPE aComponent,
COmxBufferManager::COmxBuffer* aBuffer)
{
TOmxMessage message;
message.iType = EEmptyBufferCallback;
message.iComponent = aComponent;
message.iBuffer = aBuffer;
return iMsgQueue.Send(message);
}
TInt COmxCallbacks::EventHandler(OMX_HANDLETYPE aComponent,
const TEventParams& aEventParams)
{
TOmxMessage message;
message.iType = EEventCallback;
message.iComponent = aComponent;
message.iEventParams = aEventParams;
return iMsgQueue.Send(message);
}
OMX_ERRORTYPE EventHandler(OMX_OUT OMX_HANDLETYPE aComponent,
OMX_OUT TAny* aAppData,
OMX_OUT OMX_EVENTTYPE aEvent,
OMX_OUT TUint32 aData1,
OMX_OUT TUint32 aData2,
OMX_OUT TAny* aExtra)
{
COmxCallbacks::TEventParams eventParams;
eventParams.iEvent = aEvent;
eventParams.iData1 = aData1;
eventParams.iData2 = aData2;
eventParams.iExtraData = aExtra;
TInt error = static_cast<COmxCallbacks*>(aAppData)->EventHandler(aComponent, eventParams);
return ConvertSymbianErrorType(error);
}
OMX_ERRORTYPE EmptyBufferDone(OMX_HANDLETYPE aComponent,
TAny* aAppData,
OMX_BUFFERHEADERTYPE* aBuffer)
{
COmxBufferManager::COmxBuffer* buffer = static_cast<COmxBufferManager::COmxBuffer*>(aBuffer->pAppPrivate);
TInt error = static_cast<COmxCallbacks*>(aAppData)->EmptyBufferDone(aComponent, buffer);
return ConvertSymbianErrorType(error);
}
OMX_ERRORTYPE FillBufferDone(OMX_HANDLETYPE aComponent,
TAny* aAppData,
OMX_BUFFERHEADERTYPE* aBuffer)
{
COmxBufferManager::COmxBuffer* buffer = static_cast<COmxBufferManager::COmxBuffer*>(aBuffer->pAppPrivate);
TInt error = static_cast<COmxCallbacks*>(aAppData)->FillBufferDone(aComponent, buffer);
return ConvertSymbianErrorType(error);
}