vtprotocolplugins/DisplaySink/src/CDisplaySink.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 23 Nov 2009 14:47:47 +0200
changeset 0 ed9695c8bcbe
permissions -rw-r--r--
Revision: 200948

/*
* 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:  Display Sink subsystem.
*
*/


// INCLUDE FILES

#include "CDisplaySink.h"
#include "CDisplaySinkDP.h"
#include "CDisplaySinkDSA.h"
#include "CDisplaySinkNGA.h"
#include <mmffourcc.h>
#include <featmgr.h>

// CONSTANTS

// MACROS

#ifdef _DEBUG
    #include <e32debug.h>
    #define PRINT RDebug::Print
    #define _IFDBG(a) a
#else
    #define PRINT
    #define _IFDBG(a)
#endif

// ============================ MEMBER FUNCTIONS ===============================

// ============================= CVtFrameQueue =================================

// -----------------------------------------------------------------------------
// CVtFrameQueue::CVtFrameQueue
// -----------------------------------------------------------------------------
//
CVtFrameQueue::CVtFrameQueue() : CActive( EPriorityNormal )
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::CVtFrameQueue<" ) ));
    _IFDBG(PRINT( _L( "CVtFrameQueue::CVtFrameQueue>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::ThreadLogon
// -----------------------------------------------------------------------------
//
TInt CVtFrameQueue::ThreadLogon()
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::ThreadLogon<" ) ));
    if ( !IsAdded() )
        {
        CActiveScheduler::Add( this );
        }
    TInt result( iThread.Open( RThread().Id() ) );
    _IFDBG(PRINT( _L( "CVtFrameQueue::ThreadLogon %d >" ), result ));
    return result;
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::SinkStoppedL
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::SinkStoppedL()
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::SinkStoppedL<" ) ));
    DoReleaseBufferL( iBuffer );
    DoReleaseBufferL( iReleaseBuffer );
    _IFDBG(PRINT( _L( "CVtFrameQueue::SinkStoppedL>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::ThreadLogoff
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::ThreadLogoff()
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::ThreadLogoff<" ) ));
    if ( IsAdded() )
        {
        Deque();
        }
    _IFDBG(PRINT( _L( "CVtFrameQueue::ThreadLogoff>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::Store
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::Store( MVTVideoSource& aSupplier,
    CMMFDataBuffer* aBuffer,
    TSize aFrameSize, 
    TPtr8& aPtr )
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::Store<" ) ));
    iSupplier = &aSupplier;
    iBuffer = aBuffer;
    iFrameSize = aFrameSize;
    iPtr = &aPtr;
    _IFDBG(PRINT( _L( "CVtFrameQueue::Store>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::IsStored
// -----------------------------------------------------------------------------
//
TBool CVtFrameQueue::IsStored() const
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::IsStored<" ) ));
    _IFDBG(PRINT( _L( "CVtFrameQueue::IsStored %d>" ),
        ( iBuffer != NULL ) ));
    return ( iBuffer != NULL );
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::Buffer
// -----------------------------------------------------------------------------
//
TVtMMFDataBuffer CVtFrameQueue::Buffer()
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::Buffer<" ) ));
    _IFDBG(PRINT( _L( "CVtFrameQueue::Buffer %d>" ),
        reinterpret_cast< TUint >( iBuffer ) ));
    return TVtMMFDataBuffer(iBuffer, iFrameSize, *iPtr);
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::Release
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::Release()
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::Release<" ) ));
    if ( !IsActive() && IsStored() )
        {
        iReleaseBuffer = iBuffer;
        iBuffer = NULL;
        iStatus = KRequestPending;
        TRequestStatus* pStatus = &iStatus;
        SetActive();
        iThread.RequestComplete( pStatus, KErrNone );
        _IFDBG(PRINT( _L( "CVtFrameQueue::Release -done-" ) ));
        }
    _IFDBG(PRINT( _L( "CVtFrameQueue::Release>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::RunL
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::RunL()
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::RunL<" ) ));
    DoReleaseBufferL( iReleaseBuffer );
    _IFDBG(PRINT( _L( "CVtFrameQueue::RunL>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::DoReleaseBufferL
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::DoReleaseBufferL( CMMFDataBuffer*& aBuffer )
    {
    _IFDBG(PRINT( _L( "CVtFrameQueue::DoReleaseBufferL<" ) ));
    if ( aBuffer && iSupplier )
        {
        iSupplier->BufferEmptiedL( aBuffer );
        aBuffer = NULL;
        }
    _IFDBG(PRINT( _L( "CVtFrameQueue::DoReleaseBufferL>" ) ));
    }

// -----------------------------------------------------------------------------
// CVtFrameQueue::DoCancel
// -----------------------------------------------------------------------------
//
void CVtFrameQueue::DoCancel()
    {
    // nothing to do
    }

// ============================ CVtCallback =================================

// -----------------------------------------------------------------------------
// CVtCallback::CVtCallback( MDisplaySinkObserver& aObserver )
// -----------------------------------------------------------------------------
//
CVtCallback::CVtCallback( MDisplaySinkObserver& aObserver )
: CActive( EPriorityStandard ), iObserver( &aObserver )
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::CVtCallback()<"), RThread().Id().operator TUint()));
    CActiveScheduler::Add( this );
    iOwnThreadId = RThread().Id();
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::CVtCallback()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CVtCallback::~CVtCallback()
// -----------------------------------------------------------------------------
//
CVtCallback::~CVtCallback()
    {
    Cancel();
    }

// -----------------------------------------------------------------------------
// CVtCallback::VideoFrameSizeChangedL( const TSize& aFrom, const TSize& aTo )
// -----------------------------------------------------------------------------
//
void CVtCallback::VideoFrameSizeChangedL( const TSize& aFrom, const TSize& aTo )
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::VideoFrameSizeChangedL()<"), RThread().Id().operator TUint()));
    iCallBackType = EVideoFrameSizeChanged;
    iFrom = aFrom;
    iTo = aTo;
    IssueCallbackL();
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::VideoFrameSizeChangedL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CVtCallback::Result() const
// -----------------------------------------------------------------------------
//
TInt CVtCallback::Result() const
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::Result()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::Result()>"), RThread().Id().operator TUint()));
    return iResult;
    }

// -----------------------------------------------------------------------------
// CVtCallback::Completed() const
// -----------------------------------------------------------------------------
//
TBool CVtCallback::Completed() const
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::Completed()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::Completed()>"), RThread().Id().operator TUint()));
    return iCompleted;
    }

// -----------------------------------------------------------------------------
// CVtCallback::IssueCallbackL()
// -----------------------------------------------------------------------------
//
void CVtCallback::IssueCallbackL()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::IssueCallbackL()<"), RThread().Id().operator TUint()));
    iCompleted = EFalse;
    TRequestStatus* pStatus = &iStatus;
    RThread thread;
    if( thread.Id() == iOwnThreadId )
        {
        SetActive();
        User::RequestComplete( pStatus, KErrNone );
        }
    else
        {
        User::LeaveIfError( thread.Open( iOwnThreadId ) );
        SetActive();
        *pStatus = KRequestPending;
        thread.RequestComplete( pStatus, KErrNone );
        thread.Close();
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::IssueCallbackL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CVtCallback::RunL()
// -----------------------------------------------------------------------------
//
void CVtCallback::RunL()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::RunL()<"), RThread().Id().operator TUint()));

    iResult = KErrNone;

    switch( iCallBackType )
        {
        case EVideoFrameSizeChanged:
            iObserver->VideoFrameSizeChangedL( iFrom, iTo );
            break;

        default:
            User::Leave( KErrArgument );
        }

    iCompleted = ETrue;

    _IFDBG(PRINT(_L("VideoSource[%d]: CVtCallback::RunL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CVtCallback::DoCancel()
// -----------------------------------------------------------------------------
//
void CVtCallback::DoCancel()
    {
    // do nothing!
    }

// -----------------------------------------------------------------------------
// CVtCallback::RunError( TInt aError )
// -----------------------------------------------------------------------------
//
TInt CVtCallback::RunError( TInt aError )
    {
    iCompleted = ETrue;
    iResult = aError;
    return KErrNone;
    }

// ========================== TDisplaySinkParams ===============================

// -----------------------------------------------------------------------------
// TDisplaySinkParams::TDisplaySinkParams
// -----------------------------------------------------------------------------
//
EXPORT_C TDisplaySinkParams::TDisplaySinkParams() :
    iFrameRateLimit( EFrameRateLimitNone )
    {
    }


// ============================ CDisplaySink ===================================

// -----------------------------------------------------------------------------
// CDisplaySink::~CDisplaySink
// -----------------------------------------------------------------------------
//
CDisplaySink::~CDisplaySink()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::~CDisplaySink()<"), RThread().Id().operator TUint()));
	delete iVideoFrameQueue;
	iBitmapCS.Close();
    delete iVTSignaller;
    iVTMimeTypes.Reset();
	iVTMimeTypes.Close();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::~CDisplaySink()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::ConstructL
// -----------------------------------------------------------------------------
//
void CDisplaySink::ConstructL( TDisplaySinkParams& aParams,
    const TDesC8& aInitData )
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ConstructL()<"), RThread().Id().operator TUint()));
    iDSFlags = aParams.iFlags;
    iYuv420PlanarDesc.Delete( 0, iYuv420PlanarDesc.Length() );
    iYuv420PlanarDesc.Append( KVtVideoMIMETypeYUV420 );
    User::LeaveIfError( iVTMimeTypes.Append( &iYuv420PlanarDesc ) );
    iVideoFrameQueue = new ( ELeave ) CVtFrameQueue();
    iVTSignaller = new ( ELeave ) CVtCallback( *aParams.iObserver );
	BitmapEntry( EFirstBitmap ).iIsFree = EFalse;
	BitmapEntry( ESecondBitmap ).iIsFree = EFalse;
	iThreadId = aParams.iThreadId;
	iRequestStatusPtr = aParams.iRequestStatusPtr;
    iFrameSize = QCIF;
    SetFrameRateLimit( aParams.iFrameRateLimit );
    User::LeaveIfError( iBitmapCS.CreateLocal() );
	BaseConstructL( aParams, aInitData );
    _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ConstructL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::Destroy
// -----------------------------------------------------------------------------
//
void CDisplaySink::Destroy()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::Destroy()<"), RThread().Id().operator TUint()));
	delete this;
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::Destroy()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SetBitmapAvailable( TBitmapNo aBitmapNo )
// -----------------------------------------------------------------------------
//
void CDisplaySink::SetBitmapAvailable( TBitmapNo aBitmapNo )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetBitmapAvailable()<"), RThread().Id().operator TUint()));
	iBitmapCS.Wait();
    BitmapEntry( aBitmapNo ).iIsFree = ETrue;
    BaseSetBitmapAvailable( aBitmapNo );
    iBitmapCS.Signal();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetBitmapAvailable()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::Release
// -----------------------------------------------------------------------------
//
void CDisplaySink::Release()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::Release()<"), RThread().Id().operator TUint()));
	iBitmapCS.Wait();
	if( !iReleased  )
		{
		iReleased = ETrue;
		if( iRequestStatusPtr != NULL &&
		    (*iRequestStatusPtr) == KRequestPending )
			{
			RThread thread;
			TInt err = thread.Open( iThreadId );
			if( err == KErrNone )
				{
				*iRequestStatusPtr = KRequestPending;
				TRequestStatus* statusP = iRequestStatusPtr;
				thread.RequestComplete( statusP, KErrCancel );
    			thread.Close();
				}
			}
		}
	iVideoFrameQueue->Release();
	iBitmapCS.Signal();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::Release()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::UpdateSinkParamsL( const TDisplaySinkParams& aParams,
//  TBool& aUpdated )
// -----------------------------------------------------------------------------
//
void CDisplaySink::UpdateSinkParamsL(
    const TDisplaySinkParams& aParams, TBool& aUpdated )
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::UpdateSinkParamsL()<"), RThread().Id().operator TUint()));
	// This modification was requested by the VT engine team
	iReleased = EFalse;
	// This modification was requested by the VT engine team
    iBitmapCS.Wait();
    BaseUpdateSinkParamsL( aParams );
    aUpdated = EFalse;
    iParamsUpdated = &aUpdated;
    iDSFlags = aParams.iFlags;
    BitmapEntry( EFirstBitmap ).iIsFree = EFalse;
	BitmapEntry( ESecondBitmap ).iIsFree = EFalse;
	iVideoFrameQueue->Release();
    iBitmapCS.Signal();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::UpdateSinkParamsL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::Pause()
// -----------------------------------------------------------------------------
//
void CDisplaySink::Pause()
    {
    iBitmapCS.Wait();
    iPaused = ETrue;
    iVideoFrameQueue->Release();
    iBitmapCS.Signal();
    }

// -----------------------------------------------------------------------------
// CDisplaySink::Resume()
// -----------------------------------------------------------------------------
//
void CDisplaySink::Resume()
    {
    iBitmapCS.Wait();
    iPaused = EFalse;
    iBitmapCS.Signal();
    }

// -----------------------------------------------------------------------------
// CDisplaySink::operator MVTVideoSink&()
// -----------------------------------------------------------------------------
//
CDisplaySink::operator MVTVideoSink&()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::operator MVTVideoSink&()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::operator MVTVideoSink&()>"), RThread().Id().operator TUint()));
    return *this;
    }

// -----------------------------------------------------------------------------
// CDisplaySink::NextFrame
// -----------------------------------------------------------------------------
//
void CDisplaySink::NextFrame()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::NextFrame()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::NextFrame()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::GetMultimediaTypesL() const
// -----------------------------------------------------------------------------
//
const RArray<TDesC8* >& CDisplaySink::GetMultimediaTypesL() const
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::GetMultimediaTypeL()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::GetMultimediaTypeL()>"), RThread().Id().operator TUint()));
	return iVTMimeTypes;
	}



// -----------------------------------------------------------------------------
// CDisplaySink::SetFormatL
// -----------------------------------------------------------------------------
//
void CDisplaySink::SetFormatL( const TDesC8& aFormat )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetFormatL()<"), RThread().Id().operator TUint()));
	if ( aFormat != KVtVideoMIMETypeYUV420 )
		{
		User::Leave( KErrNotSupported );
		}
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetFormatL()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SetVideoFrameSizeL
// -----------------------------------------------------------------------------
//
void CDisplaySink::SetVideoFrameSizeL( const TSize& aSize )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetVideoFrameSizeL()<"), RThread().Id().operator TUint()));
    if ( iInitFlags & ESinkThreadLogonCalled )
        {
        SinkThreadLogonL();
        }
    if ( iInitFlags & EFbsSessionConnected )
        {
        TSize size( aSize );
        BaseSetVideoFrameSizeL( aSize );
	    iFrameSize = aSize;
	    }
    else
        {
        User::Leave( KErrNotReady );
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetVideoFrameSizeL()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::GetVideoFrameSizeL
// -----------------------------------------------------------------------------
//
void CDisplaySink::GetVideoFrameSizeL( TSize& aSize ) const
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::GetVideoFrameSizeL()<"), RThread().Id().operator TUint()));
	aSize = iFrameSize;
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::GetVideoFrameSizeL()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::EmptyBufferL
// -----------------------------------------------------------------------------
//
void CDisplaySink::EmptyBufferL(
    TVtMMFDataBuffer aDataBuffer,
    MVTVideoSource* aSupplier,
    TMediaId /*aMediaId*/ )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL()<"), RThread().Id().operator TUint()));
    if ( aDataBuffer.GetMMFBuffer() == NULL || aSupplier == NULL )
		{
		User::Leave( KErrArgument );
		}
    if ( iReleased )
        {
        _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL(): sink released, just return buffer"), RThread().Id().operator TUint()));
        aSupplier->BufferEmptiedL( aDataBuffer.GetMMFBuffer() );
        _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL()>"), RThread().Id().operator TUint()));
        return;
        }
    else if ( iInitFlags & ESinkThreadLogonCalled )
        {
        TRAPD( result, SinkThreadLogonL() );
        if ( result != KErrNone )
            {
        	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL(): SinkThreadLogonL failed %d"), RThread().Id().operator TUint(), result));
            aSupplier->BufferEmptiedL( aDataBuffer.GetMMFBuffer() );
            User::Leave( result );
            }
        }
	if ( aDataBuffer.GetMMFBuffer()->Type() != KVTUidYUVFrameBuffer )
        {
		User::Leave( KErrArgument );
		}
	if ( iState != EPlaying )
		{
		User::Leave( KErrNotReady );
		}
    iBitmapCS.Wait();

    CleanupSignalPushL( iBitmapCS );
    iBuffer = aDataBuffer.GetMMFBuffer();
	iSupplier = aSupplier;
    if ( IsOkToSendFrame() )
        {
        // Waiting for frame size update?
        if ( iWaitingForUpdate )
            {
            // Update completed?
            if ( iVTSignaller->Completed() )
                {
                // YES: If it failed then Leave
                if ( iVTSignaller->Result() != KErrNone )
                    {
                    iSupplier->BufferEmptiedL( iBuffer );
                    User::Leave( iVTSignaller->Result() );
                    }
                }
            else
                {
                // NO: Report buffer emptied and return
                iSupplier->BufferEmptiedL( iBuffer );
                CleanupStack::PopAndDestroy(); // iBitmapCS.Signal();
                return;
                }
            }

        // Is param update pending?
        if ( iParamsUpdated )
            {
            // YES: set new params
            BaseDoUpdateParamsL();
            *iParamsUpdated = ETrue;
            iParamsUpdated = 0;
            iWaitingForUpdate = EFalse;
           	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL(): params update finished"), RThread().Id().operator TUint()));
            }

        // Update YUV data descriptor size based on resolution info.
        TSize size( aDataBuffer.GetFrameSize() );
        TInt length( ( size.iWidth * size.iHeight * 12 ) / 8 );
        aDataBuffer.Data().Set( const_cast<TUint8*>( aDataBuffer.Data().Ptr() ), length, length );
        // Expected frame size same as received size?
        if ( !BaseSizesMatch( size ) )
            {
            if ( !iWaitingForUpdate )
                {
                iVTSignaller->VideoFrameSizeChangedL( iExpectedFrameSize,
                    aDataBuffer.GetFrameSize() );
                BaseVideoFrameSizeChangedL( aDataBuffer.GetFrameSize() );
                iWaitingForUpdate = ETrue;
                }
            CleanupStack::PopAndDestroy(); // iBitmapCS.Signal();
            iSupplier->BufferEmptiedL( iBuffer );
            return;
            }
        // All validation done, now it is ok to do implementation specific
        // empty buffer.
        BaseEmptyBufferL( aDataBuffer );

// debugging
// debugging
// debugging

        //iFC.PrintStatus();

// debugging
// debugging
// debugging

        _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL()>"), RThread().Id().operator TUint()));
        // No CleanupStack::PopAndDestroy() here, because cleanup is done in
        // BaseEmptyBufferL(). Reason behind this decission is that certain
        // things have to be handled either before or after cleanup and thus
        // single cleanup here is not enough.
        return;
        }
    else
        {
        _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL(): dropping frame %d < %d"), RThread().Id().operator TUint(), iMilliSecondsSinceLastFrame, iFrameRateInterval ));
        iSupplier->BufferEmptiedL( iBuffer );
        }
    CleanupStack::PopAndDestroy(); // iBitmapCS.Signal()
    _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::EmptyBufferL()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::BufferFilledL
// -----------------------------------------------------------------------------
//
void CDisplaySink::BufferFilledL( CMMFBuffer* /*aBuffer*/ )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::BufferFilledL()<"), RThread().Id().operator TUint()));
	User::Leave( KErrNotSupported );
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::BufferFilledL()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::CanCreateSinkBuffer
// -----------------------------------------------------------------------------
//
TBool CDisplaySink::CanCreateSinkBuffer()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::CanCreateSinkBuffer()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::CanCreateSinkBuffer()>"), RThread().Id().operator TUint()));
	return EFalse;
	}

// -----------------------------------------------------------------------------
// CDisplaySink::CreateSinkBufferL
// -----------------------------------------------------------------------------
//
CMMFBuffer* CDisplaySink::CreateSinkBufferL(
    TMediaId /*aMediaId*/,
    TBool& /*aReference*/ )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::CreateSinkBufferL()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::CreateSinkBufferL()>"), RThread().Id().operator TUint()));
	return NULL;
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkThreadLogon
// -----------------------------------------------------------------------------
//
TInt CDisplaySink::SinkThreadLogon( MAsyncEventHandler& /*aEventHandler*/ )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogon()<"), RThread().Id().operator TUint()));
    iInitFlags |= ESinkThreadLogonCalled;
    _IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogon()>"), RThread().Id().operator TUint()));
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkThreadLogonL
// -----------------------------------------------------------------------------
//
void CDisplaySink::SinkThreadLogonL()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogonL()<"), RThread().Id().operator TUint()));
    TInt result( FbsStartup() );
    if ( result == KErrNone )
        {
        CleanupStack::PushL( TCleanupItem( &SinkThreadLogonCleanup, this ) );
        FbsConnectL();
        ThreadOpenL();
        User::LeaveIfError( iVideoFrameQueue->ThreadLogon() );
        BaseSinkThreadLogonL();
        iInitFlags &= ~ESinkThreadLogonCalled;
        CleanupStack::Pop(); // TCleanupItem( &SinkThreadLogonCleanup, this )
        }
    User::LeaveIfError( result );
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogonL()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkThreadLogoff
// -----------------------------------------------------------------------------
//
void CDisplaySink::SinkThreadLogoff()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogoff()<"), RThread().Id().operator TUint()));
	BaseSinkThreadLogoff();
	iVideoFrameQueue->ThreadLogoff();
    ThreadClose();
    FbsDisconnect();
    iInitFlags = 0;
    iExpectedFrameSize = TSize();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogoff()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkPrimeL
// -----------------------------------------------------------------------------
//
TInt CDisplaySink::SinkPrimeL()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkPrimeL()<"), RThread().Id().operator TUint()));
	if ( iState != EStopped )
		{
		return KErrNone;
		}
    iState = EPrimed;
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkPrimeL()>"), RThread().Id().operator TUint()));
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkPlayL
// -----------------------------------------------------------------------------
//
TInt CDisplaySink::SinkPlayL()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkPlayL()<"), RThread().Id().operator TUint()));
	if ( iState != EPrimed )
		{
		User::Leave( KErrNotReady );
		}
    ResetFrameRateLimitter();
	iState = EPlaying;
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkPlayL()>"), RThread().Id().operator TUint()));
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkPauseL
// -----------------------------------------------------------------------------
//
TInt CDisplaySink::SinkPauseL()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkPauseL()<"), RThread().Id().operator TUint()));
	if ( iState != EPlaying )
		{
		return KErrNone;
		}
	iState = EPrimed;
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkPauseL()>"), RThread().Id().operator TUint()));
	return KErrNone;
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SinkStopL
// -----------------------------------------------------------------------------
//
TInt CDisplaySink::SinkStopL()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkStopL()<"), RThread().Id().operator TUint()));
	if ( iState == EStopped )
		{
		return KErrNone;
		}
    iBitmapCS.Wait();
    iVideoFrameQueue->SinkStoppedL();
    iBitmapCS.Signal();
    iState = EStopped;
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkStopL()>"), RThread().Id().operator TUint()));
	return KErrNone;
	}


// -----------------------------------------------------------------------------
// CDisplaySink::CDisplaySink
// -----------------------------------------------------------------------------
//
CDisplaySink::CDisplaySink() : MVTVideoSink( KNullUid ),
    iSinkFourCC( 0 ), iState( EStopped )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::Ctor()<"), RThread().Id().operator TUint()));
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::Ctor()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::SetFrameRateLimit(
//  TDisplaySinkParams::TFrameRateLimit aFrameRateLimit )
// -----------------------------------------------------------------------------
//
void CDisplaySink::SetFrameRateLimit(
    TDisplaySinkParams::TFrameRateLimit aFrameRateLimit )
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetFrameRateLimit()<"), RThread().Id().operator TUint()));
    iFrameRateInterval = TInt( aFrameRateLimit );
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SetFrameRateLimit()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::ResetFrameRateLimitter()
// -----------------------------------------------------------------------------
//
void CDisplaySink::ResetFrameRateLimitter()
	{
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ResetFrameRateLimitter()<"), RThread().Id().operator TUint()));
    iMilliSecondsSinceLastFrame = 0;
    iLastFrameTime = Time::NullTTime();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ResetFrameRateLimitter()>"), RThread().Id().operator TUint()));
	}

// -----------------------------------------------------------------------------
// CDisplaySink::BufferFilledL
// -----------------------------------------------------------------------------
//
TBool CDisplaySink::IsOkToSendFrame()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::IsOkToSendFrame()<"), RThread().Id().operator TUint()));
    TBool isOkToSendFrame( EFalse );
    if( iPaused )
        {
        // nothing to do here because  okToSendFrame defaults to EFalse
        }
    else if( iFrameRateInterval == TDisplaySinkParams::EFrameRateLimitNone )
        {
        // If no limitation is set -> send frame
        isOkToSendFrame = ETrue;
        }
    else if( iLastFrameTime == Time::NullTTime() )
        {
        // EmptyBufferL() is being called the first time after SinkPlayL() ->
        // send frame
        iLastFrameTime.HomeTime();
        isOkToSendFrame = ETrue;
        }
    else
        {
        // Check if enough time has passed since previous frame sent
        TTime now;
        now.HomeTime();
        TTimeIntervalMicroSeconds interval(
            now.MicroSecondsFrom( iLastFrameTime ) );
        iMilliSecondsSinceLastFrame += I64INT( interval.Int64() ) / 1000;
        iLastFrameTime = now;
        if( iMilliSecondsSinceLastFrame >= iFrameRateInterval )
            {
            // Enough time passed -> send frame
        	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::IsOkToSendFrame(): sending frame %d >= %d"), RThread().Id().operator TUint(), iMilliSecondsSinceLastFrame, iFrameRateInterval ));
            isOkToSendFrame = ETrue;
            while( iMilliSecondsSinceLastFrame >= iFrameRateInterval )
                {
                iMilliSecondsSinceLastFrame -= iFrameRateInterval;
                }
            }
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::IsOkToSendFrame() %d>"), RThread().Id().operator TUint(), isOkToSendFrame));
    return isOkToSendFrame;
    }

// -----------------------------------------------------------------------------
// CDisplaySink::FbsConnectL
// -----------------------------------------------------------------------------
//
void CDisplaySink::FbsConnectL()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::FbsConnectL()<"), RThread().Id().operator TUint()));
    if ( !( iInitFlags & EFbsSessionConnected ) )
        {
        User::LeaveIfError( RFbsSession::Connect() );
        iInitFlags |= EFbsSessionConnected;
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::FbsConnectL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::ThreadOpenL
// -----------------------------------------------------------------------------
//
void CDisplaySink::ThreadOpenL()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ThreadOpenL()<"), RThread().Id().operator TUint()));
    if ( !( iInitFlags & EThreadOpened ) )
        {
        User::LeaveIfError( iThread.Open( iThreadId ) );
        iInitFlags |= EThreadOpened;
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ThreadOpenL()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::FbsDisconnect
// -----------------------------------------------------------------------------
//
void CDisplaySink::FbsDisconnect()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::FbsDisconnect()<"), RThread().Id().operator TUint()));
    if ( iInitFlags & EFbsSessionConnected )
        {
        RFbsSession::Disconnect();
        iInitFlags &= ~EFbsSessionConnected;
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::FbsDisconnect()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::ThreadClose
// -----------------------------------------------------------------------------
//
void CDisplaySink::ThreadClose()
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ThreadClose()<"), RThread().Id().operator TUint()));
    if ( iInitFlags & EThreadOpened )
        {
        iThread.Close();
        iInitFlags &= ~EThreadOpened;
        }
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::ThreadClose()>"), RThread().Id().operator TUint()));
    }

// -----------------------------------------------------------------------------
// CDisplaySink::SinkThreadLogonCleanup
// -----------------------------------------------------------------------------
//
void CDisplaySink::SinkThreadLogonCleanup( TAny* aPtr )
    {
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogonCleanup()<"), RThread().Id().operator TUint()));
	CDisplaySink* self = reinterpret_cast< CDisplaySink* >( aPtr );
	self->iVideoFrameQueue->ThreadLogoff();
	self->ThreadClose();
	self->FbsDisconnect();
	_IFDBG(PRINT(_L("VideoSource[%d]: CDisplaySink::SinkThreadLogonCleanup()>"), RThread().Id().operator TUint()));
    }

// ================= OTHER EXPORTED FUNCTIONS ==============

// -----------------------------------------------------------------------------
// CreateSinkL
// -----------------------------------------------------------------------------
//
EXPORT_C MDisplaySink* CreateSinkL( TDisplaySinkParams& aParams,
    const TDesC8& aInitData )
    {
    MDisplaySink* sink = NULL;
    if (aParams.iFlags & TDisplaySinkParams::EDisplaySinkNGA)
        {
        sink = CDisplaySinkNGA::NewL( aParams, aInitData );
        }
    else if ( FeatureManager::FeatureSupported( KFeatureIdDisplayPost ) &&
    	 ( aParams.iFlags & TDisplaySinkParams::EDisplaySinkDP ) )
	    {
        sink = CDisplaySinkDP::NewL( aParams, aInitData );
	    }
        else
	    {
        sink = CDisplaySinkDSA::NewL( aParams, aInitData );
	    }
    return sink;
    }

// End of File