tsrc/xmltestharness/xmlclient/src/portbufferhandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 25 Aug 2010 12:40:50 +0300
changeset 0 0e4a32b9112d
permissions -rw-r--r--
Revision: 201033

// 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:
//


#include "portbufferhandler.h"
#include "log.h"  // currently needed for INFO_PRINTF etc macros

/**
 * Overflow handler to generate a warning message if a log line will not fit
 * in the descriptor.
 */
class TOverflowHandler : public TDes16Overflow
    {
public:
    void Overflow(TDes& aDes)
        {
        _LIT(KWarning, "[truncated]");
        if(aDes.Length() + KWarning().Length() > aDes.MaxLength())
            {
            aDes.SetLength(aDes.Length() - KWarning().Length());
            }
        aDes.Append(KWarning);
        }
    };

CPortBufferHandler::CPortBufferHandler()
	{
	}

CPortBufferHandler::~CPortBufferHandler()
	{
	}

void CPortBufferHandler::AddPortL(OMX_COMPONENTTYPE* aComp,
								TInt aPortNum,
								const TDesC& aFileName,
								OMX_BUFFERSUPPLIERTYPE aSupplier,
								OMX_DIRTYPE aPortDir,
								MOmxScriptTestLogger& aLogger,
								TInt aHeaderLength)
	{
		
	CComponentInfo* compInfo = NULL;
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		compInfo = iComponents[pos];
		}
	else
		{
		compInfo = new (ELeave) CComponentInfo(aComp);
		CleanupStack::PushL(compInfo);
		iComponents.AppendL(compInfo);
		CleanupStack::Pop(compInfo);
		}
		
			
	CPortInfo* portInfo = compInfo->AddPortL(aPortNum,aFileName,aSupplier,aPortDir,aLogger,aHeaderLength);
	}

void CPortBufferHandler::AllocateBuffersL(OMX_COMPONENTTYPE* aComp)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->AllocateBuffersL();
		}
	}
	
void CPortBufferHandler::Start(OMX_COMPONENTTYPE* aComp, TInt aPortNum)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->Start(aPortNum);
		}
	}
	
void CPortBufferHandler::Resume(OMX_COMPONENTTYPE* aComp, TInt aPortNum)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->Resume(aPortNum);
		}
	}	

void CPortBufferHandler::BufferDone(OMX_COMPONENTTYPE* aComp, OMX_BUFFERHEADERTYPE* aBufHdr, TBool aSource)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->BufferDone(aBufHdr, aSource);
		}
	}

void CPortBufferHandler::Stop(OMX_COMPONENTTYPE* aComp, TInt aPortNum)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->Stop(aPortNum);
		}
	}
	

void CPortBufferHandler::Pause(OMX_COMPONENTTYPE* aComp, TInt aPortNum)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->Pause(aPortNum);
		}
	}	

void CPortBufferHandler::FreeBuffers(OMX_COMPONENTTYPE* aComp)
	{
	TInt pos = iComponents.Find(*aComp, CComponentInfo::CompareComp);
	if (pos >= 0)
		{
		iComponents[pos]->FreeBuffers();
		}
	}

CPortBufferHandler::CComponentInfo::CComponentInfo(OMX_COMPONENTTYPE* aComp) :
 iComp(aComp),iState(OMX_StateLoaded)
	{
	}

CPortBufferHandler::CComponentInfo::~CComponentInfo()
	{
	iPorts.ResetAndDestroy();
	}

CPortBufferHandler::CPortInfo* CPortBufferHandler::CComponentInfo::AddPortL(TInt aPortNum, const TDesC& aFileName,OMX_BUFFERSUPPLIERTYPE aSupplier, OMX_DIRTYPE aPortDir, MOmxScriptTestLogger& aLogger, TInt aHeaderLength)
	{
	__ASSERT_ALWAYS(iPorts.Find(aPortNum, CPortInfo::ComparePortNum) == KErrNotFound, User::Invariant());

	CPortInfo* portInfo = CPortInfo::NewL(iComp, aPortNum, aFileName, aSupplier, aPortDir, aLogger, aHeaderLength);
	CleanupStack::PushL(portInfo);
	iPorts.AppendL(portInfo);
	CleanupStack::Pop(portInfo);

	return portInfo;
	}

void CPortBufferHandler::CComponentInfo::AllocateBuffersL()
	{
	TInt numPorts = iPorts.Count();
	
	for (TInt port = 0; port < numPorts; ++port)
		{
		iPorts[port]->AllocateBuffersL();
		}
	iState = OMX_StateIdle;	
	}

void CPortBufferHandler::CComponentInfo::Start(TInt aPortNum)
	{
	TInt numPorts = iPorts.Count();
	
	if(aPortNum == -1)
		{
		for (TInt port = 0; port < numPorts; ++port)
			{
			iPorts[port]->Start();
			}
		}
	else
		{
		TInt pos = iPorts.Find(aPortNum, CPortInfo::ComparePortNum);
		iPorts[pos]->Start();
		}		
	iState = OMX_StateExecuting;
	}

void CPortBufferHandler::CComponentInfo::Resume(TInt aPortNum)
	{
	if(aPortNum == -1)
		{ 
		TInt numPorts = iPorts.Count();
		
		for (TInt port = 0; port < numPorts; ++port)
			{
			iPorts[port]->Resume();
			}
		}
	else
		{
		TInt pos = iPorts.Find(aPortNum, CPortInfo::ComparePortNum);
		iPorts[pos]->Resume();
		}	
	iState = OMX_StateExecuting;
	}

void CPortBufferHandler::CComponentInfo::BufferDone(OMX_BUFFERHEADERTYPE* aBufHdr, TBool aSource)
	{
	TInt pos = KErrNotFound;

	if (aSource)
		{
		pos = iPorts.Find(static_cast<TInt>(aBufHdr->nOutputPortIndex), CPortInfo::ComparePortNum);
		}
	else
		{
		pos = iPorts.Find(static_cast<TInt>(aBufHdr->nInputPortIndex), CPortInfo::ComparePortNum);
		}

	__ASSERT_ALWAYS(pos != KErrNotFound, User::Invariant());

	iPorts[pos]->BufferDone(aBufHdr);
	}

void CPortBufferHandler::CComponentInfo::Stop(TInt aPortNum)
	{
	if(aPortNum == -1)
		{
		for (TInt port = 0; port < iPorts.Count(); ++port)
			{
			iPorts[port]->Stop();
			}
		}
	else
		{
		TInt pos = iPorts.Find(aPortNum, CPortInfo::ComparePortNum);
		iPorts[pos]->Stop();
		}		
	iState = OMX_StateIdle;
	}

void CPortBufferHandler::CComponentInfo::Pause(TInt aPortNum)
	{
	if(aPortNum == -1)
		{	
		for (TInt port = 0; port < iPorts.Count(); ++port)
			{
			iPorts[port]->Pause();
			}
		}
	else
		{
		TInt pos = iPorts.Find(aPortNum, CPortInfo::ComparePortNum);
		iPorts[pos]->Pause();	
		}
	iState = OMX_StatePause;
	}

void CPortBufferHandler::CComponentInfo::FreeBuffers()
	{
	for (TInt port = 0; port < iPorts.Count(); ++port)
		{
		iPorts[port]->FreeBuffers();
		}
	iState = OMX_StateLoaded;	
	}

TBool CPortBufferHandler::CComponentInfo::CompareComp(const OMX_COMPONENTTYPE* aComp, const CComponentInfo& aComponentInfo)
	{
	return (aComp == aComponentInfo.iComp);
	}


CPortBufferHandler::CPortInfo::CPortInfo( OMX_COMPONENTTYPE* aComp,
		   TInt aPortNum,
		   OMX_BUFFERSUPPLIERTYPE aSupplier,
		   OMX_DIRTYPE aPortDir,
		   MOmxScriptTestLogger& aLogger,
		   TInt aHeaderLength):
	 iComp(aComp),
	 iPortNum(aPortNum),
	 iSupplier(aSupplier),
	 iPortDir(aPortDir),
	 iPosInputData(0),
	 iFileHeaderLength(0),
	 iFileFillingLength(0),
	 iLogger(aLogger),
	 iEOSReached(FALSE),
	 iTimeStamp(0)
	{
    if(aHeaderLength > -1)
        {
        iFileHeaderLength = aHeaderLength;
        }
	}

CPortBufferHandler::CPortInfo* CPortBufferHandler::CPortInfo::NewL( OMX_COMPONENTTYPE* aComp,
											TInt aPortNum,
											const TDesC& aFileName,
											OMX_BUFFERSUPPLIERTYPE aSupplier,
											OMX_DIRTYPE aPortDir,
											MOmxScriptTestLogger& aLogger,
											TInt aHeaderLength)
	{
	CPortInfo* self = new (ELeave) CPortInfo(aComp,aPortNum,aSupplier,aPortDir,aLogger,aHeaderLength);
	CleanupStack::PushL(self);
	
	self->iFileName.Copy(KPortDirectoryPath);
	self->iFileName.Append(aFileName);
	
	User::LeaveIfError(self->iFs.Connect());
	if(self->iPortDir == OMX_DirInput)
		{
		User::LeaveIfError(self->iFileObject.Open(self->iFs, self->iFileName, EFileShareExclusive|EFileRead));
		}
	else if(self->iPortDir == OMX_DirOutput)
		{
		User::LeaveIfError(self->iFileObject.Replace(self->iFs, self->iFileName, EFileWrite));
		}
	else
		{
		User::LeaveIfError(KErrNotFound);	
		}	
		
	CleanupStack::Pop(self);
	return self;
	}

CPortBufferHandler::CPortInfo::~CPortInfo()
	{
	DeleteAllBuffers();
	iFileObject.Close();
	iFs.Close();
	}

void CPortBufferHandler::CPortInfo::AllocateBuffersL()
	{
	OMX_BUFFERHEADERTYPE* bufHdr = NULL;

	if (iComp)
		{
		
		OMX_PARAM_PORTDEFINITIONTYPE portDef;
        portDef.nSize = sizeof(portDef);
        portDef.nVersion = KOmxLILVersion;
        portDef.nPortIndex = iPortNum;
        OMX_ERRORTYPE error = iComp->GetParameter(iComp, OMX_IndexParamPortDefinition, &portDef);
        if(error != OMX_ErrorNone)
            {
            User::Leave(error);
            }
        
        iNumBufs = portDef.nBufferCountActual;
        TInt bufSize = portDef.nBufferSize;
        
        if(iFileHeaderLength <=0)
            {
            iFileHeaderLength = bufSize;
            }
        
        //fix for video partial tunnelling
        //mpeg4decoder needs timestamp info in each frame.
        //Buffer size approximately adjusted to framesize and timestamps added for each buffer
        //this change is done for all video components(needed only for mpeg4decoder)
        
        if(portDef.eDomain == OMX_PortDomainVideo)
            {
			iFileFillingLength = 1600; //bufSize; 
            }
        else
            {
            iFileFillingLength = bufSize;
            }
		
		if (iSupplier == OMX_BufferSupplyInput)
			{
			for (TInt buf = 0; buf < iNumBufs; ++buf)
				{
				iComp->AllocateBuffer(iComp, &bufHdr, iPortNum, NULL, bufSize);
				bufHdr->pAppPrivate = (OMX_PTR)EBufferFree;
				iBufferHeaders.AppendL(bufHdr);
				}
			}
		else
			{
			OMX_U8* newBuffer = NULL;			
			
			for (TInt buf = 0; buf < iNumBufs; ++buf)
				{
				newBuffer = new (ELeave) OMX_U8[bufSize];
				CleanupStack::PushL(newBuffer);
				iBuffers.AppendL(newBuffer);
				CleanupStack::Pop(newBuffer);
				
				OMX_ERRORTYPE err = iComp->UseBuffer(iComp, &bufHdr, iPortNum, NULL, bufSize, newBuffer);
				if(err != OMX_ErrorNone)
					{
					//error encountered in allocating.
					}
				bufHdr->pAppPrivate = (OMX_PTR)EBufferFree;				
				iBufferHeaders.AppendL(bufHdr);
				}
			}
		}
	}

void CPortBufferHandler::CPortInfo::BufferDone(OMX_BUFFERHEADERTYPE* aBufHdr)
	{
	for (TInt buf = 0; buf < iNumBufs; ++buf)
		{
		if (iBufferHeaders[buf] == aBufHdr)
			{
			aBufHdr->pAppPrivate = (OMX_PTR)EBufferFree;
			if(iPortDir == OMX_DirInput)
				{
				TPtr8 data(aBufHdr->pBuffer,aBufHdr->nAllocLen);
				Mem::FillZ(aBufHdr->pBuffer,aBufHdr->nAllocLen);
				// Read data to this buffer.
				TInt err = iFileObject.Read(iPosInputData,data,iFileFillingLength);
				iPosInputData += iFileFillingLength;
				if(err != KErrNone)
					{
					return; //error return.
					}
                
				aBufHdr->nTimeStamp = iTimeStamp* 1000;
                iTimeStamp += 100;
                if(!iEOSReached)
					{
					aBufHdr->nFilledLen = data.Size();
					aBufHdr->nOffset = 0;
					aBufHdr->nInputPortIndex = iPortNum;
					aBufHdr->nOutputPortIndex = OMX_ErrorMax;
					
					//Send buffer to port and mark that it is under use.
					aBufHdr->pAppPrivate = (OMX_PTR)EBufferUnderUse;
					if((data.Size() < aBufHdr->nAllocLen)&&(data.Size() < iFileFillingLength))
						{
						//INFO_PRINTF1(_L("EOS detected on Input Port"));
						aBufHdr->nFlags |= OMX_BUFFERFLAG_EOS;
						iEOSReached = ETrue;
						}
					iComp->EmptyThisBuffer(iComp, aBufHdr);
					}
				}
			else
				{
				//create a pointer into buffer
				// using ptr , write buffer data to File.
				TPtr8 data( aBufHdr->pBuffer+aBufHdr->nOffset, aBufHdr->nFilledLen, aBufHdr->nAllocLen );
				TInt err = iFileObject.Write(data);
				if(err != KErrNone)
					{
					return; //error return.
					}
				err = iFileObject.Flush();	
				if(err != KErrNone)
					{
					return; //error return.
					}
				aBufHdr->pAppPrivate = (OMX_PTR)EBufferFree;
				aBufHdr->nFilledLen = 0;
				aBufHdr->nOffset = 0;
				aBufHdr->nOutputPortIndex = iPortNum;
				aBufHdr->nInputPortIndex = OMX_ErrorMax;
				if(aBufHdr->nFlags & OMX_BUFFERFLAG_EOS)
					{
					// TODO Logic for EOS
					return;
					}
				else
					{
					iComp->FillThisBuffer(iComp, aBufHdr);		
					}
				
				}
			}
		}
	}
void CPortBufferHandler::CPortInfo::Start()
	{
	for (TInt buf = 0; buf < iNumBufs; ++buf)
		{
		OMX_BUFFERHEADERTYPE *bufferHdr = iBufferHeaders[buf];
		
		if (bufferHdr->pAppPrivate == (OMX_PTR)EBufferFree)
			{
			if(iPortDir == OMX_DirInput)
				{
				TPtr8 data(bufferHdr->pBuffer,bufferHdr->nAllocLen);
				// Read data to this buffer.
				TInt err =0;
				if(buf == 0)
					{
					err = iFileObject.Read(iPosInputData,data,iFileHeaderLength);
					iPosInputData += iFileHeaderLength;
					bufferHdr->nFlags |= OMX_BUFFERFLAG_STARTTIME;
					}
				else
					{
					err = iFileObject.Read(iPosInputData,data,iFileFillingLength);
					iPosInputData += iFileFillingLength;	
					}				
				if(err != KErrNone)
					{
					return; //error return.
					}
              
				bufferHdr->nTimeStamp = iTimeStamp * 1000;
                iTimeStamp += 100;
				if(data.Size())
					{
					bufferHdr->nFilledLen = data.Size();
					bufferHdr->nOffset = 0;
					
					//Send buffer to port and mark that it is under use.
					bufferHdr->pAppPrivate = (OMX_PTR)EBufferUnderUse;
					//CHeck for EOF
					if(buf > 0)
						{
						if(data.Size() < iFileFillingLength)
							{
							bufferHdr->nFlags |= OMX_BUFFERFLAG_EOS;
							}	
						}
						
					if(buf == 0)
						{
						if(data.Size() < iFileHeaderLength)
							{
							ASSERT(0);
							return;
							}	
						}	
					
					iComp->EmptyThisBuffer(iComp, bufferHdr);
					}
				}
			else
				{
				bufferHdr->pAppPrivate = (OMX_PTR)EBufferUnderUse;
				bufferHdr->nFilledLen = 0;
				bufferHdr->nOffset = 0;
				iComp->FillThisBuffer(iComp, bufferHdr);	
				}
			}
			
		}
	}

void CPortBufferHandler::CPortInfo::Stop()
	{
//Todo: implement any stop functionality required.
	}

void CPortBufferHandler::CPortInfo::Resume()
	{
//Todo: implement any resume functionality required.
	}
	

void CPortBufferHandler::CPortInfo::Pause()
	{
//Todo: implement any resume functionality required.
	}	

void CPortBufferHandler::CPortInfo::FreeBuffers()
	{
	for (TInt buf = 0; buf < iNumBufs; ++buf)
		{
		iComp->FreeBuffer(iComp, iPortNum, iBufferHeaders[buf]);
		}

	DeleteAllBuffers();
	}

void CPortBufferHandler::CPortInfo::DeleteAllBuffers()
	{
	iBufferHeaders.Reset();

	if (iComp && iSupplier != OMX_BufferSupplyInput)
		{
		iBuffers.ResetAndDestroy();
		}
	else
		{
		iBuffers.Reset();
		}
	}

TBool CPortBufferHandler::CPortInfo::ComparePortNum(const TInt* aPortNum, const CPortInfo& aPortInfo)
	{
	//return (aComp == aPortInfo.iComp);
	return (*aPortNum == aPortInfo.iPortNum);
	}
	
OMX_DIRTYPE& CPortBufferHandler::CPortInfo::PortDir()
	{
	return iPortDir;
	}
	
void CPortBufferHandler::CPortInfo::LogExtra(const TText8* aFile, TInt aLine, TOmxScriptSeverity aSeverity,
            TRefByValue<const TDesC16> aFmt,...)
    {
    VA_LIST aList;
    VA_START(aList, aFmt);

    TOverflowHandler overflow;
    TBuf<255> msg;
    msg.AppendFormatList(aFmt, aList, &overflow);
    
    iLogger.Log(aFile, aLine, aSeverity, msg);
    
    VA_END(aList);
    }