/*
* Copyright (c) 2006 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 "NGAPostProcHwDevice.h"
#include "NGAPostProcSessionManager.h"
#include "NGAPostProcSurfaceHandler.h"

// post-processor info
const TUid KUidVideoPostProcHwDevice = {KUidNGAPostProcHwDeviceImplUid};
_LIT(KManufacturer, "Nokia Inc.");
_LIT(KIdentifier, "Nokia S60 Video Post Processor Hardware Device Plugin");

// --- Constants ---
const TInt KMaxVBMBuffers      			= 4;
const TInt KMinVBMInputWidth   			= 32; 
const TInt KMinVBMInputHeight  			= 32;
const TInt KMaxVBMInputWidth   			= 1280; 
const TInt KMaxVBMInputHeight  			= 720;
const TInt KRenderAhead 	     		= 50000;     
const TInt KMaxRenderDelay     			= 50000;
const TInt KPostingOfset       			= 0;    
const TInt KColorConversionBuffers  	= 3;
const TInt KMaxBuffersGceCanHold    	= 3;
const TInt KDefPlayRate					= 100;
const TInt KMaxAllowedSkipInNFrames 	= 40;
#ifdef __cplusplus
extern "C"
{
#endif

int32 gColorConvYUVtoYUV422Int (tBaseVideoFrame *yuv420Frame, tBaseVideoFrame* yuv422Frame,
							   uint8 outClrFmt, int16 stride); 

int32 Emz_VDec_gColorConv_YUVtoRGB ( 
	  tBaseVideoFrame *srcImage, uint8 *dstImage, tWndParam *srcWindow, 
	  tWndParam *dstWindow, uint8 srcImageFormat, uint8 dstImageFormat,
	  uint8 colorConvScheme);
		 	  
#ifdef __cplusplus
}
#endif

//**************************************************

CMMFVideoPostProcHwDevice* CNGAPostProcHwDevice::NewL() 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice::NewL() ++"));

    CNGAPostProcHwDevice* self = new (ELeave) CNGAPostProcHwDevice; 
    CleanupStack::PushL(self);
    self->ConstructL(); 
    CleanupStack::Pop();

   PP_DEBUG(_L("CNGAPostProcHwDevice::NewL() --"));
    return (CMMFVideoPostProcHwDevice*)self; 
}

void CNGAPostProcHwDevice::ConstructL() 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::ConstructL() ++"), this);
    
    // support for VBM buffer interface
    iVBMBufferOptions.iNumInputBuffers  = KMaxVBMBuffers; 
    iVBMBufferOptions.iBufferSize = TSize(KMaxVBMInputWidth, KMaxVBMInputHeight);
    iPostingTimer = CNGAPostProcTimer::NewL(*this);
    iWsSession.Connect();
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::ConstructL() --"), this);
}

CNGAPostProcHwDevice::CNGAPostProcHwDevice() 
        :   iProxy(NULL), 
            iInputDecoderDevice(NULL),
            iCurrentPlaybackPosition(TTimeIntervalMicroSeconds(0)),
            iPPState(EInitializing),
            iSurfaceHandler(NULL),
            iSessionManager(NULL),
            iIsInputEnded(EFalse),
            iPostingTimer(NULL),
            iFirstPictureUpdated(EFalse),
            iUsingExternalSurface(EFalse),
            iIsColorConversionNeeded(EFalse),
            iSurfaceCreatedEventPublished(EFalse),
            iOverflowPictureCounter(0),
            iVideoFrameBufSize(0),
            iResourceLost(EFalse),
            iRedrawDone(EFalse),
			iRedrawSurfaceInUse(EFalse),
            iVBMObserver(NULL),
            count(0),
            iSurfaceMask(surfaceHints::EAllowAllExternals),
            iSurfaceKey(TUid::Uid(surfaceHints::KSurfaceProtection)),
            iVideoSurfaceObserver(NULL),
            iVPObserver(NULL),
            iPicSize(0,0),
			iAspectRatioNum(1),
			iAspectRatioDenom(1),
            iStepFrameCount(0),
            iPlayRate(KDefPlayRate),
            iKeyFrameMode(EFalse),
            iFPObserver(NULL)
{
	iSurfaceId 		 = TSurfaceId::CreateNullId();
	iAttributes().iPixelFormat    = EUidPixelFormatYUV_422Interleaved;
}

CNGAPostProcHwDevice::~CNGAPostProcHwDevice()
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::~CNGAPostProcHwDevice() ++"), this);
   	if (iSessionManager)
    {
        iSessionManager->CancelUpdate();
        delete iSessionManager;
        iSessionManager = NULL;
    }
   	
   	while (iSupportedInputFormats.Count()>0)
    {
		iSupportedInputFormats.Remove(0);
    }
    
   	while (iProcessQ.Count()>0)
    {
		iProcessQ.Remove(0);
    }

   	if(iPostingTimer)
    {
    	iPostingTimer->Cancel();
        delete iPostingTimer;
        iPostingTimer = NULL;
    }
    
    while (iVBMBufferReferenceQ.Count()>0)
    {
        TVideoPicture* pic = iVBMBufferReferenceQ[0];
        iVBMBufferReferenceQ.Remove(0);
        if (iColorConversionQ.Count()>0)
    	{
	        iColorConversionQ.Remove(0);
	    }

        if (pic->iHeader) delete pic->iHeader;
        delete pic->iData.iRawData;
        delete pic;
    }
    
    iSupportedInputFormats.Reset();
    iSupportedInputFormats.Close();
    
    iVBMBufferReferenceQ.Reset();
    iVBMBufferReferenceQ.Close();
    
    iColorConversionQ.Reset();
    iColorConversionQ.Close();
    
    iVBMBufferQ.Reset();
    iVBMBufferQ.Close();
    
    iProcessQ.Reset();
    iProcessQ.Close();
        
    iInputQ.Reset();
    iInputQ.Close();
    
    if (iSurfaceHandler)
    {
    	if(!iSurfaceId.IsNull())
    	{
    		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::UnregisterSurface"), this);
			TInt numScreens = iWsSession.NumberOfScreens();
    		for(TInt i=0;i < numScreens;i++)
    		{
    			iWsSession.UnregisterSurface(i, iSurfaceId);
    		}
    		iWsSession.Flush();
        	iSurfaceHandler->DestroySurface(iSurfaceId);
    	}
        delete iSurfaceHandler;
        iSurfaceHandler = NULL;
    }
    
    iWsSession.Close();
    iChunk.Close();
    RDebug::Printf("------ Statistics of Post Processor ------");
    RDebug::Printf("    Pictures Received : %d", iPictureCounters.iTotalPictures);
    RDebug::Printf("    Pictures Displayed: %d", iPictureCounters.iPicturesDisplayed);
    RDebug::Printf("    Pictures Skipped  : %d", iPictureCounters.iPicturesSkipped);
    RDebug::Printf("    Pictures overflow : %d", iOverflowPictureCounter);
    RDebug::Printf("------------------------------------------");
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:~() --"), this);
}

void CNGAPostProcHwDevice::SetInputFormatL(const TUncompressedVideoFormat&  aFormat) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputFormatL() Pattern= %x ++"), this, aFormat.iYuvFormat.iPattern);
    if (iPPState != EInitializing)
    {
				PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputFormatL() FAILED: Unexpected state"), this);
        User::Leave(KErrNotReady);
	  }

		iVideoFormat = aFormat; 
		if( ((iVideoFormat.iYuvFormat.iPattern == EYuv420Chroma1) ||
			(iVideoFormat.iYuvFormat.iPattern == EYuv420Chroma2) ||
    		(iVideoFormat.iYuvFormat.iPattern == EYuv420Chroma3) ))
		{
			iVideoFormat.iYuvFormat.iCoefficients  	     = EYuvBt709Range1;
    		iVideoFormat.iYuvFormat.iPattern       	     = EYuv422Chroma1;
    		iVideoFormat.iYuvFormat.iDataLayout          = EYuvDataInterleavedBE;
			
#if defined __WINSCW__				
				iIsColorConversionNeeded = ETrue; 
#else
				iAttributes().iPixelFormat = EUidPixelFormatYUV_420Planar;
#endif //__WINSCW__
		}	

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputFormatL() WARNING: -- Not Found!"), this);
}


void CNGAPostProcHwDevice::SetInputDevice(CMMFVideoDecodeHwDevice* aDevice) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputDevice() ++"), this);

    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputDevice() FAILED: unexpected state"), this);
        return;
	}

    iInputDecoderDevice = aDevice;

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputDevice() --"), this);
}

void CNGAPostProcHwDevice::GetOutputFormatListL(RArray<TUncompressedVideoFormat>& ) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetOutputFormatListL() ++"), this);


	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetOutputFormatListL() --"), this);
}

void CNGAPostProcHwDevice::SetOutputFormatL(const TUncompressedVideoFormat&  ) 
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetOutputFormatL() ++"), this);

	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetOutputFormatL() --"), this);
}

void CNGAPostProcHwDevice::SetClockSource(MMMFClockSource* aClock) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetClockSource() ++"), this);
    
    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetClockSource() FAILED: Unexpected state"), this);
        return;
	}
    iClockSource = aClock;

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetClockSource() --"), this);
}

void CNGAPostProcHwDevice::SetVideoDestScreenL(TBool /*aScreen*/) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetVideoDestScreenL() ++"), this);

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetVideoDestScreenL() --"), this);
}

void CNGAPostProcHwDevice::SetProxy(MMMFDevVideoPlayProxy& aProxy) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetProxy() ++"), this);

    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetProxy() FAILED: Unexpected state"), this);
        return;
	}

    iProxy = &aProxy;

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetProxy() --"), this);
}

void CNGAPostProcHwDevice::Initialize() 
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize ++"));
	TInt err = KErrNone;

    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize() FAILED: Unexpected state"), this);
        return;
	}
	if (!iSurfaceHandler)
    {
    	TRAP(err, iSurfaceHandler = CNGAPostProcSurfaceHandler::NewL());
    	if (err != KErrNone)
    	{
    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to create SurfaceHandler."), this);
    	    return;
    	}
    }
    if (!iSessionManager)
    {
    	TRAP(err, iSessionManager = CNGAPostProcSessionManager::NewL());
    	if (err != KErrNone)
    	{
    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to create SessionManager."), this);
    	    return;
    	}
    	iSessionManager->SetObserver(*this);
    }

  	if (iInputDecoderDevice)
	{
		MMmfVideoResourceHandler* handler = NULL;
		handler = (MMmfVideoResourceHandler*)iInputDecoderDevice->CustomInterface(KUidMmfVideoResourceManagement);
		if (handler)
		{
			handler->MmvrhSetObserver((MMmfVideoResourceObserver*)this);
		}
		else
		{
			PP_DEBUG(_L("ppHwDev[%x]:Initialize() decoder yet to implement MMmfVideoResourceHandler CI"), this);
		}
		
		MMmfVideoPropertiesNotifier* VPHandler = NULL;
		VPHandler = (MMmfVideoPropertiesNotifier*)iInputDecoderDevice->CustomInterface(KUidMmfVideoPropertiesManagement);
		if (VPHandler)
		{
			PP_DEBUG(_L("ppHwDev[%x]:Initialize() Register for video property changes"), this);
			VPHandler->MmvpnSetObserver((MMmfVideoPropertiesObserver*)this);
		}
		else
		{
			PP_DEBUG(_L("ppHwDev[%x]:Initialize() decoder yet to implement MMmfVideoPropertiesNotifier CI"), this);
		}
	}
		
    // Initialize picture counters
	iPictureCounters.iPicturesSkipped 	= 0;
	iPictureCounters.iPicturesDisplayed = 0;
	iPictureCounters.iTotalPictures = 0;
	iOverflowPictureCounter = 0;
	if (iProxy)
	{
		iProxy->MdvppInitializeComplete(this, err);
	}
	iPPState = EInitialized;	
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize --"), this);
}

void CNGAPostProcHwDevice::WritePictureL(TVideoPicture* aPicture) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePicture bufId = %d"), this,GetID(aPicture));
	TVideoPicture* pic;
	if (iPPState==EInitializing || iPPState==EStopped || iIsInputEnded)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePictureL() FAILED: Unexpected state"), this);
        User::Leave(KErrNotReady);
	}

    if(!aPicture)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePictureL() FAILED: Invalid argument"), this);
		User::Leave(KErrArgument);
	}
	pic = aPicture;	
	iPictureCounters.iTotalPictures++;
	if((iPPState != EPlaying) && (iFirstPictureUpdated))
	{
		AddToQ(pic);
	}
	else if( iInputQ.Count() > 0 )
	{
		AddToQ(pic);
		AttemptToPost();
	}
	else
	{
		TInt64 delta = 0;
		TTimeToPost iTimeToPost = (TTimeToPost)IsTimeToPost(pic, delta);
		if(!IsGceReady())
	    {  
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePictureL GCE not ready"), this );
			if(iTimeToPost == EPostIt)
			{
					iTimeToPost = EDelayIt;
			}
	    }
	    if (delta > 0x7FFFFFFF)
	    {
	         PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePictureL Too large delta .. skipping"), this ); 
	         iTimeToPost = ESkipIt;
	    }
		if(!iFirstPictureUpdated)
		{
            if(iTimeToPost == EDelayIt)
            {
                iTimeToPost = EPostIt;
            }
		}
		switch(iTimeToPost)
		{
			case EDelayIt:
			{
				if(AddToQ(pic) != 0)
				{
					break;
				}
				iPostingTimer->Cancel();
				SetTimer(delta);
			}
			break;
			case EPostIt:
			{
		
				if(iIsColorConversionNeeded)
				{
					TVideoPicture* ccPic;				
	    			ccPic = DoColorConvert(pic); // output will be in ccPic
	    			pic = ccPic;			   
				}
				iProcessQ.Append(pic);
						
				#ifdef _DUMP_YUV_FRAMES
				captureYuv(pic);
				#endif
				iSessionManager->PostPicture(iSurfaceId, GetID(pic), iInfo().iBuffers, ETrue);	
				iCurrentPlaybackPosition = pic->iTimestamp;			
			
				if(!iFirstPictureUpdated)
				{
					iFirstPictureUpdated = ETrue;
                    if(!iSurfaceCreatedEventPublished)
                    {
                        PublishSurfaceCreated();
                    }
				}
			}
			break;
			case ESkipIt:
			{
				ReleasePicture(pic); 
				PicturesSkipped();
			}
			break;
		}
    }
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePicture --"), this);
}


CPostProcessorInfo* 
CNGAPostProcHwDevice::PostProcessorInfoLC() 
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:PostProcessorInfoLC() ++"), this);
    TUncompressedVideoFormat yuvFormat;
    RArray<TUint32>                     SupportedPostProcess;
    TBool                               SupportedHwAcceleration = ETrue;   //Non-Accelerated ETrue, 
    TYuvToRgbCapabilities               SupportedYuvToRgbCapab; 
    TInt32                              SupportedRotations = ERotateNone; // no rotation supported
    
    TBool                               SupportedArbitraryScaling = EFalse; // no scaling supported
    RArray<TScaleFactor>                SupportedScaleFactors;
    TBool                               SupportedAntiAliasing = EFalse;
    
    //default
    yuvFormat.iDataFormat                     = EYuvRawData;
    yuvFormat.iYuvFormat.iYuv2RgbMatrix       = 0;
    yuvFormat.iYuvFormat.iRgb2YuvMatrix       = 0;
    yuvFormat.iYuvFormat.iAspectRatioNum      = 1;
    yuvFormat.iYuvFormat.iAspectRatioDenom    = 1;
    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt709Range1;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout          = EYuvDataInterleavedBE;
    
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt709Range0;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedBE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt709Range0;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedLE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
            
	yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt709Range1;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedLE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
            
    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt601Range0;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedBE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt601Range1;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedBE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
            
    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt601Range0;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedLE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt601Range1;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataInterleavedLE;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    yuvFormat.iYuvFormat.iPattern       	  = EYuv422Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
    
    //YUV 420 planar
    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt709Range1;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataPlanar;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma3;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt709Range0;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataPlanar;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma3;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt601Range1;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataPlanar;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma3;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iCoefficients  	  = EYuvBt601Range0;
    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma1;
    yuvFormat.iYuvFormat.iDataLayout    	  = EYuvDataPlanar;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma2;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));

    yuvFormat.iYuvFormat.iPattern       	  = EYuv420Chroma3;
    User::LeaveIfError(iSupportedInputFormats.Append(yuvFormat));
            
    CPostProcessorInfo* postProcessorInfo = CPostProcessorInfo::NewL( 
                KUidVideoPostProcHwDevice, 
                KManufacturer, 
                KIdentifier, 
                TVersion(1, 0, 0), 
                iSupportedInputFormats.Array(),
                SupportedPostProcess.Array(), 
                SupportedHwAcceleration,   
                ETrue,      //Direct Display
                SupportedYuvToRgbCapab, 
                SupportedRotations, 
                SupportedArbitraryScaling,
                SupportedScaleFactors.Array(), 
                SupportedAntiAliasing);
                
    CleanupStack::PushL(postProcessorInfo);            
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:PostProcessorInfoLC() --"), this);
    return postProcessorInfo;
}

void CNGAPostProcHwDevice::MmvprcGetPlayRateCapabilitiesL(TVideoPlayRateCapabilities& aCap)
{       
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcGetPlayRateCapabilitiesL ++"), this);       
     aCap.iPlayForward = ETrue;       
     aCap.iPlayBackward = ETrue;       
     aCap.iStepForward = ETrue;       
     aCap.iStepBackward = ETrue;       
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcGetPlayRateCapabilitiesL --"), this);       
}       

void CNGAPostProcHwDevice::MmvprcSetPlayRateL(const TInt aRate)
{       
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcSetPlayRateL ++"), this);       
     iPlayRate = aRate;
     if (iPlayRate<0)        
     {       
         iKeyFrameMode = ETrue;    
     }       
     else        
     {       
         iKeyFrameMode = EFalse;   
         ResetCountingBuffer();       
     }       
     //In fast forward go direct to key frame mode if speed >4X =     
    if (iPlayRate>KDefPlayRate*4)
     {       
         if (iFPObserver)        
         {       
             iFPObserver->MmvproKeyFrameModeRequest();       
             iKeyFrameMode=ETrue;       
         }       
     }       
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcSetPlayRateL=%d --"), this, aRate);       
}       

TInt CNGAPostProcHwDevice::MmvprcPlayRateL()
{       
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcPlayRateL= ++"), this);       
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcPlayRateL= --"), this);       
    return iPlayRate;       
}       

void CNGAPostProcHwDevice::MmvprcStepFrameL(const TInt aStep)
{       
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcStepFrameL= ++"), this);       
    iStepFrameCount = aStep;       
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcStepFrameL=%d --"), this, aStep);       
}       

void CNGAPostProcHwDevice::MmvprcSetObserver(MMmfVideoPlayRateObserver& aObserver)
{       
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcSetObserver ++"), this);       
    iFPObserver  = &aObserver;
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvprcSetObserver --"), this);
} 

void CNGAPostProcHwDevice::MmvsoSetSecureOutputL(TBool aSecure)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvsoSetSecureOutputL aSecure = %d++"), this, aSecure);     
	TInt err = KErrNone;  
    if(aSecure)
	{
		iSurfaceMask = surfaceHints::EAllowInternalOnly;
	}
	else
	{
		iSurfaceMask = surfaceHints::EAllowAllExternals;
	}
	if(!iSurfaceId.IsNull())
	{
		err = AddHints();
		if(err != KErrNone)
		{
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvsoSetSecureOutputL -- leaving err = %d"), this, err);
			User::Leave(err);
		}
	}
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvsoSetSecureOutputL --"), this);
}

void CNGAPostProcHwDevice::MmavsoSetAllowedOutputL(TUint aAllowedOutputMask)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmavsoSetAllowedOutputL aAllowedOutputMask=0x%08x ++"), this,aAllowedOutputMask);  
   TInt err = KErrNone;
   iSurfaceMask = surfaceHints::EAllowInternalOnly;
    if (aAllowedOutputMask == EVideoAllowAll)
    {
        iSurfaceMask = surfaceHints::EAllowAllExternals;
    }
    else if (aAllowedOutputMask == EVideoAllowInternalOnly)
    {
        iSurfaceMask = surfaceHints::EAllowInternalOnly;
    }
    else 
    {
        // we hope to find some valid output prefs
        if (aAllowedOutputMask & EVideoAllowAnalog)
        {
            iSurfaceMask |= surfaceHints::EAllowAnalog;
        }
        if (aAllowedOutputMask & EVideoAllowMacroVision)
        {
            iSurfaceMask |= surfaceHints::EAllowAnalogProtectionRequired;
        }
        if (aAllowedOutputMask & EVideoAllowHDMI)
        {
            iSurfaceMask |= surfaceHints::EAllowDigital;
        }
        if (aAllowedOutputMask & EVideoAllowHdmiHdcpRequested)
        {
            iSurfaceMask |= surfaceHints::EAllowDigitalProtectionRequested;
        }
        if (aAllowedOutputMask & EVideoAllowHdmiHdcpRequired)
        {
            iSurfaceMask |= surfaceHints::EAllowDigitalProtectionRequired;
        }
    }
    
	if((!iSurfaceId.IsNull()))
	{
		err = AddHints();
		if(err != KErrNone)
		{
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmavsoSetAllowedOutputL -- leaving err = %d"), this, err);
			User::Leave(err);
		}
	}
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmavsoSetAllowedOutputL --"), this);
}	

void CNGAPostProcHwDevice::SetPostProcessTypesL(TUint32 /*aCombination*/) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetPostProcessTypesL ++"), this);
	
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetPostProcessTypesL --"), this);
}

void CNGAPostProcHwDevice::SetInputCropOptionsL(const TRect& /*aRect*/) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputCropOptionsL ++"), this);
   
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetInputCropOptionsL --"), this);
}    

void CNGAPostProcHwDevice::SetYuvToRgbOptionsL( const TYuvToRgbOptions&  /*aOptions*/, const TYuvFormat& /*aYuvFormat*/, TRgbFormat /*aRgbFormat*/) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetYuvToRgbOptionsL ++"), this);

	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetYuvToRgbOptionsL --"), this);
}

void CNGAPostProcHwDevice::SetYuvToRgbOptionsL(const TYuvToRgbOptions& /*aOptions*/)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetYuvToRgbOptionsL ++"), this);

	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetYuvToRgbOptionsL --"), this);
}

void CNGAPostProcHwDevice::SetRotateOptionsL(TRotationType ) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetRotateOptionsL ++"), this);
    
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetRotateOptionsL --"));
}

void CNGAPostProcHwDevice::SetScaleOptionsL(const TSize& /*aTargetSize*/, TBool /*aAntiAliasFiltering*/) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetScaleOptionsL ++"), this);
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetScaleOptionsL --"), this);
}

void CNGAPostProcHwDevice::SetOutputCropOptionsL(const TRect& /*aRect*/) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetOutputCropOptionsL ++"), this);
    
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetOutputCropOptionsL --"), this);
}

void CNGAPostProcHwDevice::SetPostProcSpecificOptionsL(const TDesC8& ) 
{ 
    //ignore 
}

void CNGAPostProcHwDevice::CommitL() 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:CommitL ++"), this);

   	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:CommitL --"), this);
}

void CNGAPostProcHwDevice::Revert() 
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Revert ++"), this);
    
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Revert --"), this);
}

void CNGAPostProcHwDevice::StartDirectScreenAccessL( const TRect& /*aVideoRect*/, CFbsScreenDevice& /*aScreenDevice*/, const TRegion& /*aClipRegion*/) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:StartDSA ++"), this);
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:StartDSA --"), this);
}

void CNGAPostProcHwDevice::AbortDirectScreenAccess() 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AbortDSA ++"), this);

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AbortDSA --"), this);
}

void CNGAPostProcHwDevice::SetScreenClipRegion(const TRegion& /*aRegion*/) 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetScreenClipRegion ++"), this);
    
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetScreenClipRegion --"), this);
}		    

void CNGAPostProcHwDevice::SetPauseOnClipFail(TBool ) 
{ 
    //ignore. Post Processor will always behave as aPause==False. 
}

TBool CNGAPostProcHwDevice::IsPlaying()
{
	if( iPPState == EPlaying)
	{
    	return ETrue; 
    }
    else
    {
    	return EFalse;
    }
}

void CNGAPostProcHwDevice::Redraw() 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Redraw ++"), this);
	TInt err = KErrNone;
	if(iRedrawSurfaceInUse && !iRedrawDone)
	{
        err = AddHints();
        if (err != KErrNone)
        {
            PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Redraw -- failed to AddHints %d"), 
                         this, err);
            iProxy->MdvppFatalError(this, err);	
            return;   
        }
        PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Redraw registering the temp surface"), this);
		err = RegisterSurface(iSurfaceId);
		if (err != KErrNone)
		{
		   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Redraw -- failed to Register Surface %d"), 
		   				this, err);
		   	iSurfaceHandler->DestroySurface(iSurfaceId);
	   		iSurfaceId = TSurfaceId::CreateNullId();
			iProxy->MdvppFatalError(this, err);	
			return;   				
		}
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Redraw registering the temp surface done"), this);
        iSessionManager->PostPicture(iSurfaceId, 0, 1, EFalse);
        PublishSurfaceCreated();
        iRedrawDone = ETrue;
    }
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Redraw --"), this);
}

void CNGAPostProcHwDevice::Start() 
{  
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Start ++"), this);
	iPPState = EPlaying;
	AttemptToPost();
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Start --"), this);
}

void CNGAPostProcHwDevice::Stop() 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Stop ++"), this);
    iPPState = EStopped;
	iPostingTimer->Cancel();
	ReleaseInputQ();
	
	RDebug::Printf("------ Statistics of Post Processor ------");
    RDebug::Printf("    Pictures Received : %d", iPictureCounters.iTotalPictures);
    RDebug::Printf("    Pictures Displayed: %d", iPictureCounters.iPicturesDisplayed);
    RDebug::Printf("    Pictures Skipped  : %d", iPictureCounters.iPicturesSkipped);
    RDebug::Printf("------------------------------------------");
    
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Stop --"), this);
}

void CNGAPostProcHwDevice::Pause()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Pause ++"), this);
	iPPState = EPaused;
    iPostingTimer->Cancel();
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Pause --"), this);
}

void CNGAPostProcHwDevice::Resume()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Resume ++"), this);
	iPPState = EPlaying;
	AttemptToPost();
   	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Resume --"), this);
}

void CNGAPostProcHwDevice::SetPosition(const TTimeIntervalMicroSeconds& aPlaybackPosition) 
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetPosition ++"), this);
    
    if (iPPState == EInitializing)
    { 
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetPosition FAILED: Unexpected state"), this);
        return;
    }
    if (iPPState == EPaused)
    {	
        iFirstPictureUpdated = EFalse;
    }
    iCurrentPlaybackPosition = aPlaybackPosition;  
    
    ReleaseInputQ();

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetPosition --"), this);
}

void CNGAPostProcHwDevice::FreezePicture(const TTimeIntervalMicroSeconds& ) 
{ 
    //TODO:
}

void CNGAPostProcHwDevice::ReleaseFreeze(const TTimeIntervalMicroSeconds&  ) 
{ 
    //TODO:
}

TTimeIntervalMicroSeconds 
CNGAPostProcHwDevice::PlaybackPosition() 
{ 
	if (iPPState == EInitializing)
    {
        return TTimeIntervalMicroSeconds(0);
    }
    
    return iCurrentPlaybackPosition; 
}

TUint CNGAPostProcHwDevice::PictureBufferBytes() 
{   //TODO 
    return 0; 
}

void CNGAPostProcHwDevice::GetPictureCounters( CMMFDevVideoPlay::TPictureCounters&  aCounters) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetPictureCounters ++"), this);
	
	if (iPPState == EInitializing)
		return;
	aCounters = iPictureCounters;
	
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetPictureCounters --"), this);
}

void CNGAPostProcHwDevice::SetComplexityLevel(TUint ) 
{ 
    //not required 
}

TUint CNGAPostProcHwDevice::NumComplexityLevels() 
{ 
    //not required 
    return 1; 
}

void CNGAPostProcHwDevice::GetComplexityLevelInfo(TUint , CMMFDevVideoPlay::TComplexityLevelInfo& ) 
{ 
    //not required 
}

void CNGAPostProcHwDevice::ReturnPicture(TVideoPicture* ) 
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReturnPicture +-"), this);
    //not required for direct rendering 
}

TBool CNGAPostProcHwDevice::GetSnapshotL(TPictureData& aPictureData, const TUncompressedVideoFormat& /*aFormat*/)
{ 
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetSnapshotL %d %d ++"), this, iVBMEnabled, iProcessQ.Count());
	TVideoPicture* 		pic = NULL;
	TInt 				err = KErrNone;
	TBool				frameAvailable =EFalse;
	tWndParam			inputCropWindow;
	tWndParam			outputCropWindow;
	tBaseVideoFrame		inputFrame;
	inputFrame.lum 		= NULL; 
	
	if(aPictureData.iDataFormat == ERgbFbsBitmap)
	{	
		if(iProcessQ.Count())
		{
			pic = iProcessQ[0]; //frame already submitted for display
		}
		else if(iInputQ.Count())
		{
			pic = iInputQ[0]; //frame yet to be displayed
		}
		if(pic) 
		{
			if (iVBMEnabled)
		    {
				inputFrame.lum	= (TUint8*)pic->iData.iRawData->Ptr();
			}
			else
			{
				if (iInputDecoderDevice)
				{
					MMmfVideoFetchFrame* VFHandler = NULL;
					VFHandler = (MMmfVideoFetchFrame*)iInputDecoderDevice->CustomInterface(KUidMMFVideoFetchFrame);
					if (VFHandler)
					{
						PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetSnapshotL() fetch frame"), this);
						inputFrame.lum = (TUint8*)VFHandler->MmvffGetFrame(GetID(pic));
					}
					else
					{
						PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetSnapshotL() decoder yet to implement MMmfVideoFetchFrame CI"), this);
					}
				}
			}
		}
		if(inputFrame.lum)
		{
			inputFrame.cb	= inputFrame.lum + iPicSize.iWidth * iPicSize.iHeight;
			
			if( ((iVideoFormat.iYuvFormat.iPattern == EYuv420Chroma1) ||
				(iVideoFormat.iYuvFormat.iPattern == EYuv420Chroma2) ||
	    		(iVideoFormat.iYuvFormat.iPattern == EYuv420Chroma3) ))						
			{
				inputFrame.cr = inputFrame.lum + (iPicSize.iWidth * iPicSize.iHeight*5)/4;
			}
			else
			{
				inputFrame.cr = inputFrame.lum + (iPicSize.iWidth * iPicSize.iHeight*3)/2;
			}
			
			inputFrame.width	= (unsigned short)iPicSize.iWidth;
			inputFrame.height	= (unsigned short)iPicSize.iHeight;
			
			outputCropWindow.wndHeight  = iPicSize.iHeight;	
			outputCropWindow.wndWidth	= iPicSize.iWidth; 	
			outputCropWindow.xOffset	= 0;
			outputCropWindow.yOffset	= 0;
			
			inputCropWindow.wndHeight  = iPicSize.iHeight;	
			inputCropWindow.wndWidth	= iPicSize.iWidth; 	
			inputCropWindow.xOffset	= 0;
			inputCropWindow.yOffset	= 0;
			
			RFbsSession fbs;
			fbs.Connect();
			CFbsBitmap* iOutBitmap = aPictureData.iRgbBitmap;
			TInt status = iOutBitmap->Resize(iPicSize);
			if (status == KErrNone)
			{
				// Lock the heap to prevent the FBS server from invalidating the address
		        iOutBitmap->LockHeap();
		        TUint8* dataAddress = (TUint8*)iOutBitmap->DataAddress();
				err = ColorConvert(&inputFrame, dataAddress, &inputCropWindow, &outputCropWindow);
				iOutBitmap->UnlockHeap();
				frameAvailable = ETrue;
			}
			fbs.Disconnect();
		}
	}
	else
	{
		err = KErrNotSupported;
	}
	if(err != KErrNone)
	{
		User::Leave(err);
	}
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:GetSnapshotL --"), this);
	return(frameAvailable);
}

void CNGAPostProcHwDevice::InputEnd() 
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:InputEnd ++"), this);
    
	if (iPPState!=EPlaying && iPPState!=EPaused)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:InputEnd FAILED: Unexpected state"), this);
        return;
	}
    iIsInputEnded = ETrue;
    
  if( (iProcessQ.Count() == 1) && (iInputQ.Count() == 0))
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:InputEnd() Stream end"), this);
		iProxy->MdvppStreamEnd();
	}
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:InputEnd --"), this);
}

TAny* CNGAPostProcHwDevice::CustomInterface(TUid aInterface)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:CustomInterface UID = %d ++"), this, aInterface.iUid);
	
	if (aInterface == KUidMmfVideoBufferManagement)
    {
      return (MMmfVideoBufferManagement *)this;
    }
	if (aInterface == KUidMMFVideoSurfaceSupport)
	{
      return (MMMFVideoSurfaceSupport *)this;
    }
	if (aInterface == KUidMMFVideoSurfaceHandleControl)
	{
    	return (MMmfVideoSurfaceHandleControl *)this;
  }    
    if (aInterface == KUidMmfVideoPlayRateControl)
    {
      return (MMmfVideoPlayRateControl *)this;
    } 
    if (aInterface == KMmfVideoAdvancedSecureOutputUid)
    {
      return (MMmfAdvancedVideoSecureOutput *)this;
    }
    if (aInterface == KUidMmfVideoResourceManagement)
    {
      return (MMmfVideoResourceObserver *)this;
    } 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:CustomInterface --"), this);
    return NULL;
}

void CNGAPostProcHwDevice::BufferAvailable(TInt aBufId, TInt aStatus)
{ 
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:CNGAPostProcHwDevice::BufferAvailable aStatus = %d aBufId = %d++"), this, aStatus, aBufId);
    TVideoPicture* pic = NULL;
    if((aStatus != KErrNone) && (aStatus != KErrOverflow) && (aStatus != KErrNotVisible))
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:BufferAvailable FAILED: aStatus = %d"), this, aStatus);
		iProxy->MdvppFatalError(this, aStatus);
	}

	if(aStatus == KErrOverflow)
	{
		iOverflowPictureCounter++;
		PicturesSkipped();
	}
    	
    if (iVBMEnabled)
    {
		for(TInt i=0; i < iProcessQ.Count(); i++)
		{
			if(iVBMBufferReferenceQ[aBufId] == iProcessQ[i])
			{
				pic = iProcessQ[i];
				iProcessQ.Remove(i);				
				ReturnPicToDecoder(pic);
				if (iIsColorConversionNeeded)
				{
				    AddPictureToColorConversionQ(pic);
				}
				else
				{
				    AddPictureToVBMQ(pic);
				}
				break;
			}
		} 
	}
	else if (iUsingExternalSurface)
	{
	    for(TInt i=0; i < iProcessQ.Count(); i++)
		{
			if (aBufId == GetExternalBufferID(iProcessQ[i]))
			{
				pic = iProcessQ[i];
				iProcessQ.Remove(i);
				ReturnPicToDecoder(pic);
				break;
			}
		} 
	}
	
	if(aStatus == KErrNone)
	{
		if (!iKeyFrameMode && iPlayRate>KDefPlayRate)     
		{   
		 	if (iSkippedFramesCountingBuffer[iCurrentPosInFramesCountingBuffer]==1)        
		 	{       
		 		iSkippedFramesCountingBuffer[iCurrentPosInFramesCountingBuffer] = 0;       
		 		iSkippedFramesInLast64Frames--;       
		 	}       
		 	iCurrentPosInFramesCountingBuffer = ++iCurrentPosInFramesCountingBuffer%64;       
		} 
		iPictureCounters.iPicturesDisplayed++;
		if (iStepFrameCount != 0)
        {       
        	iStepFrameCount > 0 ? iStepFrameCount-- : iStepFrameCount++;		            	      
            if (iStepFrameCount==0 && iFPObserver)        
            {       
            	iFPObserver->MmvproStepFrameComplete(pic->iTimestamp);       
            }       
        }
	}
	
	if(iPPState == EPlaying)
	{
		AttemptToPost();
	}

	if( iIsInputEnded && (iProcessQ.Count() == 1)  && (iInputQ.Count() == 0))
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:BufferAvailable() Stream end"), this);
		iProxy->MdvppStreamEnd();
	}
	
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:CNGAPostProcHwDevice::BufferAvailable --"), this);
}

//=== MMmfVideoBufferManagement ===
void CNGAPostProcHwDevice::MmvbmSetObserver(MMmfVideoBufferManagementObserver* aObserver)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetObserver() ++"), this);

    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetObserver FAILED: Unexpected state"), this);
        iProxy->MdvppFatalError(this, KErrNotReady);
	}

    iVBMObserver  = aObserver;

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetObserver() --"), this);
}
    

void CNGAPostProcHwDevice::MmvbmEnable(TBool aEnable)
{
    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmEnable FAILED: Unexpected state"), this);
        iProxy->MdvppFatalError(this, KErrNotReady);
	}

    iVBMEnabled = aEnable;
}
    
void CNGAPostProcHwDevice::MmvbmSetBufferOptionsL(const TBufferOptions& aOptions)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetBufferOptionsL ++"), this);

    if (iPPState != EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetBufferOptionsL FAILED: Unexpected state"), this);
        User::Leave(KErrNotReady);
	}

    if (aOptions.iNumInputBuffers > KMaxVBMBuffers 
        || aOptions.iNumInputBuffers <= 1)          //at least two buffers
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetBufferOptionsL FAILED: Input buffer count limit"), this);
        User::Leave(KErrNotSupported);
	}

    if (aOptions.iNumInputBuffers == 0 
        || aOptions.iBufferSize.iWidth <= KMinVBMInputWidth 
        || aOptions.iBufferSize.iHeight <= KMinVBMInputHeight  
        || aOptions.iBufferSize.iWidth > KMaxVBMInputWidth 
        || aOptions.iBufferSize.iHeight > KMaxVBMInputHeight)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetBufferOptionsL FAILED: Unexpected buffer size"), this);
        User::Leave(KErrArgument);
	}

    iVBMBufferOptions.iNumInputBuffers  = aOptions.iNumInputBuffers;
    iVBMBufferOptions.iBufferSize       = aOptions.iBufferSize;

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmSetBufferOptionsL --"), this);
}

void CNGAPostProcHwDevice::MmvbmGetBufferOptions(TBufferOptions& aOptions)
{
    if (iPPState == EInitializing)
    {
    	aOptions = iVBMBufferOptions;
    }
    else
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferOptions FAILED: Unexpected state"), this);
        iProxy->MdvppFatalError(this, KErrNotReady);
	}
}
    
TVideoPicture* CNGAPostProcHwDevice::MmvbmGetBufferL(const TSize& aSize)
    {
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferL() ++"), this);
    
    TInt err = KErrNone;
    TVideoPicture* lPic = NULL;

    if (iPPState == EInitializing)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferL() FAILED: Unexpected state"), this);
        User::Leave(KErrNotReady);
	  }

    if (aSize.iWidth < KMinVBMInputWidth 
        || aSize.iHeight < KMinVBMInputHeight
        || aSize.iWidth > iVBMBufferOptions.iBufferSize.iWidth 
        || aSize.iHeight > iVBMBufferOptions.iBufferSize.iHeight)
  	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferL() FAILED: Unexpected buffer size w=%d h=%d "), this,aSize.iWidth,aSize.iHeight );
        User::Leave(KErrNotSupported);
		}
		
		if(iVBMBufferReferenceQ.Count() == 0)
		{
			iPicSize = aSize;
			err = SetupSurface(aSize);
			if(err)
			{
					PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferL() Surface Setup Failed %d"), this, err);
					User::Leave(err);
			}
		}
		
    if(!iVBMBufferQ.Count())
    {
       PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferL() WARNING: Queue buffer count zero"), this);
        return NULL;
    }

    lPic    = iVBMBufferQ[0];
    iVBMBufferQ.Remove(0);

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmGetBufferL() -- %d"), this, lPic);
    return lPic;
}
    
void CNGAPostProcHwDevice::MmvbmReleaseBuffer(TVideoPicture* aBuffer)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmReleaseBuffer() ++"), this);

    if(!aBuffer)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmReleaseBuffer() FAILED: Invalid buffer ptr"), this);
    	iProxy->MdvppFatalError(this, KErrArgument);
	}

    TInt err = iVBMBufferQ.Append(aBuffer);
    if (err)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmReleaseBuffer() FAILED: Failed to append"), this);
		iProxy->MdvppFatalError(this, err);
	}

   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvbmReleaseBuffer() --"), this);
}

//=== MMMFVideoSurfaceSupport ===

void CNGAPostProcHwDevice::MmvssUseSurfaces()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssUseSurfaces() ++"), this);
	// do nothing
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssUseSurfaces() --"), this);
}

void CNGAPostProcHwDevice::MmvssSetObserver(MMMFVideoSurfaceObserver& aObserver)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssSetObserver() ++"), this);
	iVideoSurfaceObserver = &aObserver;
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssSetObserver() --"), this);
}

void CNGAPostProcHwDevice::MmvssGetSurfaceParametersL(TSurfaceId& aSurfaceId, 
						TRect& aCropRect, TVideoAspectRatio& aPixelAspectRatio)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssGetSurfaceParametersL() ++"), this);

	iSurfaceHandler->SurfaceInfo(iSurfaceId, iInfo);
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssGetSurfaceParametersL() \
		surfaceWidth = %d surfaceHeight = %d SurfaceId = 0x%x --"), 
		this, iInfo().iSize.iWidth, iInfo().iSize.iHeight, iSurfaceId);
	aSurfaceId = iSurfaceId;
		aCropRect = TRect(0, 0, iInfo().iSize.iWidth, iInfo().iSize.iHeight);
		if((iPicSize.iWidth > 0) && (iPicSize.iHeight > 0))
		{
			aCropRect.Intersection( iPicSize);
		}
	aPixelAspectRatio = TVideoAspectRatio(iAspectRatioNum,iAspectRatioDenom);
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssGetSurfaceParametersL()  \
		cropRectWidth = %d cropRectHeight = %d"), this, aCropRect.Width(), aCropRect.Height());
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssGetSurfaceParametersL()  \
		PAR Num = %d PAR Denom = %d"), this, aPixelAspectRatio.iNumerator, aPixelAspectRatio.iDenominator);
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssGetSurfaceParametersL() --"), this);
}

void CNGAPostProcHwDevice::MmvssSurfaceRemovedL(const TSurfaceId& aSurfaceId)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssSurfaceRemovedL()++"), this);
	if(!aSurfaceId.IsNull())
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssSurfaceRemovedL(): UnregisterSurface ID = 0x%x"), this, aSurfaceId );
		TInt numScreens = iWsSession.NumberOfScreens();
		for(TInt i=0;i < numScreens;i++)
		{
			iWsSession.UnregisterSurface(i, aSurfaceId);
		}
		iWsSession.Flush();
		iSurfaceHandler->DestroySurface(aSurfaceId);
		if(iSurfaceId == aSurfaceId)
		{
			iSurfaceCreatedEventPublished = EFalse;
			iSurfaceId = TSurfaceId::CreateNullId();
			iChunk.Close();
		}
	}
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvssSurfaceRemovedL() --"), this);
}

// === MMmfVideoPropertiesObserver ===
    
void CNGAPostProcHwDevice::MmvpoUpdateVideoProperties(const TYuvFormat& aYuvFormat, const TSize& aPictureSize)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvpoUpdateVideoProperties ++"), this);
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvpoUpdateVideoProperties PAR \
		iAspectRatioNum = %d, iAspectRatioDenom = %d"), this,
					 aYuvFormat.iAspectRatioNum,aYuvFormat.iAspectRatioDenom);
	iPicSize = aPictureSize;
	iAspectRatioNum = aYuvFormat.iAspectRatioNum;
	iAspectRatioDenom = aYuvFormat.iAspectRatioDenom;
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvpoUpdateVideoProperties Picture Size \
		iWidth = %d, iHeight = %d, iSurfaceCreatedEventPublished = %d"), 
		this, iPicSize.iWidth,iPicSize.iHeight, iSurfaceCreatedEventPublished?1:0);
			 
	if(iVPObserver)
	{
		iVPObserver->MmvpoUpdateVideoProperties(aYuvFormat, aPictureSize);
	} 
	if(iVideoSurfaceObserver && iSurfaceCreatedEventPublished)
	{
    	iVideoSurfaceObserver->MmvsoSurfaceParametersChanged(); 
    }
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvpoUpdateVideoProperties --"), this);
}

// === MMmfVideoResourceObserver ===

void CNGAPostProcHwDevice::MmvroResourcesLost(TUid )
{
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvroResourcesLost ++"), this);
    if(!iResourceLost)
    {
		iResourceLost = ETrue;
		iRedrawDone = EFalse;
		Pause();
		ReleaseInputQ();
		iSessionManager->CancelUpdate();
		ReleaseProcessQ();
		if(iVideoSurfaceObserver && iSurfaceCreatedEventPublished)
		{
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvroResourcesLost - Telling client to remove surface"), this);
			iVideoSurfaceObserver->MmvsoRemoveSurface();
			iSurfaceCreatedEventPublished = EFalse;
		}
	}
	else if(iResourceLost && iRedrawDone)
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvroResourcesLost ResourceLost happening \
					while Postprocessor is already in ResourceLoss state"), 
	   				this);
		iProxy->MdvppFatalError(this, KErrHardwareNotAvailable);	   				
	    return;		
	}
	else
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvroResourcesLost Ignoring the \
					duplicate ResourceLoss call"), 
	   				this);
	}
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvroResourcesLost --"), this);
}

// === MMmfVideoPropertiesNotifier ===
    
void CNGAPostProcHwDevice::MmvpnSetObserver(MMmfVideoPropertiesObserver* aObserver)
{
	PP_DEBUG(_L("ppHwDev[%x]::MmvpnSetObserver ++"), this);
	iVPObserver = aObserver;
	PP_DEBUG(_L("ppHwDev[%x]::MmvpnSetObserver --"), this);
}

void CNGAPostProcHwDevice::MmvroResourcesRestored(TUid )
{
   	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvroResourcesRestored ++"), this);
	iFirstPictureUpdated = EFalse;
	iResourceLost = EFalse;
   	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvroResourcesRestored state=%d --"), 
   			this, iPPState);
}

void CNGAPostProcHwDevice::MmvshcSetSurfaceHandle(const TSurfaceId &aSurfaceID)
{
    
    SetupExternalSurface(aSurfaceID);
    
}

void CNGAPostProcHwDevice::MmvshcRedrawBufferToSurface(TPtrC8& aRedrawBuffer)
{
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface ++"), this);
	
    TUint8*         lPtr;
    TInt 			offset;

    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface -- Creating %d x %d surface"), this, iPicSize.iWidth, iPicSize.iHeight);

   	TInt err = KErrNone;
	SetSurfaceAttributes(iPicSize, 1); 
	
  	err = iSurfaceHandler->CreateSurface(iAttributes, iSurfaceId);
  	if (err != KErrNone)
	{
	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvshcRedrawBufferToSurface -- failed to create Surface %d"), 
	   				this, err);
		iProxy->MdvppFatalError(this, err);	   				
	    return;
	}

	err = iSurfaceHandler->SurfaceInfo(iSurfaceId, iInfo);
	if (err != KErrNone)
	{
	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvshcRedrawBufferToSurface -- failed to get Surface info %d"), 
	   				this, err);
	   	iSurfaceHandler->DestroySurface(iSurfaceId);
	   	iSurfaceId = TSurfaceId::CreateNullId();
		iProxy->MdvppFatalError(this, err);	   				
	    return;
	}

	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvshcRedrawBufferToSurface() \
		surfaceWidth = %d surfaceHeight = %d surfaceStride = %d"), this, iInfo().iSize.iWidth, iInfo().iSize.iHeight, iInfo().iStride);

	TInt redrawBufferSize = aRedrawBuffer.Size();
	TInt surfaceSize = iInfo().iStride * iInfo().iSize.iHeight;

    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface RedrawBuffer size= %d Surface size = %d"), this, redrawBufferSize, surfaceSize);

	// Check whether redraw buffer will fit onto the surface.
	// If this check fails then we won't raise a fatal error - We just won't create the redraw surface
	if (redrawBufferSize > surfaceSize)
	{
    	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface Redraw buffer size larger than surface size"), this);
    	iSurfaceHandler->DestroySurface(iSurfaceId);
	   	iSurfaceId = TSurfaceId::CreateNullId();
    	return;
	}

	err = iSurfaceHandler->MapSurface(iSurfaceId, iChunk);
	if (err != KErrNone)
	{
	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:MmvshcRedrawBufferToSurface -- failed to map Surface %d"), 
	   				this, err);
	   	iSurfaceHandler->DestroySurface(iSurfaceId);
	   	iSurfaceId = TSurfaceId::CreateNullId();
		iProxy->MdvppFatalError(this, err);	   				
	    return;
	}

    if((err = iSurfaceHandler->GetBufferOffset(iSurfaceId, 0, offset)) != KErrNone)
    {
    	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface offset query failed %d"), this, err);
    	iSurfaceHandler->DestroySurface(iSurfaceId);
	   	iSurfaceId = TSurfaceId::CreateNullId();
		iChunk.Close();
    	iProxy->MdvppFatalError(this, err);
    	return;
    }

    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface offset = %d"), this, offset);

	lPtr = reinterpret_cast<TUint8*>(iChunk.Base() + offset);
	memcpy((TAny *)lPtr, (TAny *)aRedrawBuffer.Ptr(), redrawBufferSize);

	iRedrawSurfaceInUse = ETrue;

	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface(): New surface = 0x%x"), this, iSurfaceId);

    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::MmvshcRedrawBufferToSurface error = %d --"), this, err);
}

TInt CNGAPostProcHwDevice::SetupExternalSurface(const TSurfaceId &aSurfaceID)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface(): aSurfaceID = 0x%x"), this, aSurfaceID );

    TInt err = KErrNone;
    
    if(!iSurfaceId.IsNull())
    {
		if (iVideoSurfaceObserver && iSurfaceCreatedEventPublished)
		{
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface - Telling client to remove old surface"), this);
			iVideoSurfaceObserver->MmvsoRemoveSurface();
			iSurfaceCreatedEventPublished = EFalse;
		}
		else
		{
			// We never told the client about the surface, so we must destroy it ourselves
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface - Destroying old surface"), this);
			TInt numScreens = iWsSession.NumberOfScreens();
    		for(TInt i=0;i < numScreens;i++)
    		{
    			iWsSession.UnregisterSurface(i, iSurfaceId);
    		}
   			iWsSession.Flush();
			iSurfaceHandler->DestroySurface(iSurfaceId);
		}

		iChunk.Close();
	}
    
    iSurfaceId            = aSurfaceID;
    iUsingExternalSurface = ETrue;
    iRedrawSurfaceInUse = EFalse;

    // Create the surface handler if it doesn't exist.
    if (!iSurfaceHandler)
    {
        TRAP(err, iSurfaceHandler = CNGAPostProcSurfaceHandler::NewL());
        if (err != KErrNone)
        {
           PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface -- failed to create SurfaceHandler."), this);
            return err;
        }
    }
    
    err = iSurfaceHandler->OpenSurface(iSurfaceId);
    if (err != KErrNone)
	{
	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface -- failed OpenSurface %d"), 
	   				this, err);
	    return err;
	}
    err = AddHints();
    if (err != KErrNone)
    {
        PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface -- failed to AddHints %d"), 
                    this, err);
        return err;
    }
	err = RegisterSurface(iSurfaceId);
	if (err != KErrNone)
	{
	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface -- failed RegisterSurface %d"), 
	   				this, err);
	   	iSurfaceHandler->DestroySurface(iSurfaceId);
	   	iSurfaceId = TSurfaceId::CreateNullId();
	    return err;
	}

    err = iSurfaceHandler->SurfaceInfo(iSurfaceId, iInfo);
    if (err != KErrNone)
    {
        PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface -- failed to get Surface info %d"), 
                     this, err);
        return err;
    }
 
  PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetupExternalSurface err=%d"), this, err);
   return err;
}

//=== Internal ===
TVideoPicture* CNGAPostProcHwDevice::CreateBuffersL(TInt aBufId)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::CreateBuffersL ++"), this);
	
	TVideoPicture*          lVideoPicture = NULL;
    TUint8*                 lPtr;
    TPtr8*                  lTemp;
    TInt 					offset;
    
	lVideoPicture = new (ELeave) TVideoPicture;
    CleanupStack::PushL(lVideoPicture);
    if(TInt err = iSurfaceHandler->GetBufferOffset(iSurfaceId, aBufId, offset) != KErrNone)
    {
    	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::CreateBuffersL offset query failed %d"), this, err);
    }
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::CreateBuffersL offset = %d id =%d --"), this, offset, aBufId);
    
	lPtr = reinterpret_cast<TUint8*>(iChunk.Base() + offset);

    lTemp = new (ELeave) TPtr8(lPtr, 0, (iVideoFrameBufSize ));
    CleanupStack::PushL(lTemp);

    lVideoPicture->iData.iRawData   = lTemp;
    lVideoPicture->iHeader = NULL ;
    lVideoPicture->iLayerBitRates = NULL ;
    
    CleanupStack::Pop(2);
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::CreateVBMBuffersL --"), this);
    return lVideoPicture;
}

void CNGAPostProcHwDevice::CreateVBMBuffersL()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::CreateVBMBuffersL ++"), this);
    
    TInt err = KErrNone;
    TVideoPicture* pic = NULL;
    iVBMBufferReferenceQ.Reset();
    iVBMBufferQ.Reset();
    iColorConversionQ.Reset();

    for(TInt i = 0; i < iVBMBufferOptions.iNumInputBuffers; i++)
    {
        TRAP(err, pic = CreateBuffersL(i));
	    	if (err != KErrNone)
	    	{
	    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to create VBM buffer %d"), this, err);
	    	    User::Leave(err);
	    	}

        // This will hold the references which will be used in destructor
        User::LeaveIfError(iVBMBufferReferenceQ.Append(pic));
        User::LeaveIfError(iVBMBufferQ.Append(pic));
    }
    if(iIsColorConversionNeeded)
    {
		    for(TInt i = iVBMBufferOptions.iNumInputBuffers ; 
		    				 i < (iVBMBufferOptions.iNumInputBuffers + KColorConversionBuffers ); i++)
		    {
		        TRAP(err, pic = CreateBuffersL(i));
			    	if (err != KErrNone)
			    	{
			    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to create VBM buffer %d"), this, err);
			    	    User::Leave(err);
			    	}
		
		        // This will hold the references which will be used in destructor
		        User::LeaveIfError(iVBMBufferReferenceQ.Append(pic));
		        User::LeaveIfError(iColorConversionQ.Append(pic));
		    }
		}
	    
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]::CreateVBMBuffersL --"), this);
}

void CNGAPostProcHwDevice::ReturnPicToDecoder(TVideoPicture* aPic)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReturnPicToDecoder ++"), this);
	if (aPic == NULL)
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseInputPicture FAILED: Invalid pic ptr."), this);
		return;
	}
	
   	if (iInputDecoderDevice)
    {
       PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseInputPicture .. before return picture. 2"), this);
        iInputDecoderDevice->ReturnPicture(aPic);
    }
	
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReturnPicToDecoder --"), this);
}

TInt CNGAPostProcHwDevice::AttemptToPost()
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AttemptToPost ++ Q:%d"), this, iInputQ.Count());
   if (iPPState == EPaused)
   {
        return KErrNone;
   }

    TInt err = KErrNotReady;
    TInt count = iInputQ.Count();
    TBool bDone = EFalse;
    TVideoPicture* pic = PeekQ();   		
  	while(pic && !bDone)
  	{
	    if(!IsGceReady())
		{  
			PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AttemptToPost GCE not ready"), this );
			return err; //no need to catch this error
		}
		TInt64 delta = 0;
		TTimeToPost	iTimeToPost = (TTimeToPost)IsTimeToPost(pic, delta);
		switch(iTimeToPost)
		{
			case EDelayIt:
			{
				iPostingTimer->Cancel();
				SetTimer(delta);
				bDone = ETrue;
			}
			break;
			case EPostIt:
			{
				RemoveFromQ(); // remove the pic that was returned by PeekQ				
				if(iIsColorConversionNeeded)
				{
				    TVideoPicture* ccPic;
    				ccPic = DoColorConvert(pic); // output will be in ccPic
    				pic = ccPic;
			    }
				iProcessQ.Append(pic);
                #ifdef _DUMP_YUV_FRAMES
                    captureYuv(pic);
                #endif
				iSessionManager->PostPicture(iSurfaceId, GetID(pic), iInfo().iBuffers, ETrue); 
				iCurrentPlaybackPosition = pic->iTimestamp;						 					
				if(!iFirstPictureUpdated)
				{
					iFirstPictureUpdated = ETrue;
                    if(!iSurfaceCreatedEventPublished)
                    {
                        PublishSurfaceCreated();
                    }
				}	
			}	// end of postit
			break;
			case ESkipIt: 
			{
				RemoveFromQ();
				ReleasePicture(pic);
				PicturesSkipped();				
			}
			break;
		} // end of switch
		
		// get the next picture
		pic = PeekQ();	
    } // end of while
    
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AttemptToPost --"), this);
 	return err;
}

TInt CNGAPostProcHwDevice::IsTimeToPost(TVideoPicture* frame, TInt64& delta)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:IsTimeToPost ++"), this);

    if (!frame)
    {
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:IsTimeToPost FAILED: Invalid frame ptr."), this);
		return KErrGeneral;
	}

    TInt resp = EPostIt;
    // Frame presentation time
    TInt64 uPresTime = frame->iTimestamp.Int64();
      
    // Check if this is an out of order frame in case of forward playback
    if((iCurrentPlaybackPosition.Int64() > uPresTime) && (iPlayRate > 0))    
    {      
         PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:IsTimeToPost : Out of order frame (forward playback) Tfm=%d"), this,(TInt)uPresTime);
         resp = ESkipIt;  //drop      
    }      // Check if this is an out of order frame in case of backward playback
    else if((iCurrentPlaybackPosition.Int64() < uPresTime) && (iPlayRate < 0))    
    {      
        PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:IsTimeToPost : Out of order frame (backward playback) Tfm=%d"), this,(TInt)uPresTime);
        resp = ESkipIt;  //drop      
    }
    else if (iClockSource)
    {
        // The time to sync with.
        TInt64 uSyncTime = iClockSource->Time().Int64();
        
        delta = uPresTime - uSyncTime;
        if (( delta > KRenderAhead ) &&  (iPlayRate > 0))	// Delay condition not checked for 
        {													// backward playback
        	resp = EDelayIt;  //wait
        }
        else if ( (delta < (-KMaxRenderDelay) && (iPlayRate > 0))
          		||  ((delta > KMaxRenderDelay) && (iPlayRate < 0)))
        {
            resp = ESkipIt;  //drop
        }
       PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:IsTimeToPost .. Tfm=%d, Tcs=%d, delta=%d"), this, (TInt)uPresTime, (TInt)uSyncTime, (TInt)delta);
    }       
   
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:IsTimeToPost -- %d BufID = %d"), this, resp, GetID(frame));
    return resp;
}

void CNGAPostProcHwDevice::ReleaseInputQ()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseInputQ ++ Q = %d"), this, iInputQ.Count());
    while (iInputQ.Count()>0)
    {
    	ReleasePicture(iInputQ[0]);
        iInputQ.Remove(0);
    }
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseInputQ --"), this);
}

void CNGAPostProcHwDevice::ReleaseProcessQ()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseProcessQ ++ Q = %d"), this, iProcessQ.Count() );
	TVideoPicture* pic = NULL;
	
    while (iProcessQ.Count()>0)
    {
		pic = iProcessQ[0];
		iProcessQ.Remove(0);
		ReturnPicToDecoder(pic);
    }
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseProcessQ --"), this);
}

void CNGAPostProcHwDevice::ReleasePicture(TVideoPicture *pic)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleasePicture ++"), this);
	if (pic == NULL)
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseInputPicture FAILED: Invalid pic ptr."), this);
		return;
	}
	
   	if (iInputDecoderDevice)
    {
       PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleaseInputPicture .. before return picture. 2"), this);
        iInputDecoderDevice->ReturnPicture(pic);
    }
	if (iVBMEnabled)
    {
        iVBMBufferQ.Append(pic);

        if ( !iIsInputEnded && iPPState != EStopped )
        {
            iVBMObserver->MmvbmoNewBuffers();
        }
	}
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ReleasePicture --"), this);
}

void CNGAPostProcHwDevice::PublishSurfaceCreated()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:PublishSurfaceCreated ++"), this);   
	if(iVideoSurfaceObserver)
	{
		iVideoSurfaceObserver->MmvsoSurfaceCreated();
		iSurfaceCreatedEventPublished = ETrue;
	}
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:PublishSurfaceCreated --"), this);
}

TInt CNGAPostProcHwDevice::SetupSurface(const TSize& aSize)
{
	TInt err = KErrNone;
	if(iVBMEnabled && iVBMObserver)
    {
    	SetSurfaceAttributes(aSize, KMaxVBMBuffers);
	    iVBMBufferOptions.iNumInputBuffers    = KMaxVBMBuffers;
	    
	    //Decoder needs the buffer size to fit in yuv422 decoded output.
	    iVBMBufferOptions.iBufferSize = aSize;
    	
	  	err = iSurfaceHandler->CreateSurface(iAttributes, iSurfaceId);
	  	if (err != KErrNone)
    	{
    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to create Surface %d"), this, err);
    	    return err;
    	}
    	err = iSurfaceHandler->MapSurface(iSurfaceId, iChunk);
    	if (err != KErrNone)
    	{
    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to map Surface %d"), this, err);
    	  	iSurfaceHandler->DestroySurface(iSurfaceId);
	   		iSurfaceId = TSurfaceId::CreateNullId();
    	    return err;
    	}
    	err = iSurfaceHandler->SurfaceInfo(iSurfaceId, iInfo);
    	if (err != KErrNone)
    	{
    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to get Surface info %d"), this, err);
    	   	iSurfaceHandler->DestroySurface(iSurfaceId);
	   		iSurfaceId = TSurfaceId::CreateNullId();
    	    return err;
    	}
    	TRAP(err, CreateVBMBuffersL());
    	if (err != KErrNone)
    	{
    	   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to create VBM buffer %d"), this, err);
    	   	iSurfaceHandler->DestroySurface(iSurfaceId);
	   		iSurfaceId = TSurfaceId::CreateNullId();
    	    return err;
    	}
        err = AddHints();
        if (err != KErrNone)
        {
            PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to AddHints %d"), this, err);
            return err;
        }
        err = RegisterSurface(iSurfaceId);
        if (err != KErrNone)
        {
            PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:Initialize -- failed to RegisterSurface %d"), this, err);
            iSurfaceHandler->DestroySurface(iSurfaceId);
            iSurfaceId = TSurfaceId::CreateNullId();
            return err;
        }

    }
    return err;
} 

void CNGAPostProcHwDevice::SetSurfaceAttributes(const TSize& aSize, TInt aNumBuf)
{
	iAttributes().iSize                   = aSize; // size of the video frame
    iAttributes().iBuffers            	  = aNumBuf;
    
    /* The stride needs to be calculated for the surface manager to know
    how much memory to allocate */
    
    if(iAttributes().iPixelFormat == EUidPixelFormatYUV_420Planar)
    	{
    		iAttributes().iStride       = aSize.iWidth * 3/2;
    		iVideoFrameBufSize			= aSize.iWidth * aSize.iHeight * 3/2;
    	}
    	else
    	{
    		iAttributes().iStride       = aSize.iWidth * 2;
    		iVideoFrameBufSize			= aSize.iWidth * aSize.iHeight * 2;
    	}
    		
    if(iIsColorConversionNeeded)
    {
    	iAttributes().iBuffers            = aNumBuf + KColorConversionBuffers;
    }
    else
    {
    	iAttributes().iBuffers            = aNumBuf;	
    }
    
    iAttributes().iOffsetToFirstBuffer    = 0;
    iAttributes().iAlignment              = 4;
    iAttributes().iContiguous             = ETrue;
    iAttributes().iHintCount              = 0;
    iAttributes().iMappable               = ETrue;
}

TInt CNGAPostProcHwDevice::GetID(TVideoPicture *aPicture)
{
    if (iUsingExternalSurface)
    {
	    return GetExternalBufferID(aPicture);
    }
    else
    {
        TUint8* aPtr = (TUint8*) aPicture->iData.iRawData->Ptr();
        return( (TInt) ((aPtr - iChunk.Base() - iAttributes().iOffsetToFirstBuffer) / 
			(iVideoFrameBufSize )));
    }
}

TInt CNGAPostProcHwDevice::GetExternalBufferID(TVideoPicture *aPicture)
{
    // currently type cast the pointer as buffer ID.
    // FIXME once the new data structure is available.
    return( (TInt) aPicture->iData.iRawData->Ptr());
}

TInt CNGAPostProcHwDevice::RegisterSurface(const TSurfaceId& aSurfaceId)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:RegisterSurface(): RegisterSurface ID = 0x%x"), this, aSurfaceId);
	TInt err = KErrNone;
	TInt numScreens = iWsSession.NumberOfScreens();
	for(TInt i=0; (i < numScreens && err == KErrNone); i++)
	{
		err = iWsSession.RegisterSurface(i, aSurfaceId);
	}	
	return(err);
}

TInt CNGAPostProcHwDevice::IsGceReady()
{
    if(iProcessQ.Count() >= KMaxBuffersGceCanHold)
    {
    		return EFalse;
    }
    return ETrue;
}

void CNGAPostProcHwDevice::SetTimer(TInt64 aDelta)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetTimer .. aDelta=%d"), this, (TInt)aDelta);
	if(aDelta <= KRenderAhead)
	{
		if(aDelta < 0)
		{
			iPostingTimer->After(aDelta * -1);
		}
		else
		{
			iPostingTimer->After((aDelta - KRenderAhead) * -1);
		}
	}
	else
	{
		iPostingTimer->After(aDelta - KRenderAhead - KPostingOfset);
	}
}
//
// Convert YUV420 to YUV422InterLeaved.
//
TInt CNGAPostProcHwDevice::ConvertPostProcBuffer(TVideoPicture* pSrc, TVideoPicture* pDest)
{
    PP_DEBUG(_L("CMdfPostingSurfaceProxy::ConvertPostProcBuffer ++"));
    TInt err = KErrNone;
    if (!pDest && !pSrc)
	{
		PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ConvertPostProcBuffer FAILED: Invalid pic pSrc %x pDest %x."), this, pSrc, pDest);
		return KErrArgument;
	}
    
    // --- Prepare wrappers ---
    tBaseVideoFrame tFrame420, tFrame422;
    TInt    frameSize = pSrc->iData.iDataSize.iWidth * pSrc->iData.iDataSize.iHeight;

   PP_DEBUG(_L("CMdfPostingSurfaceProxy::ConvertPostProcBuffer .. w=%d, h=%d"), pSrc->iData.iDataSize.iWidth, pSrc->iData.iDataSize.iHeight);

    tFrame420.width = pSrc->iData.iDataSize.iWidth;
    tFrame420.height= pSrc->iData.iDataSize.iHeight;
    tFrame420.lum   = (TUint8*)pSrc->iData.iRawData->Ptr();
    tFrame420.cb    = (TUint8*)tFrame420.lum + frameSize;
    tFrame420.cr    = (TUint8*)tFrame420.lum + (frameSize*5)/4;
    
    tFrame422.width = pSrc->iData.iDataSize.iWidth;
    tFrame422.height= pSrc->iData.iDataSize.iHeight;
    tFrame422.lum   = (TUint8*)pDest->iData.iRawData->Ptr();
    tFrame422.cb    = 0;
    tFrame422.cr    = 0;
    
    // --- Convertion to posting buffer ---
    TInt stride     = pSrc->iData.iDataSize.iWidth * 2;
    EBufferLayout422 layout = YUV422INT_BE;
        
    err = gColorConvYUVtoYUV422Int(&tFrame420, &tFrame422, layout, stride);
    if(err != KErrNone)
    {
    		PP_DEBUG(_L("CNGAPostProcHwDevice::ConvertPostProcBuffer .. err= %d."), err);
    }
	return err;
}   

void CNGAPostProcHwDevice::AddPictureToVBMQ(TVideoPicture *pic)
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddPictureToVBMQ ++"), this);
    iVBMBufferQ.Append(pic);

    if ( !iIsInputEnded && iPPState != EStopped )
    {
        iVBMObserver->MmvbmoNewBuffers();
    }
	
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddPictureToVBMQ --"), this);
}

void CNGAPostProcHwDevice::AddPictureToColorConversionQ(TVideoPicture *pic)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddPictureToColorConversionQ ++"), this);
    iColorConversionQ.Append(pic);
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddPictureToColorConversionQ --"), this);
}

#ifdef _DUMP_YUV_FRAMES
void CNGAPostProcHwDevice::captureYuv(TVideoPicture* aPicture)
{
	char buf[128];              
	sprintf(buf, "c:\\fb%d.yuv", count++);          
	FILE *fp = ::fopen(buf, "w");
	TInt size = aPicture->iData.iRawData->Size();
	//{FILE* f1 = fopen(MY_LOG_FILE_NAME, "a+"));if(f1){fprintf(f1, "Size  %d \n"), size );fclose(f1); }}

	::fwrite(aPicture->iData.iRawData->Ptr(), 1, size, fp);
	::fclose(fp);    	
}
#endif

void CNGAPostProcHwDevice::ResetCountingBuffer()
{       
	memset(iSkippedFramesCountingBuffer,0,sizeof(iSkippedFramesCountingBuffer));
    iSkippedFramesInLast64Frames = 0;       
    iCurrentPosInFramesCountingBuffer = 0;       
} 

void CNGAPostProcHwDevice::PicturesSkipped()
{       
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:PicturesSkipped ++"), this);
	iPictureCounters.iPicturesSkipped++;
	if (!iKeyFrameMode && iPlayRate>KDefPlayRate)
    {       
    	if (iSkippedFramesCountingBuffer[iCurrentPosInFramesCountingBuffer]==0)        
        {       
        	iSkippedFramesCountingBuffer[iCurrentPosInFramesCountingBuffer] = 1;       
            iSkippedFramesInLast64Frames++;       
            if (iSkippedFramesInLast64Frames>KMaxAllowedSkipInNFrames && iFPObserver )       
            {       
            	iFPObserver->MmvproKeyFrameModeRequest();       
                iKeyFrameMode=ETrue;       
                ResetCountingBuffer();       
            }       
        }       
        iCurrentPosInFramesCountingBuffer = ++iCurrentPosInFramesCountingBuffer%64;       
    }
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:PicturesSkipped --"), this);   
}

TVideoPicture* CNGAPostProcHwDevice::DoColorConvert(TVideoPicture* aPicture)
{
    TVideoPicture *pOutPicture  = aPicture;
    					    		
	if(iColorConversionQ.Count())
    {
	    pOutPicture    = iColorConversionQ[0];
	    iColorConversionQ.Remove(0);
	    ConvertPostProcBuffer(aPicture, pOutPicture);
	   	pOutPicture->iTimestamp = aPicture->iTimestamp;
	    ReleasePicture(aPicture);    	    
    }				    
    else
    {
       PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:WritePictureL() FAILED: color conversion"), this);
    }

	return pOutPicture;
}

TInt CNGAPostProcHwDevice::AddToQ(TVideoPicture* aPicture)
{
	TVideoPicture* pic = aPicture;
	TInt pos = -1;
	if(iInputQ.Count() == 0)
	{
		iInputQ.Append(pic);
	}
	else
	{
		pos = iInputQ.Count()-1;
		for(; pos >= 0; pos--)
		{
			if(pic->iTimestamp.Int64() > iInputQ[pos]->iTimestamp.Int64())
			{
				break;
			}
		} 
		if(iInputQ.Count() == pos+1)
		{
			iInputQ.Append(pic);
		}
		else
		{
			iInputQ.Insert(pic, pos+1);
		}
	}
	return pos+1;
}

void CNGAPostProcHwDevice::RemoveFromQ()
{
	if(iInputQ.Count())
	{
		if(iPlayRate > 0)
		{
			iInputQ.Remove(0);
		}
		else
		{
			iInputQ.Remove(iInputQ.Count()-1);
		}
	}
}

TVideoPicture* CNGAPostProcHwDevice::PeekQ()
{	
	TVideoPicture *pic = NULL;
	if(iInputQ.Count())
	{
		if(iPlayRate > 0)
		{			
			pic = iInputQ[0];
		}
		else
		{			
			pic = iInputQ[iInputQ.Count()-1];
		}	
	}
	return pic;
}

TInt CNGAPostProcHwDevice::AddHints()
{
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddHints iSurfaceMask 0x%08x ++"), this, iSurfaceMask);
   TInt err = KErrNone;
   iHint.Set(iSurfaceKey,iSurfaceMask,ETrue);
   err = iSurfaceHandler->AddSurfaceHint(iSurfaceId,iHint);
   if(err == KErrAlreadyExists)
   {
		err = KErrNone;
		err = iSurfaceHandler->SetSurfaceHint(iSurfaceId,iHint);
   }
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddHints. err = %d --"), this,err);
   iHint.iKey.iUid = surfaceHints::KSurfaceContent;
   iHint.iValue = surfaceHints::EVideoPlayback;
   iHint.iMutable = ETrue;
   err = iSurfaceHandler->AddSurfaceHint(iSurfaceId,iHint);
   if(err == KErrAlreadyExists)
   {
		err = KErrNone;
		err = iSurfaceHandler->SetSurfaceHint(iSurfaceId,iHint);
   }
   PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:AddHints. err = %d --"), this,err);
   return err;
}

TInt CNGAPostProcHwDevice::ColorConvert(tBaseVideoFrame* aInputFrame, TUint8* aDestPtr, tWndParam* aInputCropWindow, tWndParam* aOutputCropWindow)
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ColorConvert ++"), this);
	__ASSERT_ALWAYS(aDestPtr, User::Invariant());
	TInt				lError = E_SUCCESS;
	TInt				err = KErrNone;
	
	err = SetSourceFormat();
	if(err == KErrNone)
	{
    	err = SetSourceRange();
    	if(err == KErrNone)
    	{
						
			lError = Emz_VDec_gColorConv_YUVtoRGB(aInputFrame,aDestPtr, 
						aInputCropWindow, aOutputCropWindow, iSourceFormat,
						EBitmapColor16MU, iSourceRange);

			if(lError)
			{
				if(lError == E_OUT_OF_MEMORY)
					{
					err = KErrNoMemory;
					}
				else if(lError == E_FAILURE)
					{
					err = KErrNotSupported;
					}
				else
					{
					err = KErrGeneral;
					}
			}
		}
	}
	
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:ColorConvert --"), this);
	return err;
}

TInt CNGAPostProcHwDevice::SetSourceFormat()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetSourceFormatL ++"), this);
	TInt err = KErrNone;
	switch (iVideoFormat.iYuvFormat.iPattern)
	{
	    case EYuv420Chroma1:
    		iSourceFormat = EYuv420Chroma1_Planar;
    		break;
        case EYuv420Chroma2:
    		iSourceFormat = EYuv420Chroma2_Planar;
    		break;
        case EYuv420Chroma3:
    		iSourceFormat = EYuv420Chroma3_Planar;
    		break;
	    case EYuv422Chroma1:
			if( iVideoFormat.iYuvFormat.iDataLayout == EYuvDataInterleavedLE)
    			iSourceFormat = EYuv422Chroma1_LE;
	    	else if( iVideoFormat.iYuvFormat.iDataLayout == EYuvDataInterleavedBE )
				iSourceFormat = EYuv422Chroma1_BE;
			else
			    err = KErrArgument;
			break;
    	case EYuv422Chroma2:
    		if( iVideoFormat.iYuvFormat.iDataLayout == EYuvDataInterleavedLE)
	    		iSourceFormat = EYuv422Chroma2_LE;
    		else if( iVideoFormat.iYuvFormat.iDataLayout == EYuvDataInterleavedBE )
    			iSourceFormat = EYuv422Chroma2_BE;
			else
			    err = KErrArgument;
			break;
      default:
    		err = KErrNotSupported;
	}
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetSourceFormatL --"), this);
	return err;
}


TInt CNGAPostProcHwDevice::SetSourceRange()
{
	PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetSourceRangeL ++"), this);
	TInt err = KErrNone;
	switch (iVideoFormat.iYuvFormat.iCoefficients)
	{
	    case EYuvBt601Range0:
			iSourceRange = EITU601_5_REDUCEDRANGE;
            break;
        case EYuvBt601Range1:
			iSourceRange = EITU601_5_FULLRANGE;
			break;
        case EYuvBt709Range0:
			iSourceRange = EB709_REDUCEDRANGE;
			break;
        case EYuvBt709Range1:
			iSourceRange = EB709_FULLRANGE;
            break;
	    default:
		    err = KErrNotSupported;
    }
    PP_DEBUG(_L("CNGAPostProcHwDevice[%x]:SetSourceRangeL --"), this);
    return err;
}

CNGAPostProcTimer::CNGAPostProcTimer( CNGAPostProcHwDevice& aParent )
:CTimer(EPriorityHigh),iParent(aParent)
{
	CActiveScheduler::Add(this);
}

CNGAPostProcTimer::~CNGAPostProcTimer()
{
	PP_DEBUG(_L("CNGAPostProcTimer[%x]:~CNGAPostProcTimer ++"), this);
	Cancel();
	PP_DEBUG(_L("CNGAPostProcTimer[%x]:~CNGAPostProcTimer --"), this);
}

CNGAPostProcTimer* CNGAPostProcTimer::NewL( CNGAPostProcHwDevice& aParent )
{
	CNGAPostProcTimer* self = new (ELeave)CNGAPostProcTimer(aParent);
	CleanupStack::PushL( self );
	self->ConstructL();
	CleanupStack::Pop( self );
	return self;
}

void CNGAPostProcTimer::ConstructL()
{
	CTimer::ConstructL();
}

void CNGAPostProcTimer::RunL()
{
	PP_DEBUG(_L("CNGAPostProcTimer[%x]:RunL ++"), this);
	if (iStatus ==KErrCancel)
	{
		PP_DEBUG(_L("CNGAPostProcNotifier[%x]:CNGAPostProcNotifier:RunL State canceled"), this);
		return;
	}
	iParent.AttemptToPost();
	PP_DEBUG(_L("CNGAPostProcTimer[%x]:RunL --"), this);
}

