videoeditorengine/vedengine/videoprocessor/src/videoprocessor.cpp
author Mikael Laine <mikael.laine@ixonos.com>
Fri, 29 Jan 2010 14:08:33 +0200
changeset 0 951a5db380a0
permissions -rw-r--r--
Committing the Video Editor package under the Eclipse Public License

/*
* Copyright (c) 2010 Ixonos Plc.
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the "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:
* Ixonos Plc
*
* Description:  
* Implementation for video processor.
*
*/


//  Include Files

#include "vedcommon.h"
#include "movieprocessorimpl.h"
#include "statusmonitor.h"
#include "activequeue.h"
#include "dataprocessor.h"
#include "h263dmai.h"  // CVedH263Dec
#include "mp4parser.h"
#include "videoencoder.h"
#include "videoprocessor.h"
#include "mpeg4timer.h"
#include "vedvolreader.h"
#include "vedvideosettings.h"
#include "vedavcedit.h"

// Local constants
const TUint KInitialDataBufferSize = 8192; // initial frame data buffer size
const TUint KH263StartCodeLength = 3;  // H.263 picture start code length
const TUint KMPEG4StartCodeLength = 4; // MPEG4 picture start code length
//const TUint KMaxEncodingDelay = 500000; // time to wait for encoding to complete in microsec.
const TUint KDefaultTimeIncrementResolution = 30000;
const TUint KAVCNotCodedFrameBuffer = 128;
const TUint KMaxItemsInProcessingQueue = 3;     // note! this must be synchronized with KTRMinNumberOfBuffersCodedPicture setting in transcoder!


#ifdef _DEBUG
const TInt KErrorCode = CVideoProcessor::EDecoderFailure;
#else
const TInt KErrorCode = KErrGeneral;
#endif

// An assertion macro wrapper to clean up the code a bit
#define VDASSERT(x, n) __ASSERT_DEBUG(x, User::Panic(_L("CVideoProcessor"), EInternalAssertionFailure+n)) 

// Debug print macro

#ifdef _DEBUG
#include <e32svr.h>
#define PRINT(x) RDebug::Print x;
#else
#define PRINT(x)
#endif

// ================= STATIC FUNCTIONS =======================

// ---------------------------------------------------------
// AddBits
// Static helper function to add bits to byte-buffer
// ---------------------------------------------------------
//
static void AddBits(TUint8* aBuf, TInt& aBitIndex, TInt& aByteIndex, TInt aBits, TInt aNrOfBits)
    {
    // aBitIndex = 8 => first bit in the left
    // aBitIndex = 1 => last bit in the right
    while ( aBitIndex < aNrOfBits )
        {
        // divide into n bytes
        aBuf[aByteIndex++] |= TUint8( aBits >> (aNrOfBits-aBitIndex) );
        aNrOfBits -= aBitIndex;
        aBitIndex = 8;
        }
    // all bits fit into 1 byte
    aBitIndex -= aNrOfBits;
    aBuf[aByteIndex] |= TUint8( aBits << aBitIndex );
    if (aBitIndex == 0)
        {
        aBitIndex = 8;
        aByteIndex++;
        }
    }



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



// ---------------------------------------------------------
// CVideoProcessor::NewL
// Symbian two-phased constructor.
// ---------------------------------------------------------
//

CVideoProcessor* CVideoProcessor::NewL(CActiveQueue *anInputQueue,
                                       CVideoProcessor::TStreamParameters *aStreamParameters,
                                       CMovieProcessorImpl* aProcessor,
                                       CStatusMonitor *aStatusMonitor,
                                       CVedAVCEdit *aAvcEdit,
                                       TBool aThumbnailMode,
                                       TInt aPriority)
{
    CVideoProcessor *self = new (ELeave) CVideoProcessor(anInputQueue,
                                                         aStreamParameters,
                                                         aProcessor,
                                                         aStatusMonitor,  
                                                         aAvcEdit,                                                 
                                                         aThumbnailMode,
                                                         aPriority);

    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();

    return self;

}

// ---------------------------------------------------------
// CVideoProcessor::CVideoProcessor
// Constructor.
// ---------------------------------------------------------
//
CVideoProcessor::CVideoProcessor(CActiveQueue *anInputQueue,
                                 TStreamParameters *aStreamParameters,
                                 CMovieProcessorImpl* aProcessor,
                                 CStatusMonitor *aStatusMonitor,
                                 CVedAVCEdit *aAvcEdit,
                                 TBool aThumbnailMode, 
                                 TInt aPriority) : CVideoDecoder(aPriority),
                                 iWriteDes(0,0),
                                 iThumbnailMode(aThumbnailMode)
{

	// Remember the objects
	iQueue = anInputQueue;
	iMonitor = aStatusMonitor;
    iProcessor = aProcessor;	
    iAvcEdit = aAvcEdit;

	// Remember the stream parameters
	iVideoWidth = aStreamParameters->iWidth;
	iVideoHeight = aStreamParameters->iHeight;	

    // Color Toning
	iFirstFrameQp = 0;
	
	iTiming = aStreamParameters->iTiming;
	// Reset state
	iReaderSet = EFalse;
	iDecoding = EFalse;
	iStreamEnd = EFalse;	
	iPreviousFrameIncluded = EFalse; 
	iFrameOperation = EDecodeAndWrite;
	
	iTrPrevious = -1;	

    iFirstFrameFlag = ETrue;
    iDecodePending = EFalse;
    
    iTranscoderStarted = EFalse;
    iDecodingSuspended = EFalse;

	iStartTransitionColor = EColorNone;	
	iEndTransitionColor = EColorNone;
	iStartNumberOfTransitionFrames = KNumTransitionFrames;
	iEndNumberOfTransitionFrames = KNumTransitionFrames;
	iNextTransitionNumber = -1;
	iProcessingComplete = EFalse;
	iStreamEndRead = EFalse;
	
	iPreviousTimeStamp = TTimeIntervalMicroSeconds(-1);
	
	iFirstRead = ETrue;
	
	iThumbDecoded = EFalse;		
	
	iMaxItemsInProcessingQueue = KMaxItemsInProcessingQueue;

    iDataFormat = EDataUnknown;

    iLastWrittenFrameNumber = -1;
    
    iInitializing = ETrue;
}


// ---------------------------------------------------------
// CVideoProcessor::~CVideoProcessor()
// Destructor
// ---------------------------------------------------------
//
CVideoProcessor::~CVideoProcessor()
{

	// If we are decoding, stop
	if (iDecoding)
		Stop();
	
	// Remove from being a reader
	if (iReaderSet)
	{
		// Return current block and all 
		// blocks from input queue
		if (iBlock)    
		{
		    if (iQueue)
			    iQueue->ReturnBlock(iBlock);
		}
					
        if (iQueue)						
		    iBlock = iQueue->ReadBlock();
		
		while (iBlock)
		{
		    if (iQueue)
		    {		        
			    iQueue->ReturnBlock(iBlock);
			    iBlock = iQueue->ReadBlock();
		    }
		}
		iBlockPos = 0;
		
		if (iQueue)
		    iQueue->RemoveReader();
	}
	Cancel();
	
	if (iTransCoder)
	{	    
	    if (iTranscoderStarted)
	    {
	        TRAPD(error, iTransCoder->StopL());
		    if (error != KErrNone) { }
	    }
	    delete iTransCoder;
	    iTransCoder = 0;	
	}
	
	iFrameInfoArray.Reset();
	
	// Close the decoder instance if one has been opened
    if (iDecoder)
        delete iDecoder;
    iDecoder = 0;   
    
	// Deallocate buffers
	if (iDataBuffer)
		User::Free(iDataBuffer);
	
	if (iOutVideoFrameBuffer)
		User::Free(iOutVideoFrameBuffer);

    if (iFrameBuffer)
        User::Free(iFrameBuffer);

	if ( iColorTransitionBuffer )
		User::Free( iColorTransitionBuffer );

	if ( iOrigPreviousYUVBuffer )
		User::Free( iOrigPreviousYUVBuffer );
	
	if (iMediaBuffer)
	    delete iMediaBuffer;
	iMediaBuffer = 0;
	
	if (iDecoderSpecificInfo)
	    delete iDecoderSpecificInfo;
    iDecoderSpecificInfo = 0;
    
    if (iOutputVolHeader)
	    delete iOutputVolHeader;
    iOutputVolHeader = 0;
    
    if (iDelayedBuffer)
        delete iDelayedBuffer;
    iDelayedBuffer = 0;
    
    if (iMPEG4Timer)
        delete iMPEG4Timer;
    iMPEG4Timer = 0;
    
    if (iTimer)
        delete iTimer;
    iTimer = 0;
    
    if (iNotCodedFrame)
        delete iNotCodedFrame;
    iNotCodedFrame = 0;
       
}


// ---------------------------------------------------------
// CVideoProcessor::ConstructL()
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------
//
void CVideoProcessor::ConstructL()
{
 	// Set as a reader to the input queue
	iQueue->SetReader(this, NULL);
	iReaderSet = ETrue;

    // Add us to active scheduler
    CActiveScheduler::Add(this);

    iMediaBuffer = new (ELeave)CCMRMediaBuffer;
	
	// Allocate buffers
	iDataBuffer = (TUint8*) User::AllocL(KInitialDataBufferSize);
	iBufferLength = KInitialDataBufferSize; 

    if ( iThumbnailMode )
    {           
    	TSize a = iProcessor->GetMovieResolution();
    	TInt length = a.iWidth*a.iHeight;
        
        length += (length>>1);
        iFrameBuffer = (TUint8*)User::AllocL(length);
    }
	
    TSize size(iVideoWidth, iVideoHeight);

    if (!iThumbnailMode)
    {        
        // Open a decoder instance
        iDecoder = CVedH263Dec::NewL(size, 1 /*iReferencePicturesNeeded*/);
    	    	
    	// create timer
    	iTimer = CCallbackTimer::NewL(*this);
    }
    
    // Make us active
    SetActive();
    iStatus = KRequestPending;
}


// ---------------------------------------------------------
// CVideoProcessor::Start
// Starts decoding
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::Start()
{
	if ( iDecoding )
		return;

    // Activate the object if we have data
    if ( (!iDecodePending) && (iStatus == KRequestPending) && iQueue->NumDataBlocks() )
    {
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, KErrNone);
    }
    
    iDecoding = ETrue;
}

// ---------------------------------------------------------
// CVideoProcessor::Stop
// Stops decoding
// (other items were commented in a header).
// ---------------------------------------------------------
//

void CVideoProcessor::Stop()
{
	iDecoding = EFalse;
		
    if (iTimer)
        iTimer->CancelTimer();
    
	if (iTranscoderStarted)
    {                
        TRAPD(error, iTransCoder->StopL());
        if (error != KErrNone) { }
        iTranscoderStarted = EFalse;
    }    	
}

// ---------------------------------------------------------
// CVideoProcessor::RunL
// Standard active object running method			
// (other items were commented in a header).
// ---------------------------------------------------------
//
					
void CVideoProcessor::RunL()
{
	PRINT((_L("CVideoProcessor::RunL() in")))
	
	// Don't decode if we aren't decoding
    if (!iDecoding)
    {
        if (!IsActive())
        {
            SetActive();
            iStatus = KRequestPending;
        }        
    	PRINT((_L("CVideoProcessor::RunL() out from !iDecoding branch")))
        return;		
    }            
    
    if (iTranscoderInitPending)
    {        
        iTranscoderInitPending = EFalse;        
        if (iStatus != KErrNone)
        {
            if (!iThumbnailMode)
            {                
                VDASSERT(iMonitor, 101);
                iMonitor->Error(iStatus.Int());
            } 
            else
            {
                iProcessor->NotifyThumbnailReady(iStatus.Int());
            }
                
            return;
        }
        // at this point we have already read a frame, 
        // so now start processing                
        iTransCoder->StartL();
                
        // stop if a fatal error has occurred in starting 
        // the transcoder (decoding stopped in MtroFatalError)
        if (!iDecoding)
            return;
        
        iTranscoderStarted = ETrue;
        
        if (!iThumbnailMode)
        {
            ProcessFrameL();
            if (iDecodePending)
                return;
        }
        else
        {
            ProcessThumb(ETrue);
            return;
        }        
    }
        
    if (iDecodePending)
    {
        iDecodePending = EFalse;        

        if (iThumbnailMode)
        {
             if (iThumbDecoded)
             {
                 PRINT((_L("CVideoProcessor::RunL() - thumb decoded")))  
                 ProcessThumb(EFalse);
             }
             else
             {
                 PRINT((_L("CVideoProcessor::RunL() - thumb not decoded")))    
                 ReadAndWriteThumbFrame();
             }
             return;
        }
    }
    
    if (iProcessingComplete)
    {       
        PRINT((_L("CVideoProcessor::RunL() iProcessingComplete == ETrue")))
        VDASSERT(iMonitor, 102);
        iMonitor->ClipProcessed();
        return;
    }
    
    if (iFirstColorTransitionFrame)
    {
        Process2ndColorTransitionFrameL();
        return;
    }

    while (!iDecodePending && !iDelayedWrite && !iTranscoderInitPending &&
             ReadFrame() )
    {    
        // process it       
        if ( ProcessFrameL() )
        {                        
            // clip processed up until cut-out time, stop 
            if (iFrameInfoArray.Count())            
            {
                PRINT((_L("CVideoProcessor::RunL() - stream end reached, wait for frames")));
                iStreamEnd = iStreamEndRead = ETrue;
                
                // if there are still frames to be encoded, start timer 
                // since encoder may skip the rest of the frames
                if ( IsNextFrameBeingEncoded() )
                {
                    PRINT((_L("CVideoProcessor::RunL(), set timer")));
                    if ( !iTimer->IsPending() )
                        iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );                                        
                }
                return;   
            }
            
            iTimer->CancelTimer();
            if (iTranscoderStarted)
            {                
                iTransCoder->StopL();
                iTranscoderStarted = EFalse;
            }
            VDASSERT(iMonitor, 103);
            iMonitor->ClipProcessed();
        	PRINT((_L("CVideoProcessor::RunL() out from ProcessFrameL == ETrue")))
            return;
        }        
    }
    
    if ( !iDecodePending && !iDelayedWrite && !iTranscoderInitPending )
    {
    
        // We didn't get a frame
        if (iStreamEnd)
        {
            iStreamEndRead = ETrue;
            PRINT((_L("CVideoProcessor::RunL() - stream end reached")));    
            if (iFrameInfoArray.Count())
            {
                PRINT((_L("CVideoProcessor::RunL() - stream end reached, wait for frames")));    
                // wait until frames have been processed   
                
                // if there are still frames to be encoded, start timer 
                // since encoder may skip the rest of the frames
                if ( IsNextFrameBeingEncoded() )
                {
                    PRINT((_L("CVideoProcessor::RunL(), set timer")));
                    if ( !iTimer->IsPending() )
                        iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
                }
                return;
            }
            else
            {    
                iTimer->CancelTimer();
                VDASSERT(iMonitor, 104);                
                iMonitor->ClipProcessed();
            }
        }
        else
        {
            if (!IsActive())
            {
                SetActive();
                iStatus = KRequestPending;
            }
        }
    }

	PRINT((_L("CVideoProcessor::RunL() out")))
      
}

// -----------------------------------------------------------------------------
// CVideoProcessor::RunError
// Called by the AO framework when RunL method has leaved
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//	
TInt CVideoProcessor::RunError(TInt aError)
{

   if ((aError == CVedH263Dec::EDecoderNoIntra) || (aError == CVedH263Dec::EDecoderCorrupted))
   {       
       if (!iThumbnailMode)
           iMonitor->Error(KErrCorrupt);
       else
           iProcessor->NotifyThumbnailReady(KErrCorrupt);
   }
   else
   {
       if (!iThumbnailMode)
           iMonitor->Error(aError);
       else
           iProcessor->NotifyThumbnailReady(aError);
   }

    return KErrNone;
}


// ---------------------------------------------------------
// CVideoProcessor::Process2ndColorTransitionFrameL
// Processes the second frame of a color transition double frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CVideoProcessor::Process2ndColorTransitionFrameL()
{    

    TFrameInformation frameInfo;
    frameInfo.iTranscoderMode = EFullWithIM;
    frameInfo.iFrameNumber = iFrameNumber;
    frameInfo.iEncodeFrame = ETrue;
    frameInfo.iKeyFrame = EFalse;
    frameInfo.iTransitionFrame = ETrue;
    frameInfo.iTransitionPosition = EPositionStartOfClip;
    frameInfo.iTransitionColor = iStartTransitionColor;
    frameInfo.iTransitionFrameNumber = iTransitionFrameNumber;
    frameInfo.iModificationApplied = EFalse;   
    frameInfo.iRepeatFrame = ETrue;
        
    TInt duration;
    // get timestamp
    iProcessor->GetNextFrameDuration(duration, frameInfo.iTimeStamp, iTimeStampIndex, iTimeStampOffset);
    iTimeStampIndex++;        
    
    frameInfo.iTimeStamp += iCutInTimeStamp;
    
    TTimeIntervalMicroSeconds ts = (iProcessor->GetVideoTimeInMsFromTicks(frameInfo.iTimeStamp, EFalse)) * 1000;
    
    if (ts <= iPreviousTimeStamp)
    {            
        // adjust timestamp so that its bigger than ts of previous frame
        TReal frameRate = iProcessor->GetVideoClipFrameRate();
        VDASSERT(frameRate > 0.0, 105);
        TInt64 durationMs =  TInt64( ( 1000.0 / frameRate ) + 0.5 );
        durationMs /= 2;  // add half the duration of one frame
        
        ts = TTimeIntervalMicroSeconds( iPreviousTimeStamp.Int64() + durationMs*1000 );
        
        frameInfo.iTimeStamp = iProcessor->GetVideoTimeInTicksFromMs( ts.Int64()/1000, EFalse );
        
        ts = iProcessor->GetVideoTimeInMsFromTicks(frameInfo.iTimeStamp, EFalse) * 1000;
        
        PRINT((_L("CVideoProcessor::Process2ndColorTransitionFrameL() - adjusted timestamp, prev = %d, new = %d"), 
                   I64INT( iPreviousTimeStamp.Int64() ) / 1000, I64INT( ts.Int64() ) / 1000));    

    }        
    
 
    iFrameInfoArray.Append(frameInfo);
    
    iPreviousTimeStamp = ts;
    
    iFirstColorTransitionFrame = EFalse;   
    
    CCMRMediaBuffer::TBufferType bt = 
        (iDataFormat == EDataH263) ? CCMRMediaBuffer::EVideoH263 : CCMRMediaBuffer::EVideoMPEG4;
    
    if (!iNotCodedFrame)
        GenerateNotCodedFrameL();
    
    PRINT((_L("CVideoProcessor::Process2ndColorTransitionFrameL() - sending not coded")));
    
#ifdef VIDEOEDITORENGINE_AVC_EDITING
    if (iDataFormat == EDataAVC)
    {        
        TPtr8 ptr(iNotCodedFrame->Des());
        
        TInt length = iNotCodedFrame->Length();
        iAvcEdit->ProcessAVCBitStreamL((TDes8&)(ptr), length, 0 /*dummy*/, EFalse );
        ptr.SetLength(length);
        iDataLength = iCurrentFrameLength = length;
    }
#endif

    iMediaBuffer->Set( TPtrC8(iNotCodedFrame->Des().Ptr(), iNotCodedFrame->Length()),                           
                       bt, 
                       iNotCodedFrame->Length(), 
                       EFalse,
                       ts );

    iDecodePending = ETrue;
    if (!IsActive())
    {
        SetActive();
        iStatus = KRequestPending;                                
    }                
                                      
    PRINT((_L("CVideoProcessor::Process2ndColorTransitionFrameL() - WriteCodedBuffer, frame #%d, timestamp %d ms"),
           iFrameNumber, I64INT( ts.Int64() ) / 1000 ));                                                  
    iTransCoder->WriteCodedBufferL(iMediaBuffer);
                
    iFrameNumber++;
    
    return ETrue;
    
}

    
// ---------------------------------------------------------
// CVideoProcessor::GenerateNotCodedFrameL
// Generate bitstream for not coded frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::GenerateNotCodedFrameL()
{

    TSize resolution = iProcessor->GetVideoClipResolution();

    if (iDataFormat == EDataH263)
    {
        // H.263 QCIF picture header
        TInt headerSize = 7;
        TUint8 notCodedH263[] = { 0x00, 0x00, 0x80, 0x02, 0x0a, 0x0c, 0x3f };
        TUint8 lsbMask[8] = { 255, 254, 252, 248, 240, 224, 192, 128 };
        
        
        if ( resolution == TSize(128,96) )
            notCodedH263[4] = 0x06;  // set source format as sub-QCIF
        
        else if ( resolution == TSize(352, 288) )
            notCodedH263[4] = 0x0e;  // set source format as CIF
            
        else if ( resolution != TSize(176,144) )
            User::Panic(_L("CVideoProcessor"), EInternalAssertionFailure);
        
        TInt numMBs = ( resolution.iWidth / 16 ) * ( resolution.iHeight / 16 );    
        
        // one COD bit for each MB, the last byte of the pic header already contains 6 MB bits
        TInt bitsLeft = numMBs - 6;  
        
        TInt bufSize = headerSize + ( bitsLeft / 8 ) + ( bitsLeft % 8 != 0 );

        VDASSERT(!iNotCodedFrame, 117);
        iNotCodedFrame = (HBufC8*) HBufC8::NewL(bufSize);
        
        TPtr8 buf(iNotCodedFrame->Des());
        buf.Copy(notCodedH263, headerSize);
        
        TInt index = headerSize;
        TUint8* ptr = const_cast<TUint8*>(buf.Ptr());
        
        // set COD bit to 1 for all macroblocks
        while (bitsLeft >= 8)
        {
            ptr[index++] = 0xff;
            bitsLeft -= 8;
        }
        
        if (bitsLeft)
        {        
            TUint8 val = 0;    
            val |= lsbMask[8 - bitsLeft];
            ptr[index] = val;
        }
        buf.SetLength(bufSize);
    } 
    
    else if (iDataFormat == EDataMPEG4)
    {
        VDASSERT(iDataFormat == EDataMPEG4, 115);

        TUint8 vopStartCodeMPEG4[] = { 0x00, 0x00, 0x01, 0xb6 };
        
        TInt headerSize = 4;

        // calculate the number of bits needed for vop_time_increment
        TInt numTiBits;
        for (numTiBits = 1; ((iInputTimeIncrementResolution - 1) >> numTiBits) != 0; numTiBits++)
        {
        }        
        
        VDASSERT(numTiBits <= 16, 116);

        TInt numMBs = ( resolution.iWidth / 16 ) * ( resolution.iHeight / 16 );
        
        // get VOP size
        //   vop_start_code: 32
        //   vop_coding_type + modulo_time_base + marker_bit: 4
        //   no. of bits for vop_time_increment
        //   marker_bit + vop_coded bit: 2
        //   rounding_type: 1
        //   intra_dc_vlc_thr: 3
        //   vop_quant: 5
        //   vop_fcode_forward: 3
        //   not_coded for each MB: numMBs
        TInt bufSizeBits = headerSize * 8 + 4 + numTiBits + 2 + 1 + 3 + 5 + 3 + numMBs;//DP mode not included!
        if ( (iInputStreamMode == EVedVideoBitstreamModeMPEG4DP)
            || (iInputStreamMode == EVedVideoBitstreamModeMPEG4DP_RVLC)
            || (iInputStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP)
            || (iInputStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC)
            )
            {
            // Motion marker in DP mode
            bufSizeBits+=17;
            }
        TInt bufSize = ( bufSizeBits / 8 ) + 1;        // always 1-8 stuffing bits
        
        VDASSERT(!iNotCodedFrame, 118);
        iNotCodedFrame = (HBufC8*) HBufC8::NewL(bufSize);
        
        TPtr8 buf(iNotCodedFrame->Des());
        buf.SetLength(bufSize);
        buf.FillZ();
        buf.SetLength(0);
        buf.Copy(vopStartCodeMPEG4, headerSize);
        
        TUint8* ptr = const_cast<TUint8*>(buf.Ptr());        
        TInt shift = 8;
        TInt index = headerSize;
        AddBits(ptr, shift, index, 1, 2); // vop_coding_type
        AddBits(ptr, shift, index, 0, 1); // modulo_time_base
        AddBits(ptr, shift, index, 1, 1); // marker_bit
        
        // vop_time_increment is left to zero (skip FillZ bits)
        AddBits(ptr, shift, index, 0, numTiBits);
            
        // marker (1 bit; 1) 
        AddBits(ptr, shift, index, 1, 1);
        // vop_coded (1 bit; 1=coded)
        AddBits(ptr, shift, index, 1, 1);
        
        // vop_rounding_type (1 bit) (0)
        AddBits(ptr, shift, index, 0, 1);
        
        // intra_dc_vlc_thr (3 bits) (0 = Intra DC, but don't care)
        AddBits(ptr, shift, index, 0, 3);
        
        // vop_quant (5 bits) (1-31)
        AddBits(ptr, shift, index, 10, 5);
        
        // vop_fcode_forward (3 bits) (1-7, 0 forbidden)
        AddBits(ptr, shift, index, 1, 3);
        
        // Macroblocks
        
        // one COD bit for each MB
        TInt bitsLeft = numMBs;  
        
        // set COD bit to 1 for all macroblocks (== not coded)
        while (bitsLeft >= 8)
        {
            AddBits(ptr, shift, index, 0xff, 8);
            bitsLeft -= 8;
        }
        
        TUint8 lsb[8] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
        if (bitsLeft)
        {        
            TUint8 val = 0;    
            val = lsb[8 - bitsLeft];
            AddBits(ptr, shift, index, val, bitsLeft);
        }
        // If DP mode is used, should add motion marker here: 1 11110000 00000001
        if ( (iInputStreamMode == EVedVideoBitstreamModeMPEG4DP)
            || (iInputStreamMode == EVedVideoBitstreamModeMPEG4DP_RVLC)
            || (iInputStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP)
            || (iInputStreamMode == EVedVideoBitstreamModeMPEG4Resyn_DP_RVLC)
            )
            {
            AddBits(ptr, shift, index, 0x01, 1);
            AddBits(ptr, shift, index, 0xf0, 8);
            AddBits(ptr, shift, index, 0x01, 8);
            }
        
        // insert stuffing in last byte
        TUint8 stuffing[8] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
        ptr[bufSize - 1] |= stuffing[shift-1];
                       
        buf.SetLength(bufSize);
            
    } 
    else
    {        
#ifdef VIDEOEDITORENGINE_AVC_EDITING    

        VDASSERT(iDataFormat == EDataAVC, 115);
        
        VDASSERT(!iNotCodedFrame, 118);
        iNotCodedFrame = (HBufC8*) HBufC8::NewL(KAVCNotCodedFrameBuffer);
        
        TPtr8 buf( const_cast<TUint8*>(iNotCodedFrame->Des().Ptr()), 
                   KAVCNotCodedFrameBuffer, KAVCNotCodedFrameBuffer );
        
        TInt len = iAvcEdit->GenerateNotCodedFrame( buf, iModifiedFrameNumber++ );        
        
        if (len == 0)
            User::Leave(KErrArgument);
                
        TPtr8 temp(iNotCodedFrame->Des());
        temp.SetLength(len);        
#else
        VDASSERT(0, 190);
#endif
    }
    
    
}

// ---------------------------------------------------------
// CVideoProcessor::ProcessFrameL
// Processes one input frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CVideoProcessor::ProcessFrameL()
    {


	PRINT((_L("CVideoProcessor::ProcessFrameL() begin")));

    VDASSERT(iCurrentFrameLength,1);    
        
    TInt frameInRange = 0;    
    TInt frameDuration = 0;    
    TBool keyFrame = EFalse; 
    TTimeIntervalMicroSeconds startCutTime = TTimeIntervalMicroSeconds(0);
    TTimeIntervalMicroSeconds endCutTime = TTimeIntervalMicroSeconds(0);
    TTimeIntervalMicroSeconds frameTime = TTimeIntervalMicroSeconds(0);

    TInt trP = iProcessor->GetTrPrevNew();    
    TInt trD = iProcessor->GetTrPrevOrig();

    // transitions
    iTransitionFrame = 0;			// is this a transition frame?
    iTransitionPosition = EPositionNone;
    iTransitionColor = EColorNone;    
    iFirstTransitionFrame = 0;		// is this the first transition frame in this instance?
    TBool endColorTransitionFrame = EFalse;
    
    TBool decodeCurrentFrame = 0;	// do we need to decode frame for transition effect?
   
    // book-keeping
    startCutTime = iProcessor->GetStartCutTime();
    endCutTime = iProcessor->GetEndCutTime();
	iRepeatFrame = EFalse;

    if(iInitializing)
    {
    
        // determine if we need to do full transcoding
		iFullTranscoding = DetermineResolutionChange() || DetermineFrameRateChange() || 
		                   DetermineBitRateChange();
		                   		
        // Do full transcoding for MPEG-4 => H.263. MPEG-4 => MPEG-4 and H.263 => MPEG-4 can be done in compressed domain
        if ( iProcessor->GetCurrentClipVideoType() == EVedVideoTypeMPEG4SimpleProfile &&
             iProcessor->GetOutputVideoType() != EVedVideoTypeMPEG4SimpleProfile )
            iFullTranscoding = ETrue;
		               
#ifdef VIDEOEDITORENGINE_AVC_EDITING
        // Do full transcoding for AVC => H.263/MPEG-4
		if ( iProcessor->GetCurrentClipVideoType() == EVedVideoTypeAVCBaselineProfile &&
		     iProcessor->GetOutputVideoType() != EVedVideoTypeAVCBaselineProfile )
            iFullTranscoding = ETrue;
            
        // Do full transcoding for H.263/MPEG-4 => AVC
        if ( iProcessor->GetCurrentClipVideoType() != EVedVideoTypeAVCBaselineProfile &&
		     iProcessor->GetOutputVideoType() == EVedVideoTypeAVCBaselineProfile )
            iFullTranscoding = ETrue;
                                            
        // Do color effects for AVC in spatial domain                    
        if ( iProcessor->GetOutputVideoType() == EVedVideoTypeAVCBaselineProfile &&
             iProcessor->GetColorEffect() != EVedColorEffectNone )
            iFullTranscoding = ETrue;
#endif

        // determine transition parameters for the clip 
        DetermineClipTransitionParameters(iTransitionEffect,iStartOfClipTransition,
            iEndOfClipTransition,iStartTransitionColor,iEndTransitionColor);
    
        if (!iTransCoder)
        {
            // initialize transcoder, normal mode
            CreateAndInitializeTranscoderL(iProcessor->GetCurrentClipVideoType(), CTRTranscoder::EFullTranscoding);
            return EFalse;
        }
    
		if ( iColorTransitionBuffer )
		{
			User::Free( iColorTransitionBuffer );
			iColorTransitionBuffer = 0;
		}
		
		if ( iOrigPreviousYUVBuffer )
		{
			User::Free( iOrigPreviousYUVBuffer );
			iOrigPreviousYUVBuffer = 0;
		}

        iFirstFrameInRange = 0;
        iFirstIncludedFrameNumber = -1;
        iTimeStampIndex = 0;
        iTimeStampOffset = 0;
        //iProcessor->iOutputFramesInClip=0; 
        iPreviousFrameIncluded = EFalse; 
        iNumberOfFrames = iProcessor->GetClipNumberOfFrames();	
        
        // calculate number of included frames
        if(iTransitionEffect)
        {
            GetNumberOfTransitionFrames(startCutTime, endCutTime);                    
        }
        iInitializing = EFalse;
    }

    TInt startFrame = iProcessor->GetOutputNumberOfFrames() - iNumberOfFrames;
    TInt absFrameNumber = startFrame + iFrameNumber;
    
    VDASSERT(startCutTime <= endCutTime,2);

    // microseconds
    frameTime = TTimeIntervalMicroSeconds(iProcessor->GetVideoTimeInMsFromTicks(
        iProcessor->VideoFrameTimeStamp(absFrameNumber), EFalse) * 1000);
    keyFrame = iProcessor->VideoFrameType(absFrameNumber);

	TInt cur = absFrameNumber; 
	TInt next = cur+1;
	
	TTimeIntervalMicroSeconds frameDurationInMicroSec(0);

	// frameDuration is in ticks, with timescale of the current input clip
	if(next >= iProcessor->GetOutputNumberOfFrames())	
	{	    
		frameDurationInMicroSec = 
			(iProcessor->GetVideoTimeInMsFromTicks(iProcessor->GetVideoClipDuration(), EFalse) * TInt64(1000)) - frameTime.Int64();		
		
		frameDuration = I64INT(iProcessor->GetVideoClipDuration() - iProcessor->VideoFrameTimeStamp(cur) );
	}
	else
	{
		frameDuration = I64INT( iProcessor->VideoFrameTimeStamp(next) - iProcessor->VideoFrameTimeStamp(cur) );
		frameDurationInMicroSec = 
			TTimeIntervalMicroSeconds(iProcessor->GetVideoTimeInMsFromTicks(TInt64(frameDuration), EFalse) * 1000);
	}
	
	TTimeIntervalMicroSeconds frameEndTime = 
		TTimeIntervalMicroSeconds( frameTime.Int64() + frameDurationInMicroSec.Int64() );    

	// endCutTime is in TTimeIntervalMicroSeconds

    // check if frame is in range for decoding/editing 
    frameInRange = ((frameEndTime <= endCutTime) ? 1 : 0);
    if(frameInRange)
    {        

        // transition is applied only for frame included in the output movie
        if(frameTime >= startCutTime)
        {
            // find the offset for the first included frame in the clip
            if(!iFirstFrameInRange)
            {
                iFirstFrameInRange = 1;
                iFirstIncludedFrameNumber = iFrameNumber;
                iModifiedFrameNumber = iFrameNumber + 1;  // +1 since number is incremented after modifying
            }
            TInt relativeIncludedFrameNumber = iFrameNumber - iFirstIncludedFrameNumber;            
            
            if(iTransitionEffect)
            {                
                // check if this is a transition frame & set transition parameters             
                SetTransitionFrameParams(relativeIncludedFrameNumber, decodeCurrentFrame);
            }
        }
        
        // check if this is an end color transition frame        
        if ( iTransitionFrame && iTransitionPosition == EPositionEndOfClip &&
		     iEndTransitionColor == EColorTransition )
		{
		    endColorTransitionFrame = ETrue;
			iFrameToEncode = EFalse; 
		}
				
        // check if we need to include this frame into output movie 
        if (frameTime < startCutTime)
        {
            // decode, but do not include in output movie 
            // iPreviousFrameIncluded = EFalse; 
            iFrameToEncode = EFalse; 
            iFrameOperation = EDecodeNoWrite; 
            // for decoding frames not writable to output movie, do not decode 
            // with any effects, because all information is need at P->I conversion            
        }
        else	// include in output movie 
        {
            
            // check if we need to encode it again as I-frame
            if (iFullTranscoding || (!iPreviousFrameIncluded && !keyFrame) || iTransitionFrame)
            {
                 // need to decode as P and encode as I
                 
                if (!endColorTransitionFrame)
                    iFrameToEncode = ETrue; 
				
                iFrameOperation = EDecodeNoWrite; 
                // for first decoding of P frame in a clip, do not decode with any effects;
                // instead, apply the effects in the spatial domain after decoding it as P;
                // then feed it to the encoder with the applied special effects
            }
            else
            {
            
#ifdef VIDEOEDITORENGINE_AVC_EDITING
                // check if we need to encode AVC frames after 
                // encoded cut frame or starting transition
                if (iDataFormat == EDataAVC && iEncodeUntilIDR)
                {
                    TPtr8 ptr(iDataBuffer, iCurrentFrameLength, iBufferLength);
                                        
                    if (iAvcEdit->IsNALUnitIDR(ptr))
                        iEncodeUntilIDR = 0; 
                    else
                    {
                        // encode
                        iFrameOperation = EDecodeNoWrite;				
				        if (!endColorTransitionFrame)
				            iFrameToEncode = ETrue;                        
                    }
                }
#endif
                
                if (!iEncodeUntilIDR)
                {   
                    // just copy the frame data as it is 
                
                    TInt colorEffect = TColorEffect2TInt(iProcessor->GetColorEffect());
                                        
                    iFrameToEncode = EFalse;
                    if(decodeCurrentFrame)
                        iFrameOperation = EDecodeAndWrite; 
                    else
                        iFrameOperation = (colorEffect==0/*None*/ ? EWriteNoDecode : EDecodeAndWrite);                
                }                
            }
            iPreviousFrameIncluded = ETrue;
        }

    }
    else
    {
        // no need to include frame in output movie
        iPreviousFrameIncluded = EFalse; 
        iFrameToEncode = EFalse;
        iFrameOperation = ENoDecodeNoWrite;

        // stop processing
        return ETrue;
    }
	
    TBool modeChanged = GetModeChangeL(); // do we need to change the current mode? 

	/* added to handle Mp4Specific size problem */
	if(modeChanged && !iFullTranscoding) 
	{
        iProcessor->SetClipModeChanged(modeChanged);	//if it is not set, it will be default false
	}

    if (iFrameOperation == EDecodeAndWrite)
        PRINT((_L("CVideoProcessor::ProcessFrameL() frame operation = EDecodeAndWrite")));
    if (iFrameOperation == EWriteNoDecode)
        PRINT((_L("CVideoProcessor::ProcessFrameL() frame operation = EWriteNoDecode")));        
    if (iFrameOperation == EDecodeNoWrite)
        PRINT((_L("CVideoProcessor::ProcessFrameL() frame operation = EDecodeNoWrite")));    
    if (iFrameOperation == ENoDecodeNoWrite)
        PRINT((_L("CVideoProcessor::ProcessFrameL() frame operation = ENoDecodeNoWrite")));    
    
    PRINT((_L("CVideoProcessor::ProcessFrameL() iFrameToEncode = %d"), iFrameToEncode));    
    
    TBool volHeaderIncluded = EFalse;
    
    if( (iFrameOperation == EDecodeAndWrite) || (iFrameOperation == EWriteNoDecode) ||
       ((iFrameOperation == EDecodeNoWrite) && !iFullTranscoding && iFirstFrameFlag) )
       // the last line is to enable processing of the 1st frame also if it would be decoded with transcoder, 
       // to enable processing of the MPEG-4 VOL header by vedh263d.
    {               
        
        TPtr8 ptr(0,0);
        TBool doCompressedDomainTC =  modeChanged || iProcessor->GetColorEffect() != EVedColorEffectNone;                        

        // If we need to do compressed domain bitstream manipulation at some
        // point of the clip, all frames must be decoded by vedh263d to be 
        // able to start bitstream modification in the middle of the clip, e.g.
        // after a transition. If we are processing MPEG-4, all frames are
        // manipulated by the decoder for changing timing information
                   
        if ( doCompressedDomainTC || (iDataFormat == EDataMPEG4 /*&& !iTransitionFrame*/) )
        {
            // use h263decoder to do bitstream modification
            
            // (if this is an end color transition frame, iFrameOperation is 
            //  EDecodeNoWrite && iFrameToEncode == 0
                
            TInt frameOp = 1;  // EDecodeAndWrite
            
            if ( iFrameOperation == EDecodeNoWrite )
                frameOp = 2; 
            
            if ( iFrameOperation == EWriteNoDecode && !modeChanged )
                frameOp = 3;  // EWriteNoDecode
        
            TInt frameSize;                                          
            
            if (iDataFormat == EDataMPEG4 && iFirstFrameFlag)
            {
                InsertDecoderSpecificInfoL();
                volHeaderIncluded = ETrue;
            }
            
            // use h263decoder to do compressed domain transcoding
            PRINT((_L("CVideoProcessor::ProcessFrameL() decode using vedh263d")));    
            DecodeFrameL(frameOp, modeChanged, frameSize);
            ptr.Set(iOutVideoFrameBuffer, frameSize, frameSize);                    
        }
        else
        {   
            // copy bitstream directly
            ptr.Set(iDataBuffer, iCurrentFrameLength, iCurrentFrameLength);
        }
        
        if (iFrameOperation == EDecodeAndWrite || iFrameOperation == EWriteNoDecode)
        {
#ifdef VIDEOEDITORENGINE_AVC_EDITING
            if (iDataFormat == EDataAVC && iTransitionEffect && 
                iStartTransitionColor == EColorTransition) 
            {
                if (!(iAvcEdit->IsNALUnitIDR(ptr)))
                {        
                    // modify frame number
                    VDASSERT( (iFrameNumber > iFirstIncludedFrameNumber), 182 );
                    iAvcEdit->ModifyFrameNumber(ptr, iModifiedFrameNumber++);       
                    PRINT((_L("CVideoProcessor::ProcessFrameL() modified frame no. => #%d"), iModifiedFrameNumber - 1));
                } 
                else
                    iModifiedFrameNumber = 1;  // this frame is IDR, start numbering from zero
            }
#endif
            // Write to file            
            if ( WriteFrameToFileL(ptr, frameDuration, absFrameNumber) )
                return ETrue;
        }
        
        if (iFrameOperation == EWriteNoDecode || 
            (iFrameOperation == EDecodeAndWrite && !decodeCurrentFrame && doCompressedDomainTC))
        {   
            // NOTE: The 2nd condition is for B&W & compr.domain TC
            
            // if we are doing only compressed domain transcoding, theres no need to
            // decode the frame using transcoder
            
            // Throw away the data for this frame:
            VDASSERT(iDataLength >= iCurrentFrameLength,4);
            Mem::Copy(iDataBuffer, iDataBuffer + iCurrentFrameLength,
                iDataLength - iCurrentFrameLength);
            iDataLength = iDataLength - iCurrentFrameLength;        
            iCurrentFrameLength = 0;			  
                        
            // update and fetch the new Time Code for MPEG4 ES
            if (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile &&
                frameInRange && (frameTime >= startCutTime) )
				
		    {
    			iMPEG4Timer->UpdateMPEG4Time(absFrameNumber, iFrameNumber, iProcessor->GetSlowMotionSpeed());
		    }
            
            iFrameNumber++;                    
            return EFalse; 
        }
    }
    
    // process using transcoder 
    if (iFrameOperation == EDecodeNoWrite || iFrameOperation == EDecodeAndWrite)
    {
        WriteFrameToTranscoderL(absFrameNumber, keyFrame, volHeaderIncluded);
    }
    
    // update and fetch the new Time Code for MPEG4 ES
    if (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile &&
        frameInRange && (frameTime >= startCutTime) )
	{
        iMPEG4Timer->UpdateMPEG4Time(absFrameNumber, iFrameNumber, iProcessor->GetSlowMotionSpeed());
    }

    iProcessor->SetTrPrevNew(trP);
    iProcessor->SetTrPrevOrig(trD);
    
    if (!iFirstColorTransitionFrame)
        iFrameNumber++;
               
    PRINT((_L("CVideoProcessor::ProcessFrameL() end")));

    return EFalse; 
}


// ---------------------------------------------------------
// CVideoProcessor::WriteFrameToFileL
// Write frame to file
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CVideoProcessor::WriteFrameToFileL(TPtr8& aBuf, TInt aDurationInTicks, TInt aFrameNumber)
{    
   
    // if there's a frame waiting to be encoded, we must not
    // write this frame now. It will be written after all to-be-encoded
    // frames have been written. New frames must not be processed
    // until the delayed write has been completed                                
                            
    iDelayedWrite = !IsEncodeQueueEmpty();
    
    if (iDelayedWrite)
    {
        PRINT((_L("CVideoProcessor::WriteFrameToFileL() delayed write")));    
        // save frame for later writing            
        if (iDelayedBuffer)
            delete iDelayedBuffer;
        iDelayedBuffer = 0;
        
        iDelayedBuffer = (HBufC8*) HBufC8::NewL(aBuf.Length());                                
                        
        TPtr8 db(iDelayedBuffer->Des());        
        db.Copy(aBuf);
        
        iDelayedTimeStamp = iProcessor->VideoFrameTimeStamp(aFrameNumber) + iTimeStampOffset;
        iDelayedKeyframe = iProcessor->VideoFrameType(aFrameNumber);
        iDelayedFrameNumber = iFrameNumber;
        if ( IsNextFrameBeingEncoded() )
        {
            // start timer to wait for encoding to complete
            if ( !iTimer->IsPending() )
                iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
        }        
    } 
    else
    {
        // write now
        TInt error = iProcessor->WriteVideoFrameToFile(aBuf, 
          ( iProcessor->VideoFrameTimeStamp(aFrameNumber) + iTimeStampOffset ),
            aDurationInTicks, iProcessor->VideoFrameType(aFrameNumber), EFalse, EFalse, EFalse );
        
        // If movie has reached maximum size then stop processing   
        if (error == KErrCompletion)
        {
            iFrameInfoArray.Reset();
            return ETrue;
        }
        
        // save frame number
        iLastWrittenFrameNumber = iFrameNumber;
        
        User::LeaveIfError(error);                           
    }            
                  
    return EFalse;
    
}


// ---------------------------------------------------------
// CVideoProcessor::WriteFrameToTranscoderL
// Write frame to transcoder
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::WriteFrameToTranscoderL(TInt aFrameNumber, TBool aKeyFrame, TBool aVolHeaderInBuffer)
{
     
    VDASSERT(iDataFormat != EDataUnknown, 30);
      
    // TODO: new buffertype for H.264
    CCMRMediaBuffer::TBufferType bt = 
        (iDataFormat == EDataH263) ? CCMRMediaBuffer::EVideoH263 : CCMRMediaBuffer::EVideoMPEG4;
   
    // insert dec. specific info header to beginning of buffer if it has not been sent
    if (!iDecoderSpecificInfoSent && 
        ( iDataFormat == EDataAVC || (iDataFormat == EDataMPEG4 && !aVolHeaderInBuffer) ) )
    {
        PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() - insert header"), iTranscoderMode));    
        InsertDecoderSpecificInfoL();
    }
    
    // determine transcoder mode for this frame
    TTranscoderMode mode;
            
    if (iFrameToEncode)
    {        
        if ( iTransitionFrame || (iProcessor->GetColorEffect() != EVedColorEffectNone) )
        {
            PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() encode current frame with intermediate modification")));
            mode = EFullWithIM;
        } 
        else
        {
            PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() encode current frame")));   
            mode = EFull;
        }            
    } 
    else
    {
        PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() only decode current frame")));   
        mode = EDecodeOnly;
    }                
    
    PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() iTranscoderMode %d"), iTranscoderMode));   
    if (iTranscoderMode != mode)
    {
        if (mode == EDecodeOnly)
        {
            iTransCoder->EnableEncoder(EFalse);
            iTransCoder->EnablePictureSink(ETrue);
        } 
        else if (mode == EFull)
        {
            iTransCoder->EnableEncoder(ETrue);
            iTransCoder->EnablePictureSink(EFalse);
        } 
        else
        {
            iTransCoder->EnableEncoder(ETrue);
            iTransCoder->EnablePictureSink(ETrue);
        }                                  
        iTranscoderMode = mode;
    }
    
    if (iFrameToEncode)
    {
        // should we encode an I-frame ?
        if( (iTransitionFrame && iFirstTransitionFrame) || 
            (iFrameNumber == iFirstIncludedFrameNumber) ||
             iFirstFrameAfterTransition )
        {
            iTransCoder->SetRandomAccessPoint();
        }
    }
    
    TFrameInformation frameInfo;        
    frameInfo.iTranscoderMode = iTranscoderMode;
    frameInfo.iFrameNumber = iFrameNumber;
    frameInfo.iEncodeFrame = iFrameToEncode;
    frameInfo.iKeyFrame = aKeyFrame;
    
    // this timestamp is in ticks for writing the frame
    frameInfo.iTimeStamp = iProcessor->VideoFrameTimeStamp(aFrameNumber) + iTimeStampOffset;
    frameInfo.iTransitionFrame = iTransitionFrame;
    frameInfo.iTransitionPosition = iTransitionPosition;
    frameInfo.iTransitionColor = iTransitionColor;
    frameInfo.iTransitionFrameNumber = iTransitionFrameNumber;
    frameInfo.iModificationApplied = EFalse;
    
    if(iTransitionFrame && iTransitionPosition == EPositionStartOfClip && 
       iStartTransitionColor == EColorTransition)
    {
        TInt duration;
        TInt64 currentTimeStamp = iProcessor->VideoFrameTimeStamp(aFrameNumber);
        
        // get timestamp for 1st frame            
        iProcessor->GetNextFrameDuration(duration, frameInfo.iTimeStamp, iTimeStampIndex, iTimeStampOffset);
        iTimeStampIndex++;
                    
        if (iFirstTransitionFrame)
            iCutInTimeStamp = currentTimeStamp;
        
        frameInfo.iTimeStamp += iCutInTimeStamp;
        
        // the duration parameter is not used actually, so no need to figure it out
        iProcessor->AppendNextFrameDuration(duration, currentTimeStamp - iCutInTimeStamp);
        
#ifdef VIDEOEDITORENGINE_AVC_EDITING    
        if (iDataFormat == EDataAVC)
        {        
        
            TPtr8 ptr(iDataBuffer, iCurrentFrameLength, iBufferLength);
            if (!iDecoderSpecificInfoSent)
            {
                ptr.Set(iDataBuffer + iProcessor->GetDecoderSpecificInfoSize(), 
                        iCurrentFrameLength - iProcessor->GetDecoderSpecificInfoSize(), iBufferLength);
            }
            
            // Store PPS id
            iAvcEdit->StoreCurrentPPSId( ptr );
           
            if (iNotCodedFrame)
                delete iNotCodedFrame;
            iNotCodedFrame = 0;                                 
        }        
#endif        
        
        frameInfo.iRepeatFrame = EFalse;            
        iFirstColorTransitionFrame = ETrue; // to indicate that iDataBuffer must not be flushed
                                            // in MtroReturnCodedBuffer
    }    
    
#ifdef VIDEOEDITORENGINE_AVC_EDITING    
    if ( iDataFormat == EDataAVC && iTransitionEffect && iStartTransitionColor == EColorTransition &&
         (iFrameNumber > iFirstIncludedFrameNumber) && iFrameOperation != EDecodeAndWrite)
    {
       TPtr8 ptr(iDataBuffer, iCurrentFrameLength, iBufferLength);
       
       if (!iDecoderSpecificInfoSent)
       {
           ptr.Set(iDataBuffer + iProcessor->GetDecoderSpecificInfoSize(), 
                        iCurrentFrameLength - iProcessor->GetDecoderSpecificInfoSize(), iBufferLength);
       }
       
       if (!(iAvcEdit->IsNALUnitIDR(ptr)))
       {        
           // modify frame number
           iAvcEdit->ModifyFrameNumber(ptr, iModifiedFrameNumber++);       
           PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() modified frame no. => #%d"), iModifiedFrameNumber - 1));
       }
       else
           iModifiedFrameNumber = 1;   // this frame is IDR, start numbering from zero
    }
#endif

    // get timestamp in microseconds
    TTimeIntervalMicroSeconds ts = 
        (iProcessor->GetVideoTimeInMsFromTicks(frameInfo.iTimeStamp, EFalse)) * 1000;
        
    if (ts <= iPreviousTimeStamp)
    {            
        // adjust timestamp so that its bigger than ts of previous frame
        TReal frameRate = iProcessor->GetVideoClipFrameRate();
        VDASSERT(frameRate > 0.0, 106);
        TInt64 durationMs =  TInt64( ( 1000.0 / frameRate ) + 0.5 );
        durationMs /= 2;   // add half the duration of one frame
        
        ts = TTimeIntervalMicroSeconds( iPreviousTimeStamp.Int64() + durationMs*1000 );
        
        frameInfo.iTimeStamp = iProcessor->GetVideoTimeInTicksFromMs( ts.Int64()/1000, EFalse );
                    
        ts = iProcessor->GetVideoTimeInMsFromTicks(frameInfo.iTimeStamp, EFalse) * 1000;
        
        PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() - adjusted timestamp, prev = %d, new = %d"), 
                   I64INT( iPreviousTimeStamp.Int64() ) / 1000, I64INT( ts.Int64() ) / 1000));    

    }
    
    iFrameInfoArray.Append(frameInfo);
            
    iPreviousTimeStamp = ts;
            
#ifdef VIDEOEDITORENGINE_AVC_EDITING
    if (iDataFormat == EDataAVC)
    {
        TPtr8 ptr(iDataBuffer, iCurrentFrameLength, iBufferLength);
        // This has to be updated when cutting from beginning ??
        iAvcEdit->ProcessAVCBitStreamL((TDes8&)(ptr), (TInt&)(iCurrentFrameLength), 
            iProcessor->GetDecoderSpecificInfoSize(), !iDecoderSpecificInfoSent );
        iDataLength = iCurrentFrameLength;
        
    }
#endif

    iMediaBuffer->Set( TPtrC8(iDataBuffer, iBufferLength), 
                              bt, 
                              iCurrentFrameLength, 
                              aKeyFrame,
                              ts);
                                       
    iDecodePending = ETrue;
    if (!IsActive())
    {
        SetActive();
        iStatus = KRequestPending;                                
    }                
    
    
    PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() - transcoder mode is %d"), iTranscoderMode));    
                              
    PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() - WriteCodedBuffer, frame #%d, timestamp %d ms"),
               iFrameNumber, I64INT( ts.Int64() ) / 1000 ));    
               
    PRINT((_L("CVideoProcessor::WriteFrameToTranscoderL() - %d items in queue"), iFrameInfoArray.Count()));                       
               
    iTransCoder->WriteCodedBufferL(iMediaBuffer);
    
}


// ---------------------------------------------------------
// CVideoProcessor::InsertDecoderSpecificInfoL
// Insert AVC dec. config record in the beginning of slice NAL('s)
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::InsertDecoderSpecificInfoL()
{
    
    if (iDataFormat == EDataMPEG4)
    {
        if ( (iDataLength + iDecoderSpecificInfo->Length()) > iBufferLength )
		{
			// extend buffer size
			TUint newSize = iDataLength + iDecoderSpecificInfo->Length();															
            iDataBuffer = (TUint8*) User::ReAllocL(iDataBuffer, newSize);					                    
			iBufferLength = newSize;
		}            
    	Mem::Copy(iDataBuffer+iDecoderSpecificInfo->Length(), iDataBuffer, iCurrentFrameLength);
    	Mem::Copy(iDataBuffer, iDecoderSpecificInfo->Des().Ptr(), iDecoderSpecificInfo->Length());
    	iCurrentFrameLength += iDecoderSpecificInfo->Length();
    	iDataLength += iDecoderSpecificInfo->Length();
     
        return;   
    }
    
    VDASSERT( iDataFormat == EDataAVC, 182 );
            
    // get number of slice NAL's in buffer
    TInt frameLen = 0;        
    TInt numSliceNalUnits = 0;
    TUint8* frameLenPtr = iDataBuffer;
    
    while (frameLen < iCurrentFrameLength)
    {                
        TInt nalLen = 0;
        
        nalLen = (frameLenPtr[0] << 24) + (frameLenPtr[1] << 16) + 
                 (frameLenPtr[2] << 8) + frameLenPtr[3] + 4;  // +4 for length field
                                     
        frameLenPtr += nalLen;
        frameLen += nalLen;
        numSliceNalUnits++;
    }
    
    // get no. of SPS & PPS        

    TUint8* ptr = const_cast<TUint8*>(iDecoderSpecificInfo->Des().Ptr());                
    
    TInt index = 4;  // Skip version and length information                    
    ptr[index] |= 0x03;  // set no. bytes used for length to 4
    
    index++;            
    TInt numSPS = ptr[index] & 0x1f;
    
    index++;
                   
    // Loop all SPS units
    for (TInt i = 0; i < numSPS; ++i)
    {                                
        TInt SPSSize = (ptr[index] << 8) + ptr[index + 1];
        index += 2;
        index += SPSSize;
    }
    TInt numPPS = ptr[index];

    // Align at 32-bit boundrary
    TInt payLoadLen = iCurrentFrameLength + iDecoderSpecificInfo->Length();
    TInt alignmentBytes = (payLoadLen % 4 != 0) * ( 4 - (payLoadLen % 4) );                                
                    
    // get needed buffer length
    TInt minBufLen = iCurrentFrameLength + iDecoderSpecificInfo->Length() + alignmentBytes +
                     ( (numSliceNalUnits + numSPS + numPPS) * 8 ) + 4;
    
    // ReAllocate buffer
    if (iBufferLength < minBufLen)
    {            
        iDataBuffer = (TUint8*) User::ReAllocL(iDataBuffer, minBufLen);
        iBufferLength = minBufLen;
        
        PRINT((_L("CVideoProcessor::XXX() reallocated databuffer, new length = %d"),iBufferLength));
    }

    // move slice NAL's the amount of DCR length
    Mem:: Copy(iDataBuffer + iDecoderSpecificInfo->Length(), iDataBuffer, iCurrentFrameLength);
    
    // copy SPS/PPS data in the beginning
    Mem:: Copy(iDataBuffer, iDecoderSpecificInfo->Des().Ptr(), iDecoderSpecificInfo->Length());
    
    iCurrentFrameLength += iDecoderSpecificInfo->Length();
    
}

// ---------------------------------------------------------
// CVideoProcessor::GetModeChangeL
// Determine need to compr. domain transcoding
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CVideoProcessor::GetModeChangeL()
{

    TInt videoClipNumber = iProcessor->GetVideoClipNumber(); 
	
	// iProcessor->GetModeTranslationMPEG4() returns the overall decision for inserted MPEG4 clips

	TVedTranscodeFactor tFact = iProcessor->GetVideoClipTranscodeFactor(videoClipNumber);
	
	TBool fModeChanged = EFalse;
	
	if (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile) //MPEG4
	{

		switch (tFact.iStreamType)
		{
		case EVedVideoBitstreamModeUnknown:
		case EVedVideoBitstreamModeMPEG4Regular:
		case EVedVideoBitstreamModeMPEG4Resyn:
			fModeChanged = EFalse; // already the target mode
			break;
		case EVedVideoBitstreamModeH263:
			fModeChanged = ETrue;	
			break;
		case EVedVideoBitstreamModeMPEG4ShortHeader:
		default: // other MPEG4 modes
			// if all the MPEG4 (note: it is also considered as MPEG4 type) have the same mode
			// no need to do the mode translation
			fModeChanged = iProcessor->GetModeTranslationMpeg4() ? ETrue: EFalse;
			break;
		}

	}
	else if ( (iProcessor->GetOutputVideoType() == EVedVideoTypeH263Profile0Level10) ||
		      (iProcessor->GetOutputVideoType() == EVedVideoTypeH263Profile0Level45) )
	{

		if (tFact.iStreamType == EVedVideoBitstreamModeH263 || 
			tFact.iStreamType == EVedVideoBitstreamModeMPEG4ShortHeader||
			tFact.iStreamType ==EVedVideoBitstreamModeUnknown)
		{
			fModeChanged = EFalse;
		}
		else
		{
			fModeChanged = ETrue;
		}
	} 
	
#ifdef VIDEOEDITORENGINE_AVC_EDITING
	else if (iProcessor->GetOutputVideoType() == EVedVideoTypeAVCBaselineProfile)
	    fModeChanged = EFalse;
#endif
	
	else // EVedVideoTypeNoVideo
	{
        User::Leave(KErrNotSupported);
	}
	
	return fModeChanged;
    
}

// ---------------------------------------------------------
// CVideoProcessor::DecodeFrameL
// Decode frame in iDataBuffer using vedh263d
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::DecodeFrameL(TInt aOperation, TBool aModeChanged, TInt& aFrameSizeInBytes)
{

    VDASSERT(iDataFormat == EDataH263 || iDataFormat ==  EDataMPEG4, 136);
    
    // go into the decoder 
    TVedColorEffect vedEffect = iProcessor->GetColorEffect();
    CVedH263Dec::TColorEffect effect = (vedEffect == EVedColorEffectNone) ? 
	    CVedH263Dec::EColorEffectNone : ((vedEffect == EVedColorEffectBlackAndWhite) ? CVedH263Dec::EColorEffectBlackAndWhite : CVedH263Dec::EColorEffectToning);

	vdeDecodeParamters_t decodeParams;
	
	// Assign the ColorTone value of the ColorTone	
	// U,V value for the color toning
    TInt colorToneU;
    TInt colorToneV;
    iProcessor->GetColorTone((TInt&)colorToneU, (TInt&)colorToneV);
	
    decodeParams.aColorToneU = colorToneU;
    decodeParams.aColorToneV = colorToneV;
	decodeParams.aColorEffect = effect;
	decodeParams.aFrameOperation = aOperation;
	decodeParams.aGetDecodedFrame = EFalse; //getDecodedFrame; // no need to get YUV
	decodeParams.aSMSpeed = iProcessor->GetSlowMotionSpeed();
	
	TInt trD = iProcessor->GetTrPrevOrig();
	TInt trP = iProcessor->GetTrPrevNew();
	
	decodeParams.aTrD = &trD;
	decodeParams.aTrP = &trP;
	decodeParams.aVideoClipNumber = iProcessor->GetVideoClipNumber();
	
	TVedTranscodeFactor tFact = iProcessor->GetVideoClipTranscodeFactor(decodeParams.aVideoClipNumber);
	
	decodeParams.streamMode = tFact.iStreamType;
	decodeParams.iTimeIncrementResolution = tFact.iTRes;
	decodeParams.aGetVideoMode = EFalse;
	decodeParams.aOutputVideoFormat = iProcessor->GetOutputVideoType();
	
	decodeParams.fModeChanged = aModeChanged;
	decodeParams.fHaveDifferentModes = iProcessor->GetModeTranslationMpeg4() ? ETrue: EFalse;
	/* Color Toning */
	decodeParams.aFirstFrameQp = iFirstFrameQp;
		
	// : Optimisation - If the frame is to be encoded, there is no need
	//       to process it using vedh263d in all cases, for example when
	//       doing end transition. In start transition case it has to be done
	//       so that compressed domain transcoding can continue after transition

	// before decoding, set the time infomation in the decoder parameters
	decodeParams.aMPEG4TimeStamp = iMPEG4Timer->GetMPEG4TimeStampPtr();
	decodeParams.aMPEG4TargetTimeResolution = iMPEG4Timer->GetMPEG4TimeResolutionPtr();
	    
	decodeParams.vosHeaderSize = 0;
    
    // +3 includes the next PSC or EOS in the bit buffer
    TPtrC8 inputPtr(iDataBuffer, iCurrentFrameLength + (iDataFormat==EDataH263 ? KH263StartCodeLength : KMPEG4StartCodeLength));
    
    // check output buffer size & reallocate if its too small    
    if ( TReal(iOutVideoFrameBufferLength) < TReal(iCurrentFrameLength) * 1.5 )
    {
        TInt newLen = TInt( TReal(iCurrentFrameLength) * 1.5 );
        
        iOutVideoFrameBuffer = (TUint8*) User::ReAllocL(iOutVideoFrameBuffer, newLen);
        iOutVideoFrameBufferLength = newLen;                
        
        PRINT((_L("CVideoProcessor::DecodeFrameL() reallocated output buffer, new size = %d"),
                   iOutVideoFrameBufferLength));
    }
    
    TPtr8 outputPtr(iOutVideoFrameBuffer, 0, iOutVideoFrameBufferLength);        
    
    TInt frameSize = 0;
    TBool wasFirstFrame = iFirstFrameFlag; // need to save the value since it may be changed inside
    iDecoder->DecodeFrameL(inputPtr, outputPtr, iFirstFrameFlag, frameSize, &decodeParams);

	if (frameSize > (TInt)iCurrentFrameLength)
    {
        // decoder used more data than was in the buffer => corrupted bitstream
        PRINT((_L("CVideoProcessor::DecodeFrameL() decoder used more data than was in the buffer => corrupted bitstream")));
        User::Leave( KErrCorrupt );
    }
    
    aFrameSizeInBytes = outputPtr.Length();    
    
    /* record first frame QP */
    if ((iFrameNumber==0) && wasFirstFrame) 
    {
        iFirstFrameQp = decodeParams.aFirstFrameQp;
	    
        if (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile)
            {
            PRINT((_L("CVideoProcessor::DecodeFrameL() save VOS header, size %d"), decodeParams.vosHeaderSize));
            // sync the vol headers
            if ( decodeParams.vosHeaderSize > iOutputVolHeader->Des().MaxLength() )
                {
                delete iOutputVolHeader;
                iOutputVolHeader = NULL;
                iOutputVolHeader = HBufC8::NewL(decodeParams.vosHeaderSize);
                }
            iOutputVolHeader->Des().Copy( outputPtr.Ptr(), decodeParams.vosHeaderSize );
            }
    }
    
    PRINT((_L("CVideoProcessor::DecodeFrameL() out")));
}

// ---------------------------------------------------------
// CVideoProcessor::CreateAndInitializeTranscoderL
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::CreateAndInitializeTranscoderL(TVedVideoType aInputType, CTRTranscoder::TTROperationalMode aMode)
{

    PRINT((_L("CVideoProcessor::CreateAndInitializeTranscoderL() begin")));    
    
    VDASSERT(iTransCoder == 0, 27);
    
    iTransCoder = CTRTranscoder::NewL(*this); 
    
    TBufC8<256> inputMime;
    
//  TInt volLength = 0;    
    TInt outputBufferSize = 0;
    iInputMPEG4ProfileLevelId = 0;

    if (aInputType == EVedVideoTypeMPEG4SimpleProfile)
    {                
        // Get the VOL header from the frame data
	    CVedVolReader* reader = CVedVolReader::NewL();
	    CleanupStack::PushL(reader);
	    // Get pointer to the frame data
	    TPtrC8 inputPtr(iDecoderSpecificInfo->Des());
	    reader->ParseVolHeaderL((TDesC8&) inputPtr);
	    
	    iInputMPEG4ProfileLevelId = reader->ProfileLevelId();	    
	    
	    iInputTimeIncrementResolution = reader->TimeIncrementResolution();
	    
	    iInputStreamMode = reader->BitstreamMode();

	    switch (iInputMPEG4ProfileLevelId)
	    {		    
	    	case 8:
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=8");
	    	    outputBufferSize = KMaxCodedPictureSizeMPEG4QCIF / 2;
	    	    break;
	    	
	    	case 9:	    	
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=9");
	    	    outputBufferSize = KMaxCodedPictureSizeMPEG4L0BQCIF / 2;
	    	    break;
	    	
	    	case 1:
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=1");	    	    
	    	    outputBufferSize = KMaxCodedPictureSizeMPEG4QCIF / 2;
	    	    break;
	    	
	    	case 2:
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=2");
	    	    outputBufferSize = KMaxCodedPictureSizeMPEG4CIF / 2;
	    	    break;
	    	
	    	case 3:
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=3");
	    	    outputBufferSize = KMaxCodedPictureSizeMPEG4CIF / 2;
	    	    break;
	    	    
	        case 4:
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=4");
	    	    outputBufferSize = KMaxCodedPictureSizeVGA / 2;
	    	    break;
	    		    		    	
	    	default:
	    	    inputMime = _L8("video/mp4v-es; profile-level-id=8");
	    	    outputBufferSize = KMaxCodedPictureSizeMPEG4QCIF / 2;
	    	    break;
	    }
	    
//	    volLength = reader->HeaderSize();
	    CleanupStack::PopAndDestroy(reader);        
    }    
    
    else if (aInputType == EVedVideoTypeH263Profile0Level10)
    {        
        inputMime = _L8("video/H263-2000; profile=0; level=10");
        outputBufferSize = KMaxCodedPictureSizeQCIF / 2;
    }
    
    else if (aInputType == EVedVideoTypeH263Profile0Level45)
    {        
        inputMime = _L8("video/H263-2000; profile=0; level=45");
        outputBufferSize = KMaxCodedPictureSizeQCIF / 2;
    }
    
    else if (aInputType == EVedVideoTypeAVCBaselineProfile)
    {
        // get input avc level        
        VDASSERT( iAvcEdit != 0, 181 );        
        VDASSERT( iDecoderSpecificInfo, 181 );
        
        TPtr8 info = iDecoderSpecificInfo->Des();
        User::LeaveIfError( iAvcEdit->GetLevel(info, iInputAVCLevel) );
                
        switch (iInputAVCLevel)
        {
            case 10:
                inputMime = _L8("video/H264; profile-level-id=42800A");                
                outputBufferSize = KMaxCodedPictureSizeAVCLevel1 / 2;
                break;
           
            case 101:
                inputMime = _L8("video/H264; profile-level-id=42900B");
                outputBufferSize = KMaxCodedPictureSizeAVCLevel1B / 2;
                break;
            
            case 11:
                inputMime = _L8("video/H264; profile-level-id=42800B");
                outputBufferSize = KMaxCodedPictureSizeAVCLevel1_1 / 2;
                break;
            
            case 12:
                inputMime = _L8("video/H264; profile-level-id=42800C");
                outputBufferSize = KMaxCodedPictureSizeAVCLevel1_2 / 2;
                break;
                
            // NOTE: Levels 1.3 and 2 are enabled for testing purposes,
            //       to be removed
            case 13:
                inputMime = _L8("video/H264; profile-level-id=42800D");
                outputBufferSize = KMaxCodedPictureSizeAVCLevel1_3 / 2;
                break;  
                
            case 20:
                inputMime = _L8("video/H264; profile-level-id=428014");
                outputBufferSize = KMaxCodedPictureSizeAVCLevel2 / 2;
                break;
                
            //WVGA task
            case 21:
                inputMime = _L8("video/H264; profile-level-id=428015");
                outputBufferSize = KMaxCodedPictureSizeAVCLevel2_1 / 2;
                break;
                
            case 22:
            	inputMime = _L8("video/H264; profile-level-id=428016");
            	outputBufferSize = KMaxCodedPictureSizeAVCLevel2_2 / 2;
            	break;                

            case 30:
            	inputMime = _L8("video/H264; profile-level-id=42801E");
            	outputBufferSize = KMaxCodedPictureSizeAVCLevel3 / 2;
            	break;   
               
            case 31:
            	inputMime = _L8("video/H264; profile-level-id=42801F");
            	outputBufferSize = KMaxCodedPictureSizeAVCLevel3_1 / 2;
            	break;                             
   
            default:
                User::Leave(KErrNotSupported);
                break;            
        }              
    }
           
    else
        User::Leave(KErrNotSupported);                  
    
    if ( !(iTransCoder->SupportsInputVideoFormat(inputMime) ) )
        {
        User::Leave(KErrNotSupported);
        }            
        
        
    // default framerate is 15 fps
    TReal frameRate = 15.0;
    
    iOutputBitRate = 64000;
        
    if ( aMode == CTRTranscoder::EFullTranscoding )
    {                
        // get output mime type 
        SetOutputVideoCodecL(iProcessor->GetOutputVideoMimeType());    
        
        if ( !(iTransCoder->SupportsOutputVideoFormat(iOutputMimeType) ) )
            {
            User::Leave(KErrNotSupported);
            }            
        
        // check output resolution
        TSize outputResolution = iProcessor->GetMovieResolution();
        
        if ( (outputResolution.iWidth > iMaxOutputResolution.iWidth) || (outputResolution.iHeight > iMaxOutputResolution.iHeight))
            {
            if ( iArbitrarySizeAllowed ) // This is for future-proofness. Currently the checking of standard sizes below overrules this one
                {
                if ( outputResolution.iWidth * outputResolution.iHeight > iMaxOutputResolution.iWidth*iMaxOutputResolution.iHeight )
                    {
                    PRINT((_L("CVideoProcessor::CreateAndInitializeTranscoderL() too high resolution requested")));
                    User::Leave( KErrNotSupported );
                    }
                }
            else
                {
                PRINT((_L("CVideoProcessor::CreateAndInitializeTranscoderL() incompatible or too high resolution requested")));
                User::Leave( KErrNotSupported );
                }
            }
        
    	// check size. For now only standard sizes are allowed
    	if ( (outputResolution != KVedResolutionSubQCIF) && 
    		 (outputResolution != KVedResolutionQCIF) &&
    		 (outputResolution != KVedResolutionCIF) &&
    		 (outputResolution != KVedResolutionQVGA) &&
    		 (outputResolution != KVedResolutionVGA16By9) &&
    		 (outputResolution != KVedResolutionVGA) &&
    		 //WVGA task
    		 (outputResolution != KVedResolutionWVGA) )
    	{
    		 User::Leave( KErrArgument );
    	}
    	
    	// check output frame rate    	
    	TReal movieFrameRate = iProcessor->GetMovieFrameRate();
    	
    	if ( movieFrameRate > 0.0 )
    	{	    	
        	if ( movieFrameRate <= iMaxOutputFrameRate )
            {
                frameRate = TReal32(movieFrameRate);
            }
            else
            {
                frameRate = iMaxOutputFrameRate;
            }
    	}    	
            
        // check output bitrate    
        TInt movieBitRate = iProcessor->GetMovieVideoBitrate();
        TInt standardBitRate = iProcessor->GetMovieStandardVideoBitrate();
        
        if ( movieBitRate > 0 )
        {            
            if ( movieBitRate <= iMaxOutputBitRate )
            {
                iOutputBitRate = movieBitRate;
            }
            else
            {
                iOutputBitRate = iMaxOutputBitRate;
            }
        } 
        else if ( standardBitRate > 0 )
        {
            if ( standardBitRate <= iMaxOutputBitRate )
            {
                iOutputBitRate = standardBitRate;
            }
            else
            {
                iOutputBitRate = iMaxOutputBitRate;
            }
        }    
    } 
    else 
    {
       iOutputMimeType = KNullDesC8;   
    }   
                
    TTRVideoFormat videoInputFormat;
    TTRVideoFormat videoOutputFormat;
    
    if (!iThumbnailMode)
    {
        videoInputFormat.iSize = iProcessor->GetVideoClipResolution();
        videoOutputFormat.iSize = iProcessor->GetMovieResolution();
    }
    else
    {
        videoInputFormat.iSize = videoOutputFormat.iSize = TSize(iVideoWidth, iVideoHeight);
    }
    
    videoInputFormat.iDataType = CTRTranscoder::ETRDuCodedPicture;
    
    if (aMode == CTRTranscoder::EFullTranscoding)
        videoOutputFormat.iDataType = CTRTranscoder::ETRDuCodedPicture;
    else
        videoOutputFormat.iDataType = CTRTranscoder::ETRYuvRawData420;
    

    iTransCoder->OpenL( this,
                        aMode,                        
                        inputMime,
                        iOutputMimeType,
                        videoInputFormat,
                        videoOutputFormat,
                        EFalse );    
    
     
    iTransCoder->SetVideoBitRateL(iOutputBitRate);
    
    if (!iThumbnailMode)
    { 
        // check framerate: target framerate cannot be larger than source framerate
        TReal inputFR = iProcessor->GetVideoClipFrameRate();       
        if ( inputFR <= 15.0 )
        {
            inputFR = 15.0;
        }
        else
        {
            inputFR = 30.0;
        }    
        if (frameRate > inputFR)
            frameRate = inputFR;
    }
    
    iTransCoder->SetFrameRateL(frameRate);           
    iTransCoder->SetChannelBitErrorRateL(0.0);         
       
    // dummy
    TTRVideoCodingOptions codingOptions;
    codingOptions.iSyncIntervalInPicture = iProcessor->GetSyncIntervalInPicture();
    codingOptions.iMinRandomAccessPeriodInSeconds = (TInt) (1.0 / iProcessor->GetRandomAccessRate());        
    codingOptions.iDataPartitioning = EFalse;
    codingOptions.iReversibleVLC = EFalse;
    codingOptions.iHeaderExtension = 0;
   
    iTransCoder->SetVideoCodingOptionsL(codingOptions);
   
    TSize targetSize;
    if (!iThumbnailMode)
        targetSize = iProcessor->GetMovieResolution();
    else
        targetSize = TSize(iVideoWidth, iVideoHeight);
    
    iTransCoder->SetVideoPictureSinkOptionsL(targetSize, this);
    
    iTransCoder->EnableEncoder(EFalse);
    iTransCoder->EnablePictureSink(ETrue);
    iTranscoderMode = EDecodeOnly;
    
    // set init. data
    TPtrC8 initData;
    if (aInputType == EVedVideoTypeMPEG4SimpleProfile || 
        aInputType == EVedVideoTypeAVCBaselineProfile)
    {
        initData.Set(iDecoderSpecificInfo->Des());
    }
    else
        initData.Set(iDataBuffer, iCurrentFrameLength); 
    
    iDecoderSpecificInfoSent = EFalse;
    
    iTransCoder->SetDecoderInitDataL( initData );
    
    if (!iThumbnailMode)
    {        
        // allocate output bitstream buffer for processing with vedh263d
        VDASSERT( outputBufferSize != 0, 52 );
        iOutVideoFrameBuffer = (TUint8*) User::AllocL(outputBufferSize);
    	iOutVideoFrameBufferLength = outputBufferSize;
    }
        
    iTranscoderInitPending = ETrue;               
    
    if (!IsActive())    
    {        
        SetActive();
        iStatus = KRequestPending;        
    }
    
    
    iTransCoder->InitializeL();
    
    // Get processing time estimate from transcoder, divide it by the framerate to get processing time per frame
    // and then multiply it by 2 to get some safety margin and by unit conversion factor 1000000. 
    // The delay is used to determine if a frame was skipped, hence there should be some margin.
#ifdef __WINSCW__
    iMaxEncodingDelay = 5000000;    // emulator can be really slow, use 5 seconds timeout
#else    
    iMaxEncodingDelay = (TUint)(2*1000000*iTransCoder->EstimateTranscodeTimeFactorL(videoInputFormat,videoOutputFormat)/frameRate);
#endif
    
    iMaxItemsInProcessingQueue = iTransCoder->GetMaxFramesInProcessing();
    
    PRINT((_L("CVideoProcessor::CreateAndInitializeTranscoderL() end")));    
}

// ---------------------------------------------------------
// CVideoProcessor::MtroInitializeComplete
// Called by transcoder to indicate init. completion
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroInitializeComplete(TInt aError)
{    

    TInt error = aError;
    TInt outputTimeIncrementResolution = KDefaultTimeIncrementResolution;
    
    PRINT((_L("CVideoProcessor::MtroInitializeComplete() error = %d"), aError));
    
    if ( !iThumbnailMode && (aError == KErrNone) &&
         ( (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile) 
#ifdef VIDEOEDITORENGINE_AVC_EDITING
        || (iProcessor->GetOutputVideoType() == EVedVideoTypeAVCBaselineProfile) 
#endif
         ) )
    {    
        PRINT((_L("CVideoProcessor::MtroInitializeComplete() calling GetCodingStandardSpecificInitOutputLC")));
        
        // get & save vol header from encoder
	    TRAP(error,
	    {
	        iOutputVolHeader = iTransCoder->GetCodingStandardSpecificInitOutputLC();
	        CleanupStack::Pop();
	    });
	    
	    iOutputVolHeaderWritten = EFalse;
	    
	    if ( error == KErrNone )
	    {
	    
#ifdef VIDEOEDITORENGINE_AVC_EDITING
	        if (iProcessor->GetOutputVideoType() == EVedVideoTypeAVCBaselineProfile)
	        {
	            // Check if we need to use encoder
	            // : Are there any other cases where encoder is used _
	            if ( iFullTranscoding || iTransitionEffect || 
	                 iProcessor->GetStartCutTime() != TTimeIntervalMicroSeconds(0) )
	            {	                
    	            HBufC8* outputAVCHeader = 0;
    	            // is the max. size of AVCDecoderConfigurationRecord known here ??
    	            TRAP(error, outputAVCHeader = (HBufC8*) HBufC8::NewL(16384));	            

                    if (error == KErrNone)
                    {   
        	            TPtr8 ptr = outputAVCHeader->Des();
        	            
        	            // parse header & convert it to AVCDecoderConfigurationRecord -format
        	            TRAP(error, iAvcEdit->ConvertAVCHeaderL(*iOutputVolHeader, ptr));
        	            
        	            if (error == KErrNone)
        	            {
        	                TRAP(error, iAvcEdit->SaveAVCDecoderConfigurationRecordL(ptr, ETrue));    	                
        	            }    	        
                    } 
                    if (outputAVCHeader)
                        delete outputAVCHeader;
	            }
	            
	            iEncodeUntilIDR = 0;
	            if ( iStartOfClipTransition != 0 || 
	                 iProcessor->GetStartCutTime() != TTimeIntervalMicroSeconds(0) )
	            {
	                // we need to use encoder at the beginning, now determine
	                // if we have to encode frames after cut / transition until
	                // input frame is IDR
	                iEncodeUntilIDR = iAvcEdit->EncodeUntilIDR();
	            }
	        }
	        else
#endif
	        {
	        
    	        VDASSERT(iOutputVolHeader, 49);

    	        // get time increment resolution using vol reader
    	        CVedVolReader* reader = NULL;	                                
    	        TRAP( error, reader = CVedVolReader::NewL() );	        
    	        
    	        if ( error == KErrNone )
    	        {	            	            
    	            TRAP( error, reader->ParseVolHeaderL( (TDesC8&) *iOutputVolHeader ) );
    	            if (error == KErrNone)
    	            {	                
                        outputTimeIncrementResolution = reader->TimeIncrementResolution();     
    	            }
    	            delete reader;	            	            	            	            
    	        }
	        }

	    }
    }

    if (error == KErrNone)
    {        
        // create MPEG-4 timing instance
        TRAP(error, iMPEG4Timer = CMPEG4Timer::NewL(iProcessor, outputTimeIncrementResolution));
    }   
    
    // enable pausing
    if ( ((iFullTranscoding) 
           || (iProcessor->GetStartCutTime() > 0))
        && (iStartOfClipTransition == 0) 
        && (iEndOfClipTransition == 0) )
        {
        // safe to enable pausing during transcoding: 
        // only when doing full transcoding or cutting from the beginning, but not if transitions
        // rules out e.g. thumbnails, and codec-free cases
        iTransCoder->EnablePausing(ETrue);
        }
            
    VDASSERT(iTranscoderInitPending, 28);
    // complete request    
    TRequestStatus *status = &iStatus;
    User::RequestComplete(status, error);
        
}

// ---------------------------------------------------------
// CVideoProcessor::MtroFatalError
// Called by transcoder to indicate a fatal error
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroFatalError(TInt aError)
{
    PRINT((_L("CVideoProcessor::MtroFatalError() %d"), aError));   
    
    if (iFullTranscoding || iThumbnailMode || iTransitionEffect || (iProcessor->GetStartCutTime() > 0))
        {
        // ok, this is fatal, continue the method
        PRINT((_L("CVideoProcessor::MtroFatalError() transcoder is in use, this is fatal")));   
        }
    else
        {
        // transcoder not in use, ignore
        PRINT((_L("CVideoProcessor::MtroFatalError() transcoder not in use, ignore")));   
        return;
        }
        
    // stop decoding
    Stop();
    
    if (!iThumbnailMode)
        iMonitor->Error(aError);
    else
        iProcessor->NotifyThumbnailReady(aError);

}

// ---------------------------------------------------------
// CVideoProcessor::MtroSuspend
// Suspends processing
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroSuspend()
{

    PRINT((_L("CVideoProcessor::MtroSuspend()")));   
    
    if (iProcessingComplete || (!iProcessor->NeedTranscoderAnyMore()))
        {
        PRINT((_L("CVideoProcessor::MtroSuspend(), this clip done or no video at all to process any more, ignore")));
        return;
        }
    
    Cancel();
	iDecoding = EFalse;
	iDecodePending = EFalse;
	iDecodingSuspended = EFalse;
		
    if (iTimer)
        iTimer->CancelTimer();
            
    iProcessor->SuspendProcessing();
    
    // flush input queue
    if (iBlock)    
		iQueue->ReturnBlock(iBlock);
	iBlock = iQueue->ReadBlock();
	while (iBlock)
	{
		iQueue->ReturnBlock(iBlock);
		iBlock = iQueue->ReadBlock();
	}
	iBlockPos = 0;
	
	iTranscoderMode = EUndefined;   // force to reset the mode when writing the next picture
	
}

// ---------------------------------------------------------
// CVideoProcessor::MtroResume
// Re-starts processing after pause
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroResume()
{
    PRINT((_L("CVideoProcessor::MtroResume()")));
    
    if (iProcessingComplete)
        {
        PRINT((_L("CVideoProcessor::MtroResume(), processing of this clip completed, continue")));   
        // fake RunL with this flag
        iDecoding = ETrue;
        if (!IsActive())
            {
             // Make us active
            PRINT((_L("CVideoProcessor::MtroResume() set active")));
            SetActive();
            iStatus = KRequestPending;
            }
        }
        
    if (!iProcessor->NeedTranscoderAnyMore())
        {
        PRINT((_L("CVideoProcessor::MtroResume(), no video to process any more, ignore")));   
        return;
        }
    
    // flush frame info array and cancel timer
    if (iTimer)
        iTimer->CancelTimer();
    iFrameInfoArray.Reset();
    
    Start();

    TInt error = iProcessor->ResumeProcessing(iFrameNumber, iLastWrittenFrameNumber);
    if (error != KErrNone)
        iMonitor->Error(error);
    
    iNumberOfFrames = iProcessor->GetClipNumberOfFrames();                 
    iPreviousTimeStamp = TTimeIntervalMicroSeconds(-1);
    
    iDataLength = iCurrentFrameLength = 0;
    iDataFormat = EDataUnknown;
    
    iStreamEnd = iStreamEndRead = 0;
    
    // reset also delayed buffer; it will need to be anyway re-read
    delete iDelayedBuffer;
    iDelayedBuffer = 0;
    iDelayedWrite = EFalse;        
        
    PRINT((_L("CVideoProcessor::MtroResume() - iFrameNumber = %d"), iFrameNumber));
    
    if (!IsActive())
    {
         // Make us active
        PRINT((_L("CVideoProcessor::MtroResume() set active")));
        SetActive();
        iStatus = KRequestPending;
    }

    PRINT((_L("CVideoProcessor::MtroResume() out")));
    
}

// ---------------------------------------------------------
// CVideoProcessor::MtroReturnCodedBuffer
// Called by transcoder to return bitstream buffer
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroReturnCodedBuffer(CCMRMediaBuffer* aBuffer)
{

    VDASSERT(aBuffer == iMediaBuffer, 29);

    iIsThumbFrameBeingCopied = EFalse;
    iDecoderSpecificInfoSent = ETrue;
    
#ifdef _DEBUG
    TTimeIntervalMicroSeconds ts = aBuffer->TimeStamp();        
    
    PRINT((_L("CVideoProcessor::MtroReturnCodedBuffer() timeStamp = %d ms"), 
             I64INT( ts.Int64() ) / 1000 ));                    

#endif
    
    if (!iFirstColorTransitionFrame)
    {        
        // Throw away the data for this frame:
        VDASSERT(iDataLength >= iCurrentFrameLength,4);
        Mem::Copy(iDataBuffer, iDataBuffer + iCurrentFrameLength,
            iDataLength - iCurrentFrameLength);
        iDataLength = iDataLength - iCurrentFrameLength;        
        iCurrentFrameLength = 0;
    }
    
    if (!iThumbnailMode)
    {            
    
        // check if the next frame in queue is waiting to be encoded
        // and start timer to detect possible frameskip
        if ( IsNextFrameBeingEncoded() )
        {
            if ( !iTimer->IsPending() )
                iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
        }       

        if (iFrameInfoArray.Count() >= iMaxItemsInProcessingQueue)
        {
            PRINT((_L("CVideoProcessor::MtroReturnCodedBuffer() - %d items in queue, suspend decoding"), 
             iFrameInfoArray.Count() ));   
        
            iDecodingSuspended = ETrue;
                                                         
            return;                        
        }
    
        VDASSERT(IsActive(), 40);        
        VDASSERT(iDecodePending, 41);
            
        // complete request    
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, KErrNone);
    } 
    else if (iDataFormat == EDataAVC)
    {

        VDASSERT(IsActive(), 40);        
        VDASSERT(iDecodePending, 41);
        
        // NOTE: it would make sense to call AsyncStopL() here, 
        // but at least in WINSCW it didn't  have any effect        
         //if (iThumbFramesToWrite == 0)
               //{
               //iTransCoder->AsyncStopL();
               //iTranscoderStarted = EFalse;               
               //}
            
        if (iStatus == KRequestPending)
        {
            PRINT((_L("CVideoProcessor::MtroReturnCodedBuffer() - completing request")));
            // complete request    
            TRequestStatus *status = &iStatus;
            User::RequestComplete(status, KErrNone);
        }
    }
}

// ---------------------------------------------------------
// CVideoProcessor::MtroSetInputFrameRate
// Called by transcoder to request inout framerate
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroSetInputFrameRate(TReal& aRate)
{    
    TReal rate = iProcessor->GetVideoClipFrameRate();
       
    if ( rate <= 15.0 )
    {
        rate = 15.0;
    }
    else
    {
        rate = 30.0;
    }
   
    aRate = rate;
}

// ---------------------------------------------------------
// CVideoProcessor::MtroAsyncStopComplete
// Called by transcoder after async. stop is complete
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroAsyncStopComplete()
{
    PRINT((_L("CVideoProcessor::MtroAsyncStopComplete()")));
}

// ---------------------------------------------------------
// CVideoProcessor::MtroPictureFromTranscoder
// Called by transcoder to return a decoded picture
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::MtroPictureFromTranscoder(TTRVideoPicture* aPicture)
{    

    TTimeIntervalMicroSeconds decodedTs = aPicture->iTimestamp;        
    
    PRINT((_L("CVideoProcessor::MtroPictureFromTranscoder(), timestamp %d ms"),
               I64INT( decodedTs.Int64() ) / 1000 ));
               
	if (iThumbnailMode)
	{	    
	    iThumbDecoded = ETrue;
	    
	    // handle thumbnail
	    HandleThumbnailFromTranscoder(aPicture);
	    
        return;
	}                

    // search the decoded frame from list                  
    TInt index;
    for (index = 0; index < iFrameInfoArray.Count(); )
    {      
        PRINT((_L("CVideoProcessor::MtroPictureFromTranscoder(), checking frame with index %d"), index));
          
        TTimeIntervalMicroSeconds ts = 
            (iProcessor->GetVideoTimeInMsFromTicks(iFrameInfoArray[index].iTimeStamp, EFalse)) * 1000;
            
        if (ts < decodedTs && ( (iFrameInfoArray[index].iEncodeFrame == EFalse) ||
                                 (iFrameInfoArray[index].iTranscoderMode == EFullWithIM &&
                                  iFrameInfoArray[index].iModificationApplied == 0) ) )        
        {
            // if there are decode-only or transcoding w/intermediate modification
            // frames in the queue before this one, remove those                
            PRINT((_L("CVideoProcessor::MtroPictureFromTranscoder(), removing frame with timestamp %d ms"),
                I64INT( ts.Int64() ) / 1000 ));
        
            iFrameInfoArray.Remove(index);
            // don't increment index
            continue;
        }
            
        if (ts == decodedTs)    
        {
            PRINT((_L("CVideoProcessor::MtroPictureFromTranscoder(), found decoded frame at index %d"), index));
            break;
        }
            
        index++;
    }

    // If decoded frame is unexpected, i.e. it is not found from book-keeping, 
    // or it is not an intermediate modification frame, return frame here
    // and continue
    if ( index >= iFrameInfoArray.Count() || 
        ( iFrameInfoArray[index].iEncodeFrame == 1 && 
          iFrameInfoArray[index].iTranscoderMode != EFullWithIM ) )
        {
        PRINT((_L("CVideoProcessor::MtroPictureFromTranscoder(), unexpected decoded frame, iTranscoderMode %d"), iTranscoderMode));
        // send picture back to transcoder
        TInt error = KErrNone;
        TRAP( error, iTransCoder->SendPictureToTranscoderL(aPicture) );
        if ( error != KErrNone )
        {
            iMonitor->Error(error);
        }    
        return;
        }

    if (iFrameInfoArray[index].iEncodeFrame == EFalse)
    {    
        // handle decode-only frame
        HandleDecodeOnlyFrameFromTranscoder(aPicture, index);        
        return;
    }

    // check color effect
    TInt colorEffect = TColorEffect2TInt( iProcessor->GetColorEffect() );
    if (colorEffect != 0/*None*/)
    {
        // U,V value for the color toning 
        TInt colorToneU;
        TInt colorToneV;
        iProcessor->GetColorTone((TInt&)colorToneU, (TInt&)colorToneV);
    	// apply color effect
    	ApplySpecialEffect( colorEffect, const_cast<TUint8*>(aPicture->iRawData->Ptr()), colorToneU, colorToneV );
        
    }
    
    if(iFrameInfoArray[index].iTransitionFrame == 1)
    {
        // apply transition to frame
		HandleTransitionFrameFromTranscoder(aPicture, index);
    }
        
    iFrameInfoArray[index].iModificationApplied = ETrue;
    
    // send picture back to transcoder for encoding
    TInt error = KErrNone;
    TRAP( error, iTransCoder->SendPictureToTranscoderL(aPicture) );
    if ( error != KErrNone )
    {
        iMonitor->Error(error);
        return;
    }    
    
    // check if the next frame is waiting to be encoded, set timer if so
    if ( IsNextFrameBeingEncoded() )
    {
        if ( !iTimer->IsPending() )
            iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
    }
    
}


// ---------------------------------------------------------
// CVideoProcessor::HandleThumbnailFromTranscoder
// Handle thumbnail frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::HandleThumbnailFromTranscoder(TTRVideoPicture* aPicture)
{

    TInt error = KErrNone;
    
    PRINT((_L("CVideoProcessor::HandleThumbnailFromTranscoder() begin")));   
 
    if (iProcessingComplete)
    {   	    
        // if requested thumbnail has been done already,
        // just release picture and return
        PRINT((_L("CVideoProcessor::HandleThumbnailFromTranscoder(), thumb already finished, returning")));   
        
        TRAP( error, iTransCoder->SendPictureToTranscoderL(aPicture) );
        if ( error != KErrNone )
        {
            iMonitor->Error(error);
            return;
        }
        return;
    }	   

    TInt yuvLength = iVideoWidth*iVideoHeight;
    yuvLength += (yuvLength >> 1);
    // copy to iFrameBuffer	
    Mem::Copy(iFrameBuffer, aPicture->iRawData->Ptr(), yuvLength);
    
    // release picture
    TRAP( error, iTransCoder->SendPictureToTranscoderL(aPicture) );
    if ( error != KErrNone )
    {
        iProcessor->NotifyThumbnailReady(error);
        return;
    }
    
    VDASSERT(iDecodePending, 33);
    VDASSERT(IsActive(), 150);
    
    if (iStatus == KRequestPending)
    {            
    
        PRINT((_L("CVideoProcessor::HandleThumbnailFromTranscoder(), complete request")));   
        // complete request    
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, KErrNone);
    }    
    
    PRINT((_L("CVideoProcessor::HandleThumbnailFromTranscoder() end")));   
}

// ---------------------------------------------------------
// CVideoProcessor::HandleDecodeOnlyFrameFromTranscoder
// Handle decode-only frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::HandleDecodeOnlyFrameFromTranscoder(TTRVideoPicture* aPicture, TInt aIndex)
{

    VDASSERT(iFrameInfoArray[aIndex].iTranscoderMode == EDecodeOnly, 43);
        
    if ( iFrameInfoArray[aIndex].iTransitionFrame && 
         iFrameInfoArray[aIndex].iTransitionPosition == EPositionEndOfClip  )
    {
		if ( iEndTransitionColor == EColorTransition )
        {    			
		    // Save decoded frame to file
		    
		    TSize a = iProcessor->GetMovieResolution();
            TInt yuvLength = a.iWidth*a.iHeight;						
			yuvLength += (yuvLength>>1); 
			TPtr8 ptr(0,0);
			TUint8* tmpBuf=0;					
			
			ptr.Set( *aPicture->iRawData );
            tmpBuf = const_cast<TUint8*>(aPicture->iRawData->Ptr());
							
			TInt colorEffect = TColorEffect2TInt( iProcessor->GetColorEffect() );
			if (colorEffect != 0 /*None*/)
			{
			    // U,V value for the color toning
                TInt colorToneU;
                TInt colorToneV;
                iProcessor->GetColorTone((TInt&)colorToneU, (TInt&)colorToneV);
				// apply special effect
				ApplySpecialEffect( colorEffect, tmpBuf, colorToneU, colorToneV ); 
			}
			    				    				    				
            TInt frameDuration = GetFrameDuration(iFrameInfoArray[aIndex].iFrameNumber);

            if (frameDuration <= 0)
            {
                TReal frameRate = iProcessor->GetVideoClipFrameRate();
                VDASSERT(frameRate > 0.0, 107);
                TInt timeScale = iProcessor->GetVideoClipTimeScale();                    
                TInt64 durationMs =  TInt64( ( 1000.0 / frameRate ) + 0.5 );            

                // in ticks
                frameDuration = TInt( ( (TReal)durationMs * (TReal)timeScale / 1000.0 ) + 0.5 ); 
            }                                     

            TInt error = iProcessor->SaveVideoFrameToFile( ptr, frameDuration, iFrameInfoArray[aIndex].iTimeStamp );
			if ( error != KErrNone )
			{
			    PRINT((_L("CVideoProcessor::HandleDecodeOnlyFrameFromTranscoder() - SaveVideoFrameToFile failed")));
				iMonitor->Error(error);
				return;
			}    				
        }
    }       
    
    iFrameInfoArray.Remove(aIndex);
    
    PRINT((_L("CVideoProcessor::HandleDecodeOnlyFrameFromTranscoder() - removed decode only pic, %d items in queue"), 
        iFrameInfoArray.Count()));

    // release picture
    TInt error = KErrNone;
    TRAP( error, iTransCoder->SendPictureToTranscoderL(aPicture) );
    if ( error != KErrNone )
    {
        iMonitor->Error(error);
        return;
    }
    
    if (iStreamEndRead && iFrameInfoArray.Count() == 0 )
    {            
        PRINT((_L("CVideoProcessor::HandleDecodeOnlyFrameFromTranscoder() - stream end read, no frames left")));       
        if (!IsActive())
        {
            SetActive();
            iStatus = KRequestPending;
        }
        iTimer->CancelTimer();
        iProcessingComplete = ETrue;
        // activate object to end processing
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, KErrNone);
        return;
    }
    
    if (iDecodingSuspended && !iStreamEndRead)
    {
        if (iFrameInfoArray.Count() < iMaxItemsInProcessingQueue && !iDelayedWrite)
        {            
            PRINT((_L("CVideoProcessor::HandleDecodeOnlyFrameFromTranscoder() - Resume decoding")));
            iDecodingSuspended = EFalse;
            // activate object to start decoding
            TRequestStatus *status = &iStatus;
            User::RequestComplete(status, KErrNone);
            return;
        }
    }
    
    // check if the next frame is waiting to be encoded, set timer if so
    if ( IsNextFrameBeingEncoded() )
    {
        if ( !iTimer->IsPending() )
            iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
    }
                    
    return;
    
}


// ---------------------------------------------------------
// CVideoProcessor::HandleTransitionFrameFromTranscoder
// Handle transition frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::HandleTransitionFrameFromTranscoder(TTRVideoPicture* aPicture, TInt aIndex)
{

    // apply transition effect in spatial domain (to yuv data in encoder buffer)    
	if ( iFrameInfoArray[aIndex].iTransitionPosition == EPositionStartOfClip && 
	     iStartTransitionColor == EColorTransition )
	{
	    // Do blending transition: wipe / crossfade
	    	
	    TSize a = iProcessor->GetMovieResolution();
        TInt yuvLength = a.iWidth*a.iHeight;
        yuvLength += (yuvLength>>1);
            
	    if (iFrameInfoArray[aIndex].iRepeatFrame == 0) 
	    {		             
            if( !iColorTransitionBuffer )
            {                    
    			iColorTransitionBuffer = (TUint8*)User::Alloc( yuvLength );
    			if (!iColorTransitionBuffer)
    			{
    			    iMonitor->Error(KErrNoMemory);
    			    return;        			    
    			}
            }
            
    		if( !iOrigPreviousYUVBuffer )
    		{        		    
    			iOrigPreviousYUVBuffer = (TUint8*)User::Alloc( yuvLength );
    			if (!iOrigPreviousYUVBuffer)
    			{
    			    iMonitor->Error(KErrNoMemory);
    			    return;        			    
    			}
    		}

    		TPtr8 ptr( iColorTransitionBuffer, 0, yuvLength );
    		
    		if ( iProcessor->GetVideoFrameFromFile( ptr, yuvLength, iFrameDuration, iTimeStamp ) != KErrNone )
    		    //|| iFrameDuration == 0 || iTimeStamp == 0 )
    		{
    			// failure in reading frame data from previous clip
    			// continue using the current frame data        			
    			Mem::Copy( iColorTransitionBuffer, aPicture->iRawData->Ptr(), yuvLength );
    		}
    		else
    		{
    		    // buffer frame from previous clip (read from file)
    			Mem::Copy( iOrigPreviousYUVBuffer, iColorTransitionBuffer, yuvLength );
    			if ( iStartOfClipTransition == (TInt)EVedMiddleTransitionEffectCrossfade )
    			{        				
    				// Target frame is the one read from file, iColorTransitionBuffer
    				ApplyBlendingTransitionEffect( iColorTransitionBuffer, const_cast<TUint8*>(aPicture->iRawData->Ptr()), 
    				                               0 /* repeatFrame */, iFrameInfoArray[aIndex].iTransitionFrameNumber);
    			}
    			else
    			{
    			    // Target frame is the one read from file, iColorTransitionBuffer
    				ApplySlidingTransitionEffect( iColorTransitionBuffer, const_cast<TUint8*>(aPicture->iRawData->Ptr()), (TVedMiddleTransitionEffect)iStartOfClipTransition, 
    				                              0 /* repeatFrame */, iFrameInfoArray[aIndex].iTransitionFrameNumber);
    			}
    			// copy frame from edited buffer to transcoder buffer
    			Mem::Copy( const_cast<TUint8*>(aPicture->iRawData->Ptr()), iColorTransitionBuffer, yuvLength );        			        			
    		}
	    }
	    else
	    {
	        // repeatFrame
	        
	        if ( iStartOfClipTransition == (TInt)EVedMiddleTransitionEffectCrossfade )
			{
				ApplyBlendingTransitionEffect( iOrigPreviousYUVBuffer, const_cast<TUint8*>(aPicture->iRawData->Ptr()), 
				                               1 /* repeatFrame */, iFrameInfoArray[aIndex].iTransitionFrameNumber);
			}
			else
			{
				ApplySlidingTransitionEffect( iOrigPreviousYUVBuffer, const_cast<TUint8*>(aPicture->iRawData->Ptr()), (TVedMiddleTransitionEffect)iStartOfClipTransition, 
				                              1 /* repeatFrame */, iFrameInfoArray[aIndex].iTransitionFrameNumber );
			}
			// copy frame from edited buffer to transcoder buffer
	        Mem::Copy( const_cast<TUint8*>(aPicture->iRawData->Ptr()), iOrigPreviousYUVBuffer, yuvLength );
	    }
	}
	else
	{
		// apply transition effect in spatial domain (to yuv data in encoder buffer)
		
		// Do fading transition
		ApplyFadingTransitionEffect(const_cast<TUint8*>(aPicture->iRawData->Ptr()), iFrameInfoArray[aIndex].iTransitionPosition, iFrameInfoArray[aIndex].iTransitionColor,
		                            iFrameInfoArray[aIndex].iTransitionFrameNumber);
	}		
    
}

// ---------------------------------------------------------
// CVideoProcessor::ProcessThumb
// Starts thumbnail generation
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CVideoProcessor::ProcessThumb(MThumbnailObserver* aThumbObserver, TInt aFrameIndex, TInt aStartFrameIndex, TVedTranscodeFactor* aFactor)
{
    TInt error;
//    TInt goodFrame = 0; 
//    TInt frameSkip = 10; 
//    TInt frameNumber = aStartFrameIndex;
    TPtrC8 inputPtr;
    TPtr8 outputPtr(0,0);
    
    iThumbObserver = aThumbObserver;
    iThumbFrameIndex = aFrameIndex;
    iThumbFrameNumber = aStartFrameIndex;
    iFramesToSkip = 0;
    iNumThumbFrameSkips = 0;
    iPreviousTimeStamp = TTimeIntervalMicroSeconds(-1);
    iProcessingComplete = EFalse;
    
    iThumbFramesToWrite  = iProcessor->GetOutputNumberOfFrames() - iThumbFrameNumber;    

    // get transcode factor to determine input stream type    
    TRAP(error, GetTranscodeFactorL(*aFactor));
    if (error != KErrNone)
        return error;
    
    TVedVideoType inType;
    if (aFactor->iStreamType == EVedVideoBitstreamModeH263)
        inType = EVedVideoTypeH263Profile0Level10;
    
    else if (aFactor->iStreamType == EVedVideoBitstreamModeAVC)
    	inType = EVedVideoTypeAVCBaselineProfile;
    
    else
        inType = EVedVideoTypeMPEG4SimpleProfile;
    
    if (aFactor->iStreamType == EVedVideoTypeUnrecognized ||
        aFactor->iStreamType == EVedVideoTypeNoVideo)
        return KErrorCode;
        
    iDecoding = ETrue;
      
    // first frame is now read in iDataBuffer, initialize transcoder
    TRAP(error, CreateAndInitializeTranscoderL(inType, CTRTranscoder::EDecoding))
    if (error != KErrNone)
        return error;
    
    // wait for initialisation to complete => RunL
    
    return KErrNone;
    
}
           
// ---------------------------------------------------------
// CVideoProcessor::ProcessThumb
// Processes a thumbnail frame internally
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::ProcessThumb(TBool aFirstFrame)
{

    PRINT((_L("CVideoProcessor::ProcessThumb() - begin()")));

    iThumbDecoded = EFalse;
 
    if (aFirstFrame)
    {    
        // frame read in iDataBuffer, decode
        CCMRMediaBuffer::TBufferType bt = 
            (iDataFormat == EDataH263) ? CCMRMediaBuffer::EVideoH263 : CCMRMediaBuffer::EVideoMPEG4;                        
        TInt index = iThumbFrameNumber - ( iProcessor->GetOutputNumberOfFrames() - 
                                           iProcessor->GetClipNumberOfFrames() );
        TTimeIntervalMicroSeconds ts = 
            TTimeIntervalMicroSeconds(iProcessor->GetVideoTimeInMsFromTicks(iProcessor->VideoFrameTimeStamp(index), ETrue) * TInt64(1000) );
                    
   		// Get the AVC bit stream and add NAL headers
   		if(iDataFormat == EDataAVC)   		
   		{   
   		    TInt error = KErrNone;
   		    
   		    // insert dec.config. record in the beginning of buffer
   		    TRAP( error, InsertDecoderSpecificInfoL() );
   		    if (error != KErrNone)
            {                                
                iProcessor->NotifyThumbnailReady(error);
                return;
            }
   		
   		    PRINT((_L("CVideoProcessor::ProcessThumb() - ProcessAVCBitStream()")));
   		
   		    TPtr8 ptr(iDataBuffer, iCurrentFrameLength, iBufferLength);
            TRAP( error, iAvcEdit->ProcessAVCBitStreamL((TDes8&)(ptr), (TInt&)(iCurrentFrameLength), 
                iProcessor->GetDecoderSpecificInfoSize(), ETrue ) );
                
            if (error != KErrNone)
            {                                
                iProcessor->NotifyThumbnailReady(error);
                return;
            }
            iDataLength = iCurrentFrameLength;
            
   		}
   		
   		// insert VOL header to beginning of buffer
        if (iDataFormat == EDataMPEG4)
        {
   		    TRAPD( error, InsertDecoderSpecificInfoL() );
   		    if (error != KErrNone)
            {                                
                iProcessor->NotifyThumbnailReady(error);
                return;
            }
        }
                
        iMediaBuffer->Set( TPtrC8(iDataBuffer, iBufferLength), 
                                  bt, 
                                  iCurrentFrameLength, 
                                  ETrue, // keyFrame
                                  ts
                                  );
                                  
        iPreviousTimeStamp = ts;

        iIsThumbFrameBeingCopied = ETrue;
        iDecodePending = ETrue;
        if (!IsActive())
        {
            SetActive();
            iStatus = KRequestPending;                                
        }
         
        PRINT((_L("CVideoProcessor::ProcessThumb() - WriteCodedBuffer, thumb frame #%d, timestamp %d ms"),
               iThumbFrameNumber, I64INT( ts.Int64() ) / 1000 ));    
               
        TRAPD( err, iTransCoder->WriteCodedBufferL(iMediaBuffer) );
        if (err != KErrNone)
        {
            // ready
            FinalizeThumb(err);
            return;            
        }
        iThumbFramesToWrite--;
        
        return;
    }
    
    if (iThumbFrameIndex == 0)
    {       
        // ready
        FinalizeThumb(KErrNone);
        return;
    }
 
    iThumbFrameNumber++;

    if (iDataFormat == EDataAVC)
    {
        // In AVC case, we have to stop decoding before the very last
        // frames are decoded, since for some reason the transcoder/decoder
        // does not decode those frames
        
        // get max number of buffered frames according to spec
        TInt buffered = iAvcEdit->GetMaxAVCFrameBuffering(iInputAVCLevel, TSize(iVideoWidth, iVideoHeight));
        
        if (iThumbFrameNumber > iProcessor->GetOutputNumberOfFrames() - 1 - buffered )   
        {            
            // ready                
            FinalizeThumb(KErrNone);
            return;
        }
    }
    
    if (iThumbFrameIndex < 0)
    {        
        if (iFramesToSkip == 0)
        {            
             PRINT((_L("CVideoProcessor::ProcessThumb() frameskip done %d times"), iNumThumbFrameSkips));

             // limit the number of frame skip cycles to 3, because with
		     // near-black or near-white videos we may never find a good thumb.
		     // => max. 30 frames are decoded to get the thumb
             
             // check quality & frame skip cycles
             if ( CheckFrameQuality(iFrameBuffer) || iNumThumbFrameSkips >= 3 )
             {
                 // quality ok or searched long enough, return
                 FinalizeThumb(KErrNone);
                 return;              
             }
             iFramesToSkip = 10;
             iNumThumbFrameSkips++;
        }
        else
            iFramesToSkip--;
        
        // read new frame & decode                           
    }
    
    if (iThumbFrameIndex > 0)
    {            
        if (iThumbFrameNumber > iThumbFrameIndex)        
        {
            // ready                
            FinalizeThumb(KErrNone);
            return;
        }
        // read new frame & decode
    }
    
    if (iIsThumbFrameBeingCopied)
    {
        PRINT((_L("CVideoProcessor::ProcessThumb() - thumb being copied, activate")));
        // Re-activate to wait for MtroReturnCodedBuffer
        iDecodePending = ETrue;
        if (!IsActive())
        {
            SetActive();
            iStatus = KRequestPending;                                
        }
    } 
    else 
    {
        PRINT((_L("CVideoProcessor::ProcessThumb() - read and write new")));
        // send new frame for decoding
        ReadAndWriteThumbFrame();
    }
    
    PRINT((_L("CVideoProcessor::ProcessThumb() - end")));
    
}

// ---------------------------------------------------------
// CVideoProcessor::ReadAndWriteThumbFrame
// Reads a new frame to input queue and sends it to transcoder
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::ReadAndWriteThumbFrame()
{

    PRINT((_L("CVideoProcessor::ReadAndWriteThumbFrame() - begin, thumb frames to write %d"),
        iThumbFramesToWrite));

    TInt error = KErrNone;

    if ( iThumbFramesToWrite )
    {
        // read new frame to input queue
        if(iThumbFrameNumber < (iProcessor->GetOutputNumberOfFrames())) // do not read last frame (already read!)
        {   
            CMP4Demux *demux = (CMP4Demux *)iProcessor->GetDemux();
            error = demux->ReadVideoFrames(1);
            if (error != KErrNone)
            {
                FinalizeThumb(error);
                return;
            }
        }
        else
        {
            // no frames left, return            
            FinalizeThumb(KErrNone);
            return;
        }
        
        iDataLength = 0;
        iCurrentFrameLength = 0;
        iDataFormat = EDataUnknown;
        
        if (ReadFrame())
        {
            // frame read in iDataBuffer, decode
            CCMRMediaBuffer::TBufferType bt = 
                (iDataFormat == EDataH263) ? CCMRMediaBuffer::EVideoH263 : CCMRMediaBuffer::EVideoMPEG4;
            
            TInt index = iThumbFrameNumber - ( iProcessor->GetOutputNumberOfFrames() - 
                iProcessor->GetClipNumberOfFrames() );
            
            TTimeIntervalMicroSeconds ts = 
                TTimeIntervalMicroSeconds(iProcessor->GetVideoTimeInMsFromTicks(iProcessor->VideoFrameTimeStamp(index), ETrue) * TInt64(1000) );
                
            if (ts <= iPreviousTimeStamp)
            {            
                // adjust timestamp so that its bigger than ts of previous frame
                TReal frameRate = iProcessor->GetVideoClipFrameRate();
                VDASSERT(frameRate > 0.0, 108);
                TInt64 durationMs =  TInt64( ( 1000.0 / frameRate ) + 0.5 );
                durationMs /= 2;  // add half the duration of one frame
                
                ts = TTimeIntervalMicroSeconds( iPreviousTimeStamp.Int64() + durationMs*1000 );
            }
            
            iPreviousTimeStamp = ts;
            
       		// Get the AVC bit stream and add NAL headers
       		if(iDataFormat == EDataAVC)
       		{
       		    TPtr8 ptr(iDataBuffer, iCurrentFrameLength, iBufferLength);
                TRAPD( error, iAvcEdit->ProcessAVCBitStreamL((TDes8&)(ptr), (TInt&)(iCurrentFrameLength), 
                    iProcessor->GetDecoderSpecificInfoSize(), EFalse ) );
                    
                if (error != KErrNone)
                {
                    FinalizeThumb(error);
                    return;
                }
                iDataLength = iCurrentFrameLength;
       		}                    

            iMediaBuffer->Set( TPtrC8(iDataBuffer, iBufferLength), 
                                      bt, 
                                      iCurrentFrameLength, 
                                      iProcessor->GetVideoFrameType(index),
                                      ts );                                                                            

            iIsThumbFrameBeingCopied = ETrue;
            iDecodePending = ETrue;
            if (!IsActive())
            {
                SetActive();
                iStatus = KRequestPending;                                
            }
            
            PRINT((_L("CVideoProcessor::ProcessThumb() - WriteCodedBuffer, thumb frame #%d, timestamp %d ms"),
               iThumbFrameNumber, I64INT( ts.Int64() ) / 1000 ));    
                   
            TRAPD( err, iTransCoder->WriteCodedBufferL(iMediaBuffer) );
            if (err != KErrNone)
            {
                FinalizeThumb(err);
            }            
            iThumbFramesToWrite--;
            return;        
        }
    } 
    
    else
    {
        if (iDataFormat == EDataAVC)
        {
            PRINT((_L("CVideoProcessor::ReadAndWriteThumbFrame() - all frames written, wait for output")));
            // all necessary frames written to decoder, now wait for output frames            
            iDecodePending = ETrue;
            if (!IsActive())
            {
                SetActive();
                iStatus = KRequestPending;                                
            }            
        } 
        else
        {
            FinalizeThumb(KErrNone);            
        }
    }    
    
    PRINT((_L("CVideoProcessor::ReadAndWriteThumbFrame() - end")));     
}
    
// ---------------------------------------------------------
// CVideoProcessor::FinalizeThumb
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::FinalizeThumb(TInt aError)
{       
    iProcessingComplete = ETrue;
    if (iTranscoderStarted) 
    {        
        TRAPD( err, iTransCoder->StopL() );
        if (err != KErrNone) { }
        iTranscoderStarted = EFalse;
    }
    iProcessor->NotifyThumbnailReady(aError);
}
    
// ---------------------------------------------------------
// CVideoProcessor::FetchThumb
// For getting a pointer to YUV thumbnail frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CVideoProcessor::FetchThumb(TUint8** aYUVDataPtr)
{
    *aYUVDataPtr = iFrameBuffer;    
        
    return KErrNone;
}


// ---------------------------------------------------------
// CVideoProcessor::GetTranscodeFactorL
// Gets the transcode factor from the current clip
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CVideoProcessor::GetTranscodeFactorL(TVedTranscodeFactor& aFactor)
{
    // start reading video frames
    CMP4Demux *demux = (CMP4Demux *)iProcessor->GetDemux();
    TInt error = demux->ReadVideoFrames(1);

    if (error != KErrNone)
        User::Leave(error);

    // seek to and decode first frame
    if (!ReadFrame())
        User::Leave(KErrCorrupt);
    
    // Get pointer to the frame data
    TPtr8 inputPtr(0,0);
    if ( iDataFormat == EDataH263 )
        inputPtr.Set(iDataBuffer, iCurrentFrameLength + KH263StartCodeLength, iCurrentFrameLength + KH263StartCodeLength);
    else
        inputPtr.Set(iDecoderSpecificInfo->Des());
    
	if(iDataFormat == EDataAVC)
	{
		// @@ HARI AVC harcode for now    
	    // Set transcode factors
	    aFactor.iTRes = 30;
	    aFactor.iStreamType = EVedVideoBitstreamModeAVC;
	} 
	else
	{
        // Get the VOL header from the frame data
        CVedVolReader* reader = CVedVolReader::NewL();
        CleanupStack::PushL(reader);
        reader->ParseVolHeaderL((TDesC8&) inputPtr);
        
        // Set transcode factors
        aFactor.iTRes = reader->TimeIncrementResolution();
        aFactor.iStreamType = reader->BitstreamMode();
        
        CleanupStack::PopAndDestroy(reader);
	}
    
    return KErrNone;    
}



// ---------------------------------------------------------
// CVideoProcessor::CheckFrameQuality
// Checks if a frame has "good" or "legible" quality
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CVideoProcessor::CheckFrameQuality(TUint8* aYUVDataPtr)
{
    TInt i;
    TInt minValue = 255;
    TInt maxValue = 0;
    TInt goodFrame = 1;
    TInt runningSum=0;
    TInt averageValue=0;
    TInt pixelSkips = 4;
    TInt numberOfSamples=0;
    TInt minMaxDeltaThreshold = 20; 
    TInt extremeRegionThreshold = 20; 
    TInt ySize = iVideoWidth*iVideoHeight; 
    
    // gather image statistics
    for(i=0, numberOfSamples=0; i<ySize; i+=pixelSkips, aYUVDataPtr+=pixelSkips, numberOfSamples++)
    {
        runningSum += *aYUVDataPtr;
        if(*aYUVDataPtr > maxValue)
            maxValue = *aYUVDataPtr;
        if(*aYUVDataPtr < minValue)
            minValue = *aYUVDataPtr;
    }
    VDASSERT(numberOfSamples,10);
    averageValue = runningSum/numberOfSamples;
    
    // make decision based statistics
    if((maxValue - minValue) < minMaxDeltaThreshold)
        goodFrame = 0;
    else 
    {
        if(averageValue < (minValue + extremeRegionThreshold) || 
            averageValue > (maxValue - extremeRegionThreshold))
            goodFrame = 0;
    }
    return goodFrame;
}


// ---------------------------------------------------------
// CVideoProcessor::ReadFrame
// Reads a frame from input queue to internal buffer
// (other items were commented in a header).
// ---------------------------------------------------------
//				
TInt CVideoProcessor::ReadFrame()
{

	TUint doNow;		
	
	if (iProcessor->GetCurrentClipVideoType() == EVedVideoTypeAVCBaselineProfile)
        iDataFormat = EDataAVC;  
	
	// Determine data format if needed
	if ( iDataFormat == EDataUnknown )
	{
		// We'll need four bytes of data
		while ( iDataLength < 4 )
		{
			// Get a block (we can't have one as we go here only at the stream
			// start)
			VDASSERT(!iBlock,11);
			while ( (!iBlock) || (iBlock->Length() == 0) )
			{
				if ( iBlock )
					iQueue->ReturnBlock(iBlock);
				if ( (iBlock = iQueue->ReadBlock()) == NULL )
					return EFalse;
			}
			iBlockPos = 0;
			
			// get timestamp for first frame
			if ( iTiming == ETimeStamp )
			{
				VDASSERT( (TUint)iBlock->Length() >= 8,12 );		
				iBlockPos += 4;
			}
			
			// Copy data from block to buffer:
			doNow = 4 - iDataLength;
			if ( doNow > (TUint) iBlock->Length() - iBlockPos )
				doNow = iBlock->Length() - iBlockPos;
			Mem::Copy(iDataBuffer+iDataLength, iBlock->Ptr()+iBlockPos, doNow);
			iDataLength += doNow;
			iBlockPos += doNow;
			
			// Return the block if it doesn't have any more data
			if ( ((TInt)iBlockPos == iBlock->Length()) )
			{
				iQueue->ReturnBlock(iBlock);
				iBlock = 0;
			}
		}          
    
		// OK, we have 4 bytes of data. Check if the buffer starts with a
		// H.263 PSC:
		if ( (iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) &&
			((iDataBuffer[2] & 0xfc) == 0x80) )
		{
			// Yes, this is a H.263 stream
			iDataFormat = EDataH263;
		}
		
		// It should be MPEG-4, check if it starts with MPEG 4 Visual
		// Object Sequence start code, Visual Object start code, Video
		// Object start code, or Video Object Layer start code
		else if ( ((iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) && (iDataBuffer[2] == 1) && (iDataBuffer[3] == 0xb0)) ||
			((iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) && (iDataBuffer[2] == 1) && (iDataBuffer[3] == 0xb6)) ||
			((iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) && (iDataBuffer[2] == 1) && (iDataBuffer[3] == 0xb3)) ||
			((iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) && (iDataBuffer[2] == 1) && (iDataBuffer[3] == 0xb5)) ||
			((iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) && (iDataBuffer[2] == 1) && ((iDataBuffer[3] >> 5) == 0)) ||
			((iDataBuffer[0] == 0) && (iDataBuffer[1] == 0) && (iDataBuffer[2] == 1) && ((iDataBuffer[3] >> 4) == 2)))
		{
			iDataFormat = EDataMPEG4;                
		}
		else
		{
            PRINT((_L("CVideoProcessor::ReadFrame() - no PSC or MPEG-4 start code in the start of the buffer")));
            if (iMonitor)
			    iMonitor->Error(KErrCorrupt);
			return EFalse;
		}
	}
	
	// Determine the start code length
	TUint startCodeLength = 0;
	switch (iDataFormat)
	{
	case EDataH263:
		startCodeLength = KH263StartCodeLength;
		break;
	case EDataMPEG4:
		startCodeLength = KMPEG4StartCodeLength ;
		break;		
    case EDataAVC:
		break;

	default:
		User::Panic(_L("CVideoPlayer"), EInternalAssertionFailure);
	}

	// If the stream has ended, we have no blocks and no data for even a
	// picture start code, we can't get a frame
	if( iDataFormat == EDataH263 )
	{
		if ( iStreamEnd && (iQueue->NumDataBlocks() == 0) &&
			(iCurrentFrameLength <= startCodeLength) &&	(iDataLength <= startCodeLength) )
			return EFalse;
	}
	else
	{
		if ( iStreamEnd && (iQueue->NumDataBlocks() == 0) &&
			(iCurrentFrameLength <= startCodeLength) &&	(iDataLength < startCodeLength) )
			return EFalse;
	}
		
    switch(iDataFormat)
    {
        case EDataH263:
            return ReadH263Frame();
//            break;
            
        case EDataMPEG4:
            return ReadMPEG4Frame();
//            break;
            
        case EDataAVC:
            return ReadAVCFrame();
//            break;
            
        default:
            User::Panic(_L("CVideoProcessor"), EInternalAssertionFailure);        
        
    }
    
    return ETrue;
}


// ---------------------------------------------------------
// CVideoProcessor::ReadH263Frame
// Reads a H.263 frame from input queue to internal buffer
// (other items were commented in a header).
// ---------------------------------------------------------
//				
TBool CVideoProcessor::ReadH263Frame()
{
     
    VDASSERT( iDataFormat == EDataH263, 17 );    
       
    TInt offset = 0;    
    if ( iTiming == ETimeStamp )
	    offset = 4;		
    
    // There should be one PSC at the buffer start, 
    // and no other PSCs up to iDataLength    	
	if ( (iDataLength >= KH263StartCodeLength) && 
        ((iDataBuffer[0] != 0) || (iDataBuffer[1] != 0) || ((iDataBuffer[2] & 0xfc) != 0x80)) )
    {
		PRINT((_L("CVideoProcessor::ReadH263Frame() - no PSC in the start of the buffer")))
		if (iMonitor)
            iMonitor->Error(KErrCorrupt);
		return EFalse;
    }
    
	if (iCurrentFrameLength < KH263StartCodeLength )
		iCurrentFrameLength = KH263StartCodeLength;

    TBool gotPSC = EFalse;
	while (!gotPSC)
	{
		// If we don't have a block at the moment, get one and check if it
		// has a new PSC
		while (!iBlock)
		{
			if ((iBlock = iQueue->ReadBlock()) == NULL)
			{
				if (!iStreamEnd && !iProcessor->IsThumbnailInProgress())
					return EFalse;
				
				// No more blocks in the stream. If we have more data than
				// just a PSC, use the remaining as the last frame. We'll
				// append an End Of Stream (EOS) codeword to the stream end
				// to keep the decoder happy
				if (iDataLength <= 3)
					return EFalse;
				iCurrentFrameLength = iDataLength;
				if (iBufferLength < (iDataLength+3))
				{
					iBufferLength += 3;						                       
                    TUint8* tmp = (TUint8*) User::ReAlloc(iDataBuffer, iBufferLength);
					if ( !tmp  )
					{
					    if (iMonitor)
						    iMonitor->Error(KErrNoMemory);							
						return EFalse;
					}
                    iDataBuffer = tmp;
				}
				iDataBuffer[iCurrentFrameLength] = 0;
				iDataBuffer[iCurrentFrameLength+1] = 0;
				iDataBuffer[iCurrentFrameLength+2] = 0xfc;
				iDataLength += 3;
				return ETrue;
			}
							
			iBlockPos = 0;
			// Return empty blocks immediately
			if ( iBlock->Length() == 0 )
			{
				iQueue->ReturnBlock(iBlock);
				iBlock = 0;
			}                
		}
		
		// If we are at the start of a block, check if it begins with a PSC
		if ( iBlockPos == 0 )
		{                
			if ( (iBlock->Length() > 2 + offset) &&
				( ((*iBlock)[0+offset] == 0) && ((*iBlock)[1+offset] == 0) && (((*iBlock)[2+offset] & 0xfc) == 0x80) ) )
			{
				gotPSC = ETrue;
				iCurrentFrameLength = iDataLength;  // timestamps not copied to buffer
				
				if (iTiming == ETimeStamp)
				{						
					iBlockPos += offset;
				}
			}
            else
            {
                PRINT((_L("CVideoProcessor::ReadH263Frame() - no PSC in the start of the buffer")))
                if (iMonitor)
                    iMonitor->Error( KErrCorrupt );
                return EFalse;
            }
		}
		
		// If we still have data in our current block, copy it to the buffer
		// Make sure we have enough space
		TUint copyBytes = iBlock->Length() - iBlockPos;
		if (copyBytes)
		{
			while (iBufferLength < (iDataLength + copyBytes))
			{
				// New size is 3/2ths of the old size, rounded up to the next
				// full kilobyte
				TUint newSize = (3 * iBufferLength) / 2;
				newSize = (newSize + 1023) & (~1023);
				
                TUint8* tmp = (TUint8*) User::ReAlloc(iDataBuffer, newSize);
				if (!tmp)
				{
				    if (iMonitor)
					    iMonitor->Error(KErrNoMemory);
					return EFalse;
				}
                iDataBuffer = tmp;
				iBufferLength = newSize;
			}
			Mem::Copy(&iDataBuffer[iDataLength], iBlock->Ptr() + iBlockPos,
				copyBytes);
			iBlockPos += copyBytes;
			iDataLength += copyBytes;
		}
		
		// OK, block used, throw it away
		VDASSERT(iBlock->Length() == (TInt)iBlockPos,16);
		iQueue->ReturnBlock(iBlock);
		iBlock = 0;
	}
	
	return ETrue;	
}
		


// ---------------------------------------------------------
// CVideoProcessor::ReadMPEG4Frame
// Reads a MPEG-4 frame from input queue to internal buffer
// (other items were commented in a header).
// ---------------------------------------------------------
//				
TBool CVideoProcessor::ReadMPEG4Frame()
{
    
    VDASSERT( (iDataFormat == EDataMPEG4 && iTiming == ETimeStamp), 17 );    
		
    // The following code assumes that there is one complete video frame
    // in each input block. This is true for 3GP input streams.     
	
    // get a new block if we don't have one
    while (!iBlock)
    {
        if ((iBlock = iQueue->ReadBlock()) == NULL)        
            return EFalse;        
        
        iBlockPos = 0;
        // Return empty blocks immediately
        if (iBlock->Length() == 0)
        {
            iQueue->ReturnBlock(iBlock);
            iBlock = 0;
        }
    }    

    // If we are at the start of a block, save timestamp
    if (iBlockPos == 0)
    {
        //TUint* p = (TUint*)iBlock->Ptr();
        //AI:         iRenderFrameTime = TInt64( (TUint)((*p)*1000) );
        iBlockPos += 4; // skip timestamp
    }
    
    if (iFirstRead)
    {
        // allocate buffer for header        
        VDASSERT(!iDecoderSpecificInfo, 160);        
        iDecoderSpecificInfo = (HBufC8*) HBufC8::New(iProcessor->GetDecoderSpecificInfoSize());
        if (!iDecoderSpecificInfo)
        {
            iMonitor->Error(KErrNoMemory);
            return EFalse;
        }
        
        TPtr8 ptr(iDecoderSpecificInfo->Des());
        
        // first copy already read bytes from iDataBuffer
        ptr.Copy(iDataBuffer, iDataLength);
        
        TInt copyNow = iProcessor->GetDecoderSpecificInfoSize() - iDataLength;
        iDataLength = 0;
        
        // then copy the rest from input buffer
        ptr.Append(iBlock->Ptr() + iBlockPos, copyNow);
        iBlockPos += copyNow;
        iDecoderSpecificInfoSent = EFalse;
            
        iFirstRead = EFalse;
    
    }
	
    TUint copyBytes = iBlock->Length() - iBlockPos;
    if (copyBytes)
    {
        // Make sure we have enough space
        //   +4 is for inserting a start code at the end of the frame 
        while (iBufferLength < (iDataLength + copyBytes + 4))
        {
            // New size is 3/2ths of the old size, rounded up to the next
            // full kilobyte
            TUint newSize = (3 * iBufferLength) / 2;
            newSize = (newSize + 1023) & (~1023);				
            TUint8* tmp = (TUint8*) User::ReAlloc(iDataBuffer, newSize);
            if (!tmp)
            {
                if (iMonitor)
                    iMonitor->Error(KErrNoMemory);
                return EFalse;
            }
            iDataBuffer = tmp;
            iBufferLength = newSize;
        }
        Mem::Copy(&iDataBuffer[iDataLength], iBlock->Ptr() + iBlockPos,
            copyBytes);
        iBlockPos += copyBytes;
        iDataLength += copyBytes;        
    }

    // OK, block used, throw it away
    VDASSERT((iBlock->Length() == (TInt)iBlockPos),18);
    iQueue->ReturnBlock(iBlock);
    iBlock = 0;
    
    // check for VOS end code
    if ( (iDataBuffer[0] == 0 ) && (iDataBuffer[1] == 0 ) && 
        (iDataBuffer[2] == 0x01) && (iDataBuffer[3] == 0xb1) )
        return EFalse;
    
    // insert VOP start code at the end, the decoder needs it
    iDataBuffer[iDataLength++] = 0;
    iDataBuffer[iDataLength++] = 0;
    iDataBuffer[iDataLength++] = 0x01;
    iDataBuffer[iDataLength++] = 0xb6;
    iCurrentFrameLength = iDataLength;
    
    // we have a complete frame
    return ETrue;
    
}


// ---------------------------------------------------------
// CVideoProcessor::ReadAVCFrame
// Reads an AVC frame from input queue to internal buffer
// (other items were commented in a header).
// ---------------------------------------------------------
//				
TBool CVideoProcessor::ReadAVCFrame()
{

    VDASSERT( iDataFormat == EDataAVC, 17 );    

    // get a new block if we don't have one
    while (!iBlock)
    {
        if ((iBlock = iQueue->ReadBlock()) == NULL)        
            return EFalse;        
        
        iBlockPos = 0;
        // Return empty blocks immediately
        if (iBlock->Length() == 0)
        {
            iQueue->ReturnBlock(iBlock);
            iBlock = 0;
        }
    }    
    
    // skip 4 bytes for the timestamp
    TInt skip = 4;
//    TInt numSPS = 0;
//    TInt numPPS = 0;        

    // set this to point to the start of frame length field
    TUint8* frameLenPtr = const_cast<TUint8*>(iBlock->Ptr()) + skip;
    // how much space needed for frame data 
    TInt frameLen = 0;                

    TInt totalFrameLen = iBlock->Length() - skip;
    
    if (iFirstRead)
    {
        TInt index = skip + 4;     // Skip timestamp + version etc.
        TUint8* temp = const_cast<TUint8*>(iBlock->Ptr());                    
        
        // get no. bytes used for length
        iFrameLengthBytes = ( temp[index] & 0x3 ) + 1;

        // save DCR
        VDASSERT(!iDecoderSpecificInfo, 160);
        
        iDecoderSpecificInfo = (HBufC8*) HBufC8::New(iProcessor->GetDecoderSpecificInfoSize());
        if (!iDecoderSpecificInfo)
        {
            iMonitor->Error(KErrNoMemory);
            return EFalse;
        }
        
        TPtr8 ptr(iDecoderSpecificInfo->Des());
        ptr.Copy(iBlock->Ptr() + skip, iProcessor->GetDecoderSpecificInfoSize());
        iDecoderSpecificInfoSent = EFalse;
        
        // advance pointer over info to point to length field
        frameLenPtr += iProcessor->GetDecoderSpecificInfoSize();
        
        // add to frame len. since it is used to calculate the minimum buffer size
        //frameLen += iProcessor->GetDecoderSpecificInfoSize();
        
        totalFrameLen -= iProcessor->GetDecoderSpecificInfoSize();
        skip += iProcessor->GetDecoderSpecificInfoSize();
        
        iFirstRead = EFalse;
    }
       
    

    TInt numSliceNalUnits = 0;
    while (frameLen < totalFrameLen)
    {                
        TInt nalLen = 0;
        switch (iFrameLengthBytes)
        {
            case 1:
                nalLen = frameLenPtr[0] + 1;  // +1 for length field
                break;                
                
            case 2:            
                nalLen = (frameLenPtr[0] << 8) + frameLenPtr[1] + 2; // +2 for length field
                break;

            case 3:
                nalLen = (frameLenPtr[0] << 16) + (frameLenPtr[1] << 8) +
                          frameLenPtr[2] + 3; // +3 for length field
                break;
                
            case 4:
                nalLen = (frameLenPtr[0] << 24) + (frameLenPtr[1] << 16) + 
                         (frameLenPtr[2] << 8) + frameLenPtr[3] + 4;  // +4 for length field
                break;
                
            default:
                if (iMonitor)
                    iMonitor->Error(KErrCorrupt);
                return EFalse;
        }
        frameLenPtr += nalLen;
        frameLen += nalLen;
        numSliceNalUnits++;
    }
    
    if ( iFrameLengthBytes != 4 )
        frameLen += numSliceNalUnits * ( (iFrameLengthBytes == 1) ? 3 : 2 );                     

    // reserve space for alignment
    TInt addBytes = (frameLen % 4 != 0) * ( 4 - (frameLen % 4) );
    
    // reserve space for slice NAL unit offset and size fields
    addBytes += (numSliceNalUnits * 8);
    
    // reserve space for number of NAL units (4)                
    addBytes += 4;

    // Make sure we have enough space
    while (iBufferLength < (iDataLength + frameLen + addBytes))
    {
        // New size is 3/2ths of the old size, rounded up to the next
        // full kilobyte
        TUint newSize = (3 * iBufferLength)  / 2;
        newSize = (newSize + 1023) & (~1023);				
        TUint8* tmp = (TUint8*) User::ReAlloc(iDataBuffer, newSize);
        if (!tmp)
        {
            iMonitor->Error(KErrNoMemory);
            return EFalse;
        }
        
        iDataBuffer = tmp;
        iBufferLength = newSize;
    }                

    iBlockPos += skip;
    
    if (iFrameLengthBytes == 4)
    {
        // just copy directly, no need to change length field
        Mem::Copy(&iDataBuffer[iDataLength], iBlock->Ptr() + skip, frameLen);
        iDataLength += frameLen;
        iBlockPos += frameLen;
    } 
    else
    {
        // have to change length field for each NAL
        TUint8* srcPtr = const_cast<TUint8*>(iBlock->Ptr()) + skip;
        while (numSliceNalUnits--)
        {
            // read length
            TInt nalLen = 0;
            switch (iFrameLengthBytes)
            {
                case 1:
                    nalLen = srcPtr[0];
                    srcPtr += 1;  // skip length field
                    iBlockPos += 1;
                    break;
                    
                case 2:            
                    nalLen = (srcPtr[0] << 8) + srcPtr[1];
                    srcPtr += 2;  // skip length field  
                    iBlockPos += 2;
                    break;
                    
                case 3:
                    nalLen = (srcPtr[0] << 16) + (srcPtr[1] << 8) + srcPtr[2];
                    srcPtr += 3;  // skip length field  
                    iBlockPos += 3;
                    break;
                    
                default:
                    if (iMonitor)
                        iMonitor->Error(KErrCorrupt);
                    return EFalse;
            }
                    
            // code length with 4 bytes
            iDataBuffer[iDataLength] =     TUint8((nalLen >> 24) & 0xff);
            iDataBuffer[iDataLength + 1] = TUint8((nalLen >> 16) & 0xff);
            iDataBuffer[iDataLength + 2] = TUint8((nalLen >> 8) & 0xff);
            iDataBuffer[iDataLength + 3] = TUint8(nalLen & 0xff);
            iDataLength += 4;
            // copy NAL data
            Mem::Copy(&iDataBuffer[iDataLength], srcPtr, nalLen);
            iDataLength += nalLen;
            srcPtr += nalLen;
            iBlockPos += nalLen;
        }
    }               

    // OK, block used, throw it away
    VDASSERT((iBlock->Length() == (TInt)iBlockPos),18);
    iQueue->ReturnBlock(iBlock);
    iBlock = 0;
            
    iCurrentFrameLength = iDataLength;
    
    // we have a complete frame
    return ETrue;

}
			
			

// ---------------------------------------------------------
// CVideoProcessor::DetermineClipTransitionParameters
// Sets transition frame parameters
// (other items were commented in a header).
// ---------------------------------------------------------
//	
TInt CVideoProcessor::DetermineClipTransitionParameters(TInt& aTransitionEffect,
                                                        TInt& aStartOfClipTransition,
													    TInt& aEndOfClipTransition,
													    TTransitionColor& aStartTransitionColor,
													    TTransitionColor& aEndTransitionColor)
{
	TInt error=KErrNone;
	// find if transition effect is to be applied 
	TInt numberOfVideoClips = iProcessor->GetNumberOfVideoClips();
	TInt videoClipNumber = iProcessor->GetVideoClipNumber(); 
	TVedStartTransitionEffect startTransitionEffect = iProcessor->GetStartTransitionEffect();
	TVedEndTransitionEffect endTransitionEffect = iProcessor->GetEndTransitionEffect();
	TVedMiddleTransitionEffect middleTransitionEffect = iProcessor->GetMiddleTransitionEffect();
	TVedMiddleTransitionEffect previousMiddleTransitionEffect = iProcessor->GetPreviousMiddleTransitionEffect();

	// is transition effect to be applied anywhere in the movie?
	if(startTransitionEffect==EVedStartTransitionEffectNone && 
		middleTransitionEffect==EVedMiddleTransitionEffectNone &&
		endTransitionEffect==EVedEndTransitionEffectNone &&
		previousMiddleTransitionEffect==EVedMiddleTransitionEffectNone)
		aTransitionEffect=0;
	else
		aTransitionEffect=1;
	// where is the transition effect to be applied - beginning, end or both?
	if(aTransitionEffect)
	{
		// if first video clip
		if(videoClipNumber==0)		
		{
			switch(startTransitionEffect)
			{
			default:
			case EVedStartTransitionEffectNone:
			case EVedStartTransitionEffectLast:
				aStartOfClipTransition=0;
				aStartTransitionColor = EColorNone;
				break;
			case EVedStartTransitionEffectFadeFromBlack:
				aStartOfClipTransition=1;
				aStartTransitionColor = EColorBlack;
				break;
			case EVedStartTransitionEffectFadeFromWhite:
				aStartOfClipTransition=1;
				aStartTransitionColor = EColorWhite;
				break;
			}
			// do we need transition at the end of this clip?
			if(videoClipNumber==numberOfVideoClips-1)	// last clip?
			{
				switch(endTransitionEffect)
				{
				default:
				case EVedEndTransitionEffectNone:
				case EVedEndTransitionEffectLast:
					aEndOfClipTransition=0;
					aEndTransitionColor = EColorNone;
					break;
				case EVedEndTransitionEffectFadeToBlack:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorBlack;
					break;
				case EVedEndTransitionEffectFadeToWhite:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorWhite;
					break;
				}
			}
			else	// middle clip
			{
				switch(middleTransitionEffect)
				{
				default:
				case EVedMiddleTransitionEffectNone:
				case EVedMiddleTransitionEffectLast:
					aEndOfClipTransition=0;
					aEndTransitionColor = EColorNone;
					break;
				case EVedMiddleTransitionEffectDipToBlack:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorBlack;
					break;
				case EVedMiddleTransitionEffectDipToWhite:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorWhite;
					break;
					//change
				case EVedMiddleTransitionEffectCrossfade:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectCrossfade);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeLeftToRight:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeLeftToRight);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeRightToLeft:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeRightToLeft);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeTopToBottom:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeTopToBottom);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeBottomToTop:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeBottomToTop);
					aEndTransitionColor = EColorTransition;
					break;
				}
			}
		}
		// else its the middle or last clip
		else	
		{
			// do we need transition at the beginning of this clip?
			switch(previousMiddleTransitionEffect)
			{
			default:
			case EVedMiddleTransitionEffectNone:
			case EVedMiddleTransitionEffectLast:
				aStartOfClipTransition=0;
				aStartTransitionColor = EColorNone;
				break;
			case EVedMiddleTransitionEffectDipToBlack:
				aStartOfClipTransition=1;
				aStartTransitionColor = EColorBlack;
				break;
			case EVedMiddleTransitionEffectDipToWhite:
				aStartOfClipTransition=1;
				aStartTransitionColor = EColorWhite;
				break;
				
			case EVedMiddleTransitionEffectCrossfade:
				aStartOfClipTransition=TInt(EVedMiddleTransitionEffectCrossfade);
				aStartTransitionColor = EColorTransition;
				break;
			case EVedMiddleTransitionEffectWipeLeftToRight:
				aStartOfClipTransition=TInt(EVedMiddleTransitionEffectWipeLeftToRight);
				aStartTransitionColor = EColorTransition;
				break;
			case EVedMiddleTransitionEffectWipeRightToLeft:
				aStartOfClipTransition=TInt(EVedMiddleTransitionEffectWipeRightToLeft);
				aStartTransitionColor = EColorTransition;
				break;
			case EVedMiddleTransitionEffectWipeTopToBottom:
				aStartOfClipTransition=TInt(EVedMiddleTransitionEffectWipeTopToBottom);
				aStartTransitionColor = EColorTransition;
				break;
			case EVedMiddleTransitionEffectWipeBottomToTop:
				aStartOfClipTransition=TInt(EVedMiddleTransitionEffectWipeBottomToTop);
				aStartTransitionColor = EColorTransition;
				break;
			}
			// do we need transition at the end of this clip?
			if(videoClipNumber==numberOfVideoClips-1)	// last clip?
			{
				switch(endTransitionEffect)
				{
				default:
				case EVedEndTransitionEffectNone:
				case EVedEndTransitionEffectLast:
					aEndOfClipTransition=0;
					aEndTransitionColor = EColorNone;
					break;
				case EVedEndTransitionEffectFadeToBlack:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorBlack;
					break;
				case EVedEndTransitionEffectFadeToWhite:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorWhite;
					break;
				}
			}
			else	// middle clip
			{
				switch(middleTransitionEffect)
				{
				default:
				case EVedMiddleTransitionEffectNone:
				case EVedMiddleTransitionEffectLast:
					aEndOfClipTransition=0;
					aEndTransitionColor = EColorNone;
					break;
				case EVedMiddleTransitionEffectDipToBlack:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorBlack;
					break;
				case EVedMiddleTransitionEffectDipToWhite:
					aEndOfClipTransition=1;
					aEndTransitionColor = EColorWhite;
					break;
					//change
				case EVedMiddleTransitionEffectCrossfade:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectCrossfade);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeLeftToRight:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeLeftToRight);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeRightToLeft:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeRightToLeft);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeTopToBottom:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeTopToBottom);
					aEndTransitionColor = EColorTransition;
					break;
				case EVedMiddleTransitionEffectWipeBottomToTop:
					aEndOfClipTransition=TInt(EVedMiddleTransitionEffectWipeBottomToTop);
					aEndTransitionColor = EColorTransition;
					break;
				}
			}
		}
	}
	return error;
}


// ---------------------------------------------------------
// CVideoProcessor::GetNumberOfTransitionFrames
// Calculate the number of transition frames
// (other items were commented in a header).
// ---------------------------------------------------------
//	
void CVideoProcessor::GetNumberOfTransitionFrames(TTimeIntervalMicroSeconds aStartCutTime, 
                                                  TTimeIntervalMicroSeconds aEndCutTime)
{

    TInt startFrameIndex = iProcessor->GetVideoFrameIndex(aStartCutTime);
    // the following is because binary search gives us frame with timestamp < startCutTime
    // this frame would be out of range for  movie
    if(startFrameIndex > 0 && startFrameIndex < iNumberOfFrames-1)
        startFrameIndex++;
    TInt endFrameIndex = iProcessor->GetVideoFrameIndex(aEndCutTime);
    // adjust frame indices for cut video clip
    startFrameIndex -= iProcessor->GetStartFrameIndex();
    endFrameIndex -= iProcessor->GetStartFrameIndex();
       if(startFrameIndex < 0)
        startFrameIndex = 0;
    if(endFrameIndex < 0)
        endFrameIndex = 0;
	if(endFrameIndex<startFrameIndex)
		endFrameIndex = startFrameIndex;

    // determine the total number of included frames in the clip
    iNumberOfIncludedFrames = endFrameIndex-startFrameIndex+1;
                
    // make sure there are enough frames to apply transition
    // for transition at both ends
    if(iStartOfClipTransition && iEndOfClipTransition)
    {

		if ( iStartTransitionColor == EColorTransition &&
			iEndTransitionColor == EColorTransition )
		{
			iStartNumberOfTransitionFrames >>= 1;
						
			// if there are not enough frames saved from previous
			// clip, the transition must be shortened accordingly
			if (iProcessor->GetNumberOfSavedFrames() < iStartNumberOfTransitionFrames)
                iStartNumberOfTransitionFrames = iProcessor->GetNumberOfSavedFrames();			
			
			iEndNumberOfTransitionFrames >>= 1;
			if ( iNumberOfIncludedFrames < (iStartNumberOfTransitionFrames + iEndNumberOfTransitionFrames) )
			{
				iStartNumberOfTransitionFrames = iNumberOfIncludedFrames >> 1;
				iEndNumberOfTransitionFrames = iNumberOfIncludedFrames - iStartNumberOfTransitionFrames;
			}
		}
		else
		{
			if ( iStartTransitionColor == EColorTransition )
			{
				iStartNumberOfTransitionFrames >>= 1;
				
				// if there are not enough frames saved from previous
			    // clip, the transition must be shortened accordingly
			    if (iProcessor->GetNumberOfSavedFrames() < iStartNumberOfTransitionFrames)
                    iStartNumberOfTransitionFrames = iProcessor->GetNumberOfSavedFrames();			
			}
			
			if ( iEndTransitionColor == EColorTransition )
				iEndNumberOfTransitionFrames >>= 1;
			
			if ( iNumberOfIncludedFrames < (iStartNumberOfTransitionFrames + iEndNumberOfTransitionFrames) )
			{
				if ( iStartTransitionColor == EColorTransition )
				{
					if ( ( iNumberOfIncludedFrames >> 1 ) > iStartNumberOfTransitionFrames )
					{
						iEndNumberOfTransitionFrames = iNumberOfIncludedFrames - iStartNumberOfTransitionFrames;
					}
					else
					{
						iStartNumberOfTransitionFrames = iNumberOfIncludedFrames >> 1;
						iEndNumberOfTransitionFrames = iNumberOfIncludedFrames - iStartNumberOfTransitionFrames;
					}
				}
				else if ( iEndTransitionColor == EColorTransition )
				{
					if ( ( iNumberOfIncludedFrames >> 1 ) > iEndNumberOfTransitionFrames )
					{
						iStartNumberOfTransitionFrames = iNumberOfIncludedFrames - iEndNumberOfTransitionFrames;
					}
					else
					{
						iStartNumberOfTransitionFrames = iNumberOfIncludedFrames >> 1;
						iEndNumberOfTransitionFrames = iNumberOfIncludedFrames - iStartNumberOfTransitionFrames;
					}
				}
				else
				{
					iStartNumberOfTransitionFrames = iNumberOfIncludedFrames >> 1;
					iEndNumberOfTransitionFrames = iNumberOfIncludedFrames - iStartNumberOfTransitionFrames;
				}
			}
		}            
    }
    // if transition is at one end only
    else 
    {
		if ( iStartOfClipTransition )
		{   
			iEndNumberOfTransitionFrames = 0;
			if ( iStartTransitionColor == EColorTransition )
			{
				iStartNumberOfTransitionFrames >>= 1;
				
				// if there are not enough frames saved from previous
			    // clip, the transition must be shortened accordingly
			    if (iProcessor->GetNumberOfSavedFrames() < iStartNumberOfTransitionFrames)
                    iStartNumberOfTransitionFrames = iProcessor->GetNumberOfSavedFrames();			
			}

			if ( iNumberOfIncludedFrames < iStartNumberOfTransitionFrames )
			{
				iStartNumberOfTransitionFrames = iNumberOfIncludedFrames; 
			}
		}
		else
		{
			iStartNumberOfTransitionFrames = 0;
			if ( iEndTransitionColor == EColorTransition )
			{
				iEndNumberOfTransitionFrames >>= 1;
			}
			if ( iNumberOfIncludedFrames < iEndNumberOfTransitionFrames )
			{
				iEndNumberOfTransitionFrames = iNumberOfIncludedFrames; 
			}
		}             
    }
    // fetch the last Intra before transition begins.
    // should be done after the cutting as well.
    
    iLastIntraFrameBeforeTransition=0;
    if(iNumberOfIncludedFrames > 2) //so that we could loop to find the last intra.
    {
        TInt i;
        TInt j=iProcessor->GetStartFrameIndex(); // processor needs frame index from beginning of clip
        for(i=endFrameIndex-iEndNumberOfTransitionFrames; i>=startFrameIndex;i--)
        {
            if(iProcessor->GetVideoFrameType(i+j) == 1)	// absolute index needed here!
            {
                iLastIntraFrameBeforeTransition=i;
                break;
            }
        }
    }
    
}

// ---------------------------------------------------------
// CVideoProcessor::SetTransitionFrameParams
// Set parameters for a transition frame
// (other items were commented in a header).
// ---------------------------------------------------------
//	
void CVideoProcessor::SetTransitionFrameParams(TInt aIncludedFrameNumber, TBool& aDecodeFrame)
{

    // if transition is to be applied at the beginning of the clip
    if(iStartOfClipTransition)
    {
        iFirstFrameAfterTransition = EFalse;
        // this is for start-of-clip transition
        if(aIncludedFrameNumber < iStartNumberOfTransitionFrames)
        {
            // if its first transition frame
            if(aIncludedFrameNumber == 0)
            {
                iFirstTransitionFrame = 1;
                iTransitionFrameNumber = 0;
            }
            else
            {
                iTransitionFrameNumber++;							
            }

			if ( iStartTransitionColor == EColorTransition )
			{
				// ignore this transition if the previous clip has less transition frames
				// than this clip's transition frames
				if ( iTransitionFrameNumber < ( iProcessor->NumberOfTransition() - iTransitionFrameNumber ) )
				{
					iTransitionFrame = 1;
					iTransitionPosition = EPositionStartOfClip;
					aDecodeFrame = ETrue;
					iTransitionColor = iStartTransitionColor;
				}
				else
				{
					iPreviousFrameIncluded = EFalse; 
				}
			}
			else
			{
				iTransitionFrame = 1;
				iTransitionPosition = EPositionStartOfClip;
				aDecodeFrame = EFalse;
				iTransitionColor = iStartTransitionColor;
			}
			
        }
        else
        {
            // if this is first frame after transition, we need to encode it as intra
            // treat/simulate it as if its the start of the cut point. 
            if(aIncludedFrameNumber == iStartNumberOfTransitionFrames)
            {
                iFirstFrameAfterTransition = ETrue;
                iPreviousFrameIncluded = EFalse; 
            }
        }
    }
    
    // if transition is to be applied at the end of the clip
    if(iEndOfClipTransition && iTransitionFrame == 0)
    {
        // this is for end-of-clip transition
        if(aIncludedFrameNumber >= iNumberOfIncludedFrames - iEndNumberOfTransitionFrames)
        {
            // if its first transition frame
            if(aIncludedFrameNumber == iNumberOfIncludedFrames - iEndNumberOfTransitionFrames)
            {
                iFirstTransitionFrame = 1;
                iTransitionFrameNumber = 0;
            }
            else
            {
                iTransitionFrameNumber++;
            }

			if ( iEndTransitionColor == EColorTransition )
			{
				// get the next clip's start transition information
				GetNextClipTransitionInfo();
				// if next clip's start transition number is less than current clip's
				// end transition number, then DO NOT treat current frame as the
				// the transition frame
				if ( ( iEndNumberOfTransitionFrames - iTransitionFrameNumber ) <= iNextTransitionNumber )
				{
					iTransitionFrame = 1;
					iTransitionPosition = EPositionEndOfClip;
					aDecodeFrame = ETrue;
					iTransitionColor = iEndTransitionColor;
				}
			}
			else
			{		
				iTransitionFrame = 1;
				iTransitionPosition = EPositionEndOfClip;
				aDecodeFrame = EFalse;
				iTransitionColor = iEndTransitionColor;
			}
		}
        else
        {
            // if this is first frame, we need to start decoding from here
            // treat/simulate it as if its the nearest preceding intra frame. 
            if(iFrameNumber >= iLastIntraFrameBeforeTransition)
                aDecodeFrame = ETrue;
            
            // In AVC case, if there is also starting transition, decode
            // all frames after that since frame numbering must be consistent
            // for AVC decoding to work
            if (iDataFormat == EDataAVC && iStartOfClipTransition)
                aDecodeFrame = ETrue;
            
        }	// end-of-clip transition
    }
    
}



// ---------------------------------------------------------
// CVideoProcessor::ApplyFadingTransitionEffect
// Applies fading transition effect for a YUV frame
// (other items were commented in a header).
// ---------------------------------------------------------
//	

void CVideoProcessor::ApplyFadingTransitionEffect(TUint8* aYUVPtr,
                                                  TTransitionPosition aTransitionPosition,
                                                  TTransitionColor aTransitionColor,
                                                  TInt aTransitionFramenumber)
{
	TInt i;

	TSize movieSize = iProcessor->GetMovieResolution();
	TInt yLength = movieSize.iWidth * movieSize.iHeight;	

	TInt uLength = yLength>>2;	
	TUint8* yFrame = (TUint8*)aYUVPtr;
	TUint8* uFrame = (TUint8*)(yFrame+yLength); 
	TUint8* vFrame = (TUint8*)(uFrame+uLength); 	
	TInt position;
	TChar chr; 
	TInt value; 
	TPtr8 ptr(0,0);

	// look-up tables to avoid floating point operations due to fractional weighting
	// corresponding to 0.1, 26 values quantized to 8
	const TUint8 quantTable1[8] = { 
		  4,   7,  10,  13,  16,  19,  22,  24 };
	// corresponding to 0.2, 52 values quantized to 16
	const TUint8 quantTable2[16] = { 
		  4,   8,  12,  15,  18,  21,  24,  27,  30,  33,  36,  39,  42,  45,  48,  50 };
	// corresponding to 0.3, 77 values quantized to 16
	const TUint8 quantTable3[16] = { 
		  5,  10,  15,  20,  24,  29,  33,  38,  42,  47,  51,  56,  61,  66,  71,  75 };
	// corresponding to 0.4, 103 values quantized to 32
	const TUint8 quantTable4[32] = { 
		  5,  10,  14,  18,  21,  24,  27,  30,  33,  36,  39,  42,  45,  48,  51,  54,
		 57,  60,  63,  66,  69,  72,  75,  78,  81,  84,  87,  90,  93,  96,  99, 101 };
	// corresponding to 0.5, 128 values quantized to 32
	const TUint8 quantTable5[32] = { 
		  3,   7,  11,  15,  19,  23,  27,  31,  35,  39,  43,  47,  51,  55,  59,  63,
		 67,  71,  75,  79,  83,  87,  91,  95,  99, 103, 107, 111, 115, 119, 123, 126 };
	// corresponding to 0.6, 154 values quantized to 32
	const TUint8 quantTable6[32] = { 
		  5,  13,  20,  27,  32,  36,  41,  45,  50,  54,  59,  63,  68,  72,  77,  81,
		 86,  90,  95,  99, 103, 108, 112, 117, 121, 126, 130, 135, 139, 144, 148, 152 };
	// corresponding to 0.7, 179 values quantized to 64
	const TUint8 quantTable7[64] = { 
		  5,   8,  11,  14,  17,  20,  23,  26,  29,  32,  35,  38,  41,  44,  47,  50,
		 53,  56,  59,  62,  65,  68,  71,  74,  77,  80,  83,  86,  89,  92,  95,  98,
		101, 104, 107, 110, 113, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146,
		149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 178 };
	// corresponding to 0.8, 204 values quantized to 64
	const TUint8 quantTable8[64] = { 
		  5,  10,  15,  20,  25,  29,  33,  36,  40,  42,  45,  48,  51,  54,  57,  60,
		 63,  66,  69,  72,  75,  78,  81,  84,  87,  90,  93,  96,  99, 102, 105, 108,
		111, 114, 117, 120, 123, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156,
		159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 203 };
	// corresponding to 0.9, 230 values quantized to 64
	const TUint8 quantTable9[64] = { 
		  5,  10,  15,  19,  23,  26,  30,  33,  37,  40,  44,  47,  51,  54,  58,  61,
		 65,  68,  72,  75,  79,  82,  86,  89,  93,  96, 100, 103, 107, 110, 114, 117,
		121, 124, 128, 131, 135, 138, 142, 145, 149, 152, 156, 159, 163, 166, 170, 173,
		177, 180, 184, 187, 191, 194, 198, 201, 205, 208, 212, 215, 219, 222, 226, 228 };
	const TUint8 indexTable[10]={1,2,3,4,5,6,7,8,9,10};

	// figure out if the transition is at the beginning or end of the clip	
    TInt index;
	switch(aTransitionPosition) 
	{
		case EPositionStartOfClip:		// start-of-clip transition
			if( (index = iStartNumberOfTransitionFrames - aTransitionFramenumber-1) < 0 ) index = 0;
		    break;
		case EPositionEndOfClip:		// end-of-clip transition
	        if( (index = aTransitionFramenumber) >= iEndNumberOfTransitionFrames ) index = iEndNumberOfTransitionFrames - 1;
			break;
		default:
			index = 0; 
			break;
	}
    position = indexTable[index];

	if(aTransitionColor==EColorWhite)
	{
		switch(position) // white
		{
		case 10: 	// 0% frame1, 100% frame2
			// Y
			value = 254; chr = value;
			ptr.Set(yFrame, yLength, yLength); 
			ptr.Fill(chr);
            // U,V
			value = 128; chr = value;
			ptr.Set(uFrame, uLength<<1, uLength<<1); 
			ptr.Fill(chr); 
			break;
		case 9:		// 10% frame1, 90% frame2
			value = quantTable9[63];	// 90% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable1[(*yFrame)>>5] + value);
			value = 113;							// 90% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable1[(*uFrame)>>5] + value);
				*vFrame = (TUint8)(quantTable1[(*vFrame)>>5] + value);
			}
			break;
		case 8:		// 20% frame1, 80% frame2
			value = quantTable8[63];	// 80% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable2[(*yFrame)>>4] + value);
			value = 98;							// 80% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable2[(*uFrame)>>4] + value);
				*vFrame = (TUint8)(quantTable2[(*vFrame)>>4] + value);
			}
			break;
		case 7:		// 30% frame1, 70% frame2
			value = quantTable7[63];	// 70% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable3[(*yFrame)>>4] + value);
			value = 86;							  // 70% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable3[(*uFrame)>>4] + value);
				*vFrame = (TUint8)(quantTable3[(*vFrame)>>4] + value);
			}
			break;
		case 6:		// 40% frame1, 60% frame2
			value = quantTable6[31];	// 60% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable4[(*yFrame)>>3] + value);
			value = 72; //77;							  // 60% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable4[(*uFrame)>>3] + value);
				*vFrame = (TUint8)(quantTable4[(*vFrame)>>3] + value);
			}
			break;
		case 5:		// 50% frame1, 50% frame2
			value = quantTable5[31];	// 50% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable5[(*yFrame)>>3] + value);
			value = 62;							  // 50% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable5[(*uFrame)>>3] + value);
				*vFrame = (TUint8)(quantTable5[(*vFrame)>>3] + value);
			}
			break;
		case 4: 	// 60% frame1, 40% frame2
			value = quantTable4[31];	// 40% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable6[(*yFrame)>>3] + value);
			value = 44; //51;							  // 40% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable6[(*uFrame)>>3] + value);
				*vFrame = (TUint8)(quantTable6[(*vFrame)>>3] + value);
			}
			break;
		case 3: 	// 70% frame1, 30% frame2
			value = quantTable3[15];	// 30% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable7[(*yFrame)>>2] + value);
			value = 28; //38;							  // 30% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable7[(*uFrame)>>2] + value);
				*vFrame = (TUint8)(quantTable7[(*vFrame)>>2] + value);
			}
			break;
		case 2: 	// 80% frame1, 20% frame2
			value = quantTable2[15];	// 20% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable8[(*yFrame)>>2] + value);
			value = 18; //25;							  // 20% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable8[(*uFrame)>>2] + value);
				*vFrame = (TUint8)(quantTable8[(*vFrame)>>2] + value);
			}
			break;
		case 1: 	// 90% frame1, 10% frame2
			value = quantTable1[7];	  // 10% of 254 (white)
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable9[(*yFrame)>>2] + value);
			value = 8; //13;							  // 10% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable9[(*uFrame)>>2] + value);
				*vFrame = (TUint8)(quantTable9[(*vFrame)>>2] + value);
			}
			break;
		default: 	// e.g., 100% frame1, 0% frame2
			break;
		}
	}
	else if(aTransitionColor==EColorBlack) // black
	{
		switch(position)
		{
		case 10: 	// 0% frame1, 100% frame2
			// Y
			value = 4; chr = value;
			ptr.Set(yFrame, yLength, yLength); 
			ptr.Fill(chr);
            // U,V
			value = 128; chr = value;
			ptr.Set(uFrame, uLength<<1, uLength<<1); 
			ptr.Fill(chr); 
			break;
		case 9:		// 10% frame1, 90% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable1[(*yFrame)>>5]);
			value = 113;							// 90% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable1[(*uFrame)>>5] + value);
				*vFrame = (TUint8)(quantTable1[(*vFrame)>>5] + value);
			}
			break;
		case 8:		// 20% frame1, 80% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable2[(*yFrame)>>4]);
			value = 98;							// 80% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable2[(*uFrame)>>4] + value);
				*vFrame = (TUint8)(quantTable2[(*vFrame)>>4] + value);
			}
			break;
		case 7:		// 30% frame1, 70% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable3[(*yFrame)>>4]);
			value = 86;							  // 70% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable3[(*uFrame)>>4] + value);
				*vFrame = (TUint8)(quantTable3[(*vFrame)>>4] + value);
			}
			break;
		case 6:		// 40% frame1, 60% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable4[(*yFrame)>>3]);
			value = 72; //77;							  // 60% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable4[(*uFrame)>>3] + value);
				*vFrame = (TUint8)(quantTable4[(*vFrame)>>3] + value);
			}
			break;
		case 5:		// 50% frame1, 50% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable5[(*yFrame)>>3]);
			value = 62;							  // 50% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable5[(*uFrame)>>3] + value);
				*vFrame = (TUint8)(quantTable5[(*vFrame)>>3] + value);
			}
			break;
		case 4: 	// 60% frame1, 40% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable6[(*yFrame)>>3]);
			value = 44; //51;							  // 40% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable6[(*uFrame)>>3] + value);
				*vFrame = (TUint8)(quantTable6[(*vFrame)>>3] + value);
			}
			break;
		case 3: 	// 70% frame1, 30% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable7[(*yFrame)>>2]);
			value = 28; //38;							  // 30% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable7[(*uFrame)>>2] + value);
				*vFrame = (TUint8)(quantTable7[(*vFrame)>>2] + value);
			}
			break;
		case 2: 	// 80% frame1, 20% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable8[(*yFrame)>>2]);
			value = 18; //25;							  // 20% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable8[(*uFrame)>>2] + value);
				*vFrame = (TUint8)(quantTable8[(*vFrame)>>2] + value);
			}
			break;
		case 1: 	// 90% frame1, 10% frame2
			for(i=0; i<yLength; i++, yFrame++) // Y
				*yFrame = (TUint8)(quantTable9[(*yFrame)>>2]);
			value = 8; //13;							  // 10% of 128
			for(i=0; i<uLength; i++, uFrame++,vFrame++)	// U
			{
				*uFrame = (TUint8)(quantTable9[(*uFrame)>>2] + value);
				*vFrame = (TUint8)(quantTable9[(*vFrame)>>2] + value);
			}
			break;
		default: 	// e.g., 100% frame1, 0% frame2
			break;
		}
	} 
	return;
}

// ---------------------------------------------------------
// CVideoProcessor::ApplyBlendingTransitionEffect
// Applies blending transition effect between two YUV frames
// (other items were commented in a header).
// ---------------------------------------------------------
//	
void CVideoProcessor::ApplyBlendingTransitionEffect(TUint8* aYUVPtr1, 
												    TUint8* aYUVPtr2, 
												    TInt aRepeatFrame,
												    TInt aTransitionFramenumber)
{
	TInt i;
	TSize tempSize = iProcessor->GetMovieResolution();

	TInt yLength = tempSize.iWidth*tempSize.iHeight; 
	TInt uLength = yLength>>2;	
	TInt yuvLength = yLength + (yLength>>1);
	TUint8* yFrame1 = (TUint8*)aYUVPtr1;
	TUint8* uFrame1 = (TUint8*)(yFrame1+yLength); 
	TUint8* vFrame1 = (TUint8*)(uFrame1+uLength); 	
	TUint8* yFrame2 = (TUint8*)aYUVPtr2;
	TUint8* uFrame2 = (TUint8*)(yFrame2+yLength); 
	TUint8* vFrame2 = (TUint8*)(uFrame2+uLength); 	
	TInt position;
	TPtr8 ptr(0,0);
	const TInt numberOfTables = 10; 

	// corresponding to 0.1, 26 values quantized to 8
	const TUint8 quantTable1[8] = { 
		  4,   7,  10,  13,  16,  19,  22,  24 };
	// corresponding to 0.2, 52 values quantized to 16
	const TUint8 quantTable2[16] = { 
		  4,   8,  12,  15,  18,  21,  24,  27,  30,  33,  36,  39,  42,  45,  48,  50 };
	// corresponding to 0.3, 77 values quantized to 16
	const TUint8 quantTable3[16] = { 
		  5,  10,  15,  20,  24,  29,  33,  38,  42,  47,  51,  56,  61,  66,  71,  75 };
	// corresponding to 0.4, 103 values quantized to 32
	const TUint8 quantTable4[32] = { 
		  5,  10,  14,  18,  21,  24,  27,  30,  33,  36,  39,  42,  45,  48,  51,  54,
		 57,  60,  63,  66,  69,  72,  75,  78,  81,  84,  87,  90,  93,  96,  99, 101 };
	// corresponding to 0.5, 128 values quantized to 32
	const TUint8 quantTable5[32] = { 
		  3,   7,  11,  15,  19,  23,  27,  31,  35,  39,  43,  47,  51,  55,  59,  63,
		 67,  71,  75,  79,  83,  87,  91,  95,  99, 103, 107, 111, 115, 119, 123, 126 };
	// corresponding to 0.6, 154 values quantized to 32
	const TUint8 quantTable6[32] = { 
		  5,  13,  20,  27,  32,  36,  41,  45,  50,  54,  59,  63,  68,  72,  77,  81,
		 86,  90,  95,  99, 103, 108, 112, 117, 121, 126, 130, 135, 139, 144, 148, 152 };
	// corresponding to 0.7, 179 values quantized to 64
	const TUint8 quantTable7[64] = { 
		  5,   8,  11,  14,  17,  20,  23,  26,  29,  32,  35,  38,  41,  44,  47,  50,
		 53,  56,  59,  62,  65,  68,  71,  74,  77,  80,  83,  86,  89,  92,  95,  98,
		101, 104, 107, 110, 113, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146,
		149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 178 };
	// corresponding to 0.8, 204 values quantized to 64
	const TUint8 quantTable8[64] = { 
		  5,  10,  15,  20,  25,  29,  33,  36,  40,  42,  45,  48,  51,  54,  57,  60,
		 63,  66,  69,  72,  75,  78,  81,  84,  87,  90,  93,  96,  99, 102, 105, 108,
		111, 114, 117, 120, 123, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156,
		159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 203 };
	// corresponding to 0.9, 230 values quantized to 64
	const TUint8 quantTable9[64] = { 
		  5,  10,  15,  19,  23,  26,  30,  33,  37,  40,  44,  47,  51,  54,  58,  61,
		 65,  68,  72,  75,  79,  82,  86,  89,  93,  96, 100, 103, 107, 110, 114, 117,
		121, 124, 128, 131, 135, 138, 142, 145, 149, 152, 156, 159, 163, 166, 170, 173,
		177, 180, 184, 187, 191, 194, 198, 201, 205, 208, 212, 215, 219, 222, 226, 228 };

	const TUint8 indexTable[10]={1,2,3,4,5,6,7,8,9,10};

	// figure out the position of the index (determines which table to use) 
	TInt frameNumber = aTransitionFramenumber; 
	if(frameNumber>=iStartNumberOfTransitionFrames) frameNumber=iStartNumberOfTransitionFrames-1;
  TInt index = (frameNumber<<1) + aRepeatFrame;
	if(index>=numberOfTables) index=numberOfTables-1;
	position = indexTable[index];

	// calculate new values
	switch(position) 
	{
	case 10: 	// 0% frame1, 100% frame2
		ptr.Set(yFrame1,yuvLength,yuvLength);
		ptr.Copy(yFrame2,yuvLength);
		break;
	case 9:		// 10% frame1, 90% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable1[(*yFrame1)>>5] + quantTable9[(*yFrame2)>>2]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable1[(*uFrame1)>>5] + quantTable9[(*uFrame2)>>2] - 10);
			*vFrame1 = (TUint8)(quantTable1[(*vFrame1)>>5] + quantTable9[(*vFrame2)>>2] - 10);
		}
		break;
	case 8:		// 20% frame1, 80% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable2[(*yFrame1)>>4] + quantTable8[(*yFrame2)>>2]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable2[(*uFrame1)>>4] + quantTable8[(*uFrame2)>>2] - 15);
			*vFrame1 = (TUint8)(quantTable2[(*vFrame1)>>4] + quantTable8[(*vFrame2)>>2] - 15);
		}
		break;
	case 7:		// 30% frame1, 70% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable3[(*yFrame1)>>4] + quantTable7[(*yFrame2)>>2]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable3[(*uFrame1)>>4] + quantTable7[(*uFrame2)>>2] - 15);
			*vFrame1 = (TUint8)(quantTable3[(*vFrame1)>>4] + quantTable7[(*vFrame2)>>2] - 15);
		}
		break;
	case 6:		// 40% frame1, 60% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable4[(*yFrame1)>>3] + quantTable6[(*yFrame2)>>3]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable4[(*uFrame1)>>3] + quantTable6[(*uFrame2)>>3] - 10);
			*vFrame1 = (TUint8)(quantTable4[(*vFrame1)>>3] + quantTable6[(*vFrame2)>>3] - 10);
		}
		break;
	case 5:		// 50% frame1, 50% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable5[(*yFrame1)>>3] + quantTable5[(*yFrame2)>>3]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable5[(*uFrame1)>>3] + quantTable5[(*uFrame2)>>3] - 5);
			*vFrame1 = (TUint8)(quantTable5[(*vFrame1)>>3] + quantTable5[(*vFrame2)>>3] - 5);
		}
		break;
	case 4: 	// 60% frame1, 40% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable6[(*yFrame1)>>3] + quantTable4[(*yFrame2)>>3]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable6[(*uFrame1)>>3] + quantTable4[(*uFrame2)>>3] - 10);
			*vFrame1 = (TUint8)(quantTable6[(*vFrame1)>>3] + quantTable4[(*vFrame2)>>3] - 10);
		}
		break;
	case 3: 	// 70% frame1, 30% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable7[(*yFrame1)>>2] + quantTable3[(*yFrame2)>>4]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable7[(*uFrame1)>>2] + quantTable3[(*uFrame2)>>4] - 8);
			*vFrame1 = (TUint8)(quantTable7[(*vFrame1)>>2] + quantTable3[(*vFrame2)>>4] - 8);
		}
		break;
	case 2: 	// 80% frame1, 20% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable8[(*yFrame1)>>2] + quantTable2[(*yFrame2)>>4]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable8[(*uFrame1)>>2] + quantTable2[(*uFrame2)>>4] - 8);
			*vFrame1 = (TUint8)(quantTable8[(*vFrame1)>>2] + quantTable2[(*vFrame2)>>4] - 8);
		}
		break;
	case 1: 	// 90% frame1, 10% frame2
		for(i=0; i<yLength; i++, yFrame1++,yFrame2++) // Y
			*yFrame1 = (TUint8)(quantTable9[(*yFrame1)>>2] + quantTable1[(*yFrame2)>>5]);
		for(i=0; i<uLength; i++, uFrame1++,uFrame2++,vFrame1++,vFrame2++)	// U
		{
			*uFrame1 = (TUint8)(quantTable9[(*uFrame1)>>2] + quantTable1[(*uFrame2)>>5] - 5);
			*vFrame1 = (TUint8)(quantTable9[(*vFrame1)>>2] + quantTable1[(*vFrame2)>>5] - 5);
		}
		break;
	default: 	// e.g., 100% frame1, 0% frame2
		break;
	}
	return;
}


// ---------------------------------------------------------
// CVideoProcessor::ApplySlidingTransitionEffect
// Applies sliding transition effect between two YUV frames
// (other items were commented in a header).
// ---------------------------------------------------------
//	
void CVideoProcessor::ApplySlidingTransitionEffect(TUint8* aYUVPtr1, 
												   TUint8* aYUVPtr2,
												   TVedMiddleTransitionEffect aVedMiddleTransitionEffect,
												   TInt aRepeatFrame,
												   TInt aTransitionFramenumber)
{
	TInt i;
	TSize tempSize = iProcessor->GetMovieResolution();
	TInt yLength = tempSize.iWidth*tempSize.iHeight;
	TInt uLength = yLength>>2;
	TInt yWidth = tempSize.iWidth;
	TInt uWidth = tempSize.iWidth>>1;
	TInt yHeight = tempSize.iHeight; 
	TInt uHeight = tempSize.iHeight>>1; 
	TUint8* yFrame1 = (TUint8*)aYUVPtr1;
	TUint8* uFrame1 = (TUint8*)(yFrame1+yLength); 
	TUint8* vFrame1 = (TUint8*)(uFrame1+uLength); 	
	TUint8* yFrame2 = (TUint8*)aYUVPtr2;
	TUint8* uFrame2 = (TUint8*)(yFrame2+yLength); 
	TUint8* vFrame2 = (TUint8*)(uFrame2+uLength); 	
	TPtr8 ptr(0,0);
	TInt offset = 0;
	TInt ySliceWidth = 0;
	TInt uSliceWidth = 0;
	TInt sliceSize = 0;
	TInt frameNumber = (aTransitionFramenumber<<1) + aRepeatFrame;

	switch(aVedMiddleTransitionEffect)
	{
		case EVedMiddleTransitionEffectWipeLeftToRight:
			// figure out the amount of data to change 
            VDASSERT(iStartNumberOfTransitionFrames,19);
			ySliceWidth = (TInt)((TReal)yWidth * (TReal)(frameNumber+1)/(TReal)(iStartNumberOfTransitionFrames<<1) + 0.5); 
			if(ySliceWidth>yWidth) ySliceWidth = yWidth; 
			uSliceWidth = ySliceWidth>>1; 
			// copy the relevant portions of the image from frame2 to frame1 
			// y
			for(i=0; i<yHeight; i++, yFrame1+=yWidth,yFrame2+=yWidth)
			{
				ptr.Set(yFrame1,ySliceWidth,ySliceWidth);
				ptr.Copy(yFrame2,ySliceWidth);
			}
			// u,v
			for(i=0; i<uHeight; i++, uFrame1+=uWidth,uFrame2+=uWidth,vFrame1+=uWidth,vFrame2+=uWidth)
			{
				ptr.Set(uFrame1,uSliceWidth,uSliceWidth);
				ptr.Copy(uFrame2,uSliceWidth);
				ptr.Set(vFrame1,uSliceWidth,uSliceWidth);
				ptr.Copy(vFrame2,uSliceWidth);
			}
			break;
		case EVedMiddleTransitionEffectWipeRightToLeft:
			// figure out the amount of data to change 
            VDASSERT(iStartNumberOfTransitionFrames,20);
			ySliceWidth = (TInt)((TReal)yWidth * (TReal)(frameNumber+1)/(TReal)(iStartNumberOfTransitionFrames<<1) + 0.5); 
			if(ySliceWidth>yWidth) ySliceWidth = yWidth; 
			uSliceWidth = ySliceWidth>>1; 
			// evaluate the yuv offsets and new positions to point to in the buffer
			offset = yWidth-ySliceWidth;
			yFrame1+=offset;
			yFrame2+=offset;
			offset = uWidth-uSliceWidth;
			uFrame1+=offset;
			uFrame2+=offset;
			vFrame1+=offset;
			vFrame2+=offset;
			// copy the relevant portions of the image from frame2 to frame1 
			// y
			for(i=0; i<yHeight; i++, yFrame1+=yWidth,yFrame2+=yWidth)
			{
				ptr.Set(yFrame1,ySliceWidth,ySliceWidth);
				ptr.Copy(yFrame2,ySliceWidth);
			}
			// u,v
			for(i=0; i<uHeight; i++, uFrame1+=uWidth,uFrame2+=uWidth,vFrame1+=uWidth,vFrame2+=uWidth)
			{
				ptr.Set(uFrame1,uSliceWidth,uSliceWidth);
				ptr.Copy(uFrame2,uSliceWidth);
				ptr.Set(vFrame1,uSliceWidth,uSliceWidth);
				ptr.Copy(vFrame2,uSliceWidth);
			}
			break;
		case EVedMiddleTransitionEffectWipeTopToBottom:
			// figure out the amount of data to change 
            VDASSERT(iStartNumberOfTransitionFrames,21);
			ySliceWidth = (TInt)((TReal)yHeight * (TReal)(frameNumber+1)/(TReal)(iStartNumberOfTransitionFrames<<1) + 0.5); 
			if(ySliceWidth>yHeight) ySliceWidth = yHeight; 
			uSliceWidth = ySliceWidth>>1; 
			// copy the relevant portions of the image from frame2 to frame1 
			// y
			sliceSize = ySliceWidth * yWidth;
			ptr.Set(yFrame1,sliceSize,sliceSize);
			ptr.Copy(yFrame2,sliceSize);
			// u,v
			sliceSize = uSliceWidth * uWidth;
			ptr.Set(uFrame1,sliceSize,sliceSize);
			ptr.Copy(uFrame2,sliceSize);
			ptr.Set(vFrame1,sliceSize,sliceSize);
			ptr.Copy(vFrame2,sliceSize);
			break;
		case EVedMiddleTransitionEffectWipeBottomToTop:
			// figure out the amount of data to change 
            VDASSERT(iStartNumberOfTransitionFrames,22);
			ySliceWidth = (TInt)((TReal)yHeight * (TReal)(frameNumber+1)/(TReal)(iStartNumberOfTransitionFrames<<1) + 0.5); 
			if(ySliceWidth>yHeight) ySliceWidth = yHeight; 
			uSliceWidth = ySliceWidth>>1; 
			// evaluate the yuv offsets and new positions to point to in the buffer
			offset = (yHeight-ySliceWidth) * yWidth;
			yFrame1+=offset;
			yFrame2+=offset;
			offset = (uHeight-uSliceWidth) * uWidth;
			uFrame1+=offset;
			uFrame2+=offset;
			vFrame1+=offset;
			vFrame2+=offset;
			// copy the relevant portions of the image from frame2 to frame1 
			// y
			sliceSize = ySliceWidth * yWidth;
			ptr.Set(yFrame1,sliceSize,sliceSize);
			ptr.Copy(yFrame2,sliceSize);
			// u,v
			sliceSize = uSliceWidth * uWidth;
			ptr.Set(uFrame1,sliceSize,sliceSize);
			ptr.Copy(uFrame2,sliceSize);
			ptr.Set(vFrame1,sliceSize,sliceSize);
			ptr.Copy(vFrame2,sliceSize);
			break;		
		case EVedMiddleTransitionEffectNone:
		case EVedMiddleTransitionEffectDipToBlack:
		case EVedMiddleTransitionEffectDipToWhite:
		case EVedMiddleTransitionEffectCrossfade:
		case EVedMiddleTransitionEffectLast:
		default:
			break;
	}
	return;
}


// ---------------------------------------------------------
// CVideoProcessor::ApplySpecialEffect
// Applies color effect for a YUV frame
// (other items were commented in a header).
// ---------------------------------------------------------
//	
void CVideoProcessor::ApplySpecialEffect(TInt aColorEffect, TUint8* aYUVDataPtr, 
                                         TInt aColorToneU, TInt aColorToneV)
{
	VDASSERT(aYUVDataPtr,23); 
	VDASSERT(iVideoWidth,24); 
	VDASSERT(iVideoHeight,25); 
	TChar chr; 
	TInt value; 
	TInt offset;
	TInt length;
	// Values for the U & V Fill parameters
	TInt uFillValue, vFillValue;
	TPtr8 ptr(0,0); 
	TSize tempSize = iProcessor->GetMovieResolution();
	
	// asad - check if mpeg4, then change pixel range from (-128,127) to (0,255)
	if (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile)
	{
		// U
		aColorToneU += 128;
		if (aColorToneU<0)	 aColorToneU = 0;
		if (aColorToneU>255) aColorToneU = 255;
		// V
		aColorToneV += 128; 
		if (aColorToneV<0)	 aColorToneV = 0;
		if (aColorToneV>255) aColorToneV = 255;
	}
	TChar uChr, vChr;
	switch(aColorEffect)
	{
		case 0/*None*/: 
			return; 
		case 1/*BW*/:	
			value = 128; 
			chr = value;
			offset = tempSize.iWidth*tempSize.iHeight;
			length = offset>>1;								// u,v data length (2*L/2*W/2)
			ptr.Set((TUint8*)(aYUVDataPtr+offset), length, length); 
			ptr.Fill((TChar)chr); 
			break;
		case 2:
			offset = tempSize.iWidth*tempSize.iHeight;
			length = offset>>2;
			uFillValue = aColorToneU;
			uChr = uFillValue;
			vFillValue = aColorToneV;
			vChr = vFillValue;
			
			ptr.Set((TUint8*)(aYUVDataPtr + offset), length, length);
			ptr.Fill((TChar)uChr);
			
			offset = 1.25 * offset; // For filling the v-value
			ptr.Set((TUint8*)(aYUVDataPtr + offset), length, length);
			ptr.Fill((TChar)vChr);
			break;
		default:			
			return; 
	}
}

// ---------------------------------------------------------
// CVideoProcessor::TFrameOperation2TInt
// Converts frame operation enumeration to int
// (other items were commented in a header).
// ---------------------------------------------------------
//	
TInt CVideoProcessor::TFrameOperation2TInt(TDecoderFrameOperation aFrameOperation)
{
	switch(aFrameOperation)
	{
		case EDecodeAndWrite:
			return 1;
		case EDecodeNoWrite:
			return 2;
		case EWriteNoDecode:
			return 3;
		case ENoDecodeNoWrite:
			return 4;
		default:
			return KErrGeneral;
	}
}

// ---------------------------------------------------------
// CVideoProcessor::TColorEffect2TInt
// Converts  color effect enumeration to int
// (other items were commented in a header).
// ---------------------------------------------------------
//	
TInt CVideoProcessor::TColorEffect2TInt(TVedColorEffect aColorEffect)
{
	switch(aColorEffect)
	{
		case EVedColorEffectNone:
			return 0;
		case EVedColorEffectBlackAndWhite:
			return 1;
	    case EVedColorEffectToning:
			return 2;		
		default:
			return KErrGeneral;
	}
}



// ---------------------------------------------------------
// CVideoProcessor::InputDataAvailable
// Overridden CDataProcessor::InputDataAvailable() method
// Called when new input blocks are available
// (other items were commented in a header).
// ---------------------------------------------------------
//	
void CVideoProcessor::InputDataAvailable(TAny* /*aUserPointer*/)
{
    PRINT((_L("CVideoProcessor::InputDataAvailable()")));   
	// Signal ourselves if we are decoding and a request is not
	// pending:
	if ( iDecoding && !iTranscoderInitPending && !iDecodePending &&
	     (iStatus == KRequestPending) )
	{
	    PRINT((_L("CVideoProcessor::InputDataAvailable() - complete request")));   
		TRequestStatus *status = &iStatus;
		User::RequestComplete(status, KErrNone);
	}
}


// ---------------------------------------------------------
// CVideoProcessor::StreamEndReached
// Overridden CDataProcessor::StreamEndReached() method
// Called when input stream has ended
// (other items were commented in a header).
// ---------------------------------------------------------
//

void CVideoProcessor::StreamEndReached(TAny* /*aUserPointer*/)
{
    PRINT((_L("CVideoProcessor::StreamEndReached()")));   
	iStreamEnd = ETrue;
}

// ---------------------------------------------------------
// CVideoProcessor::DoCancel
// Cancels any asynchronous requests pending.
//
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::DoCancel()
{

	// Cancel our internal request
	if ( iStatus == KRequestPending )
	{
		TRequestStatus *status = &iStatus;
		User::RequestComplete(status, KErrCancel);
	}

}

// ---------------------------------------------------------
// CVideoProcessor::GetNextClipTransitionInfo
// Get the start transition info of the next clip.
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CVideoProcessor::GetNextClipTransitionInfo()
{
	if ( iNextTransitionNumber == -1 )
	{
		iNextTransitionNumber = iProcessor->NextClipStartTransitionNumber();
	}
}

// ---------------------------------------------------------
// CVideoProcessor::DetermineResolutionChange
// This function checks if the video clip is needed to be resampled
// (other items were commented in a header).
// ---------------------------------------------------------
// Resolution Transcoder, check if this video clip need to be resample

TBool CVideoProcessor::DetermineResolutionChange()
{
	TSize VideoClipResolution = iProcessor->GetVideoClipResolution();
	TSize MovieResolution = iProcessor->GetMovieResolution();
	if (VideoClipResolution != MovieResolution)
		return ETrue;
	else
		return EFalse;
}

// ---------------------------------------------------------
// CVideoProcessor::DetermineFrameRateChange
// This function checks if the frame rate must be changed
// => clip re-encoded
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CVideoProcessor::DetermineFrameRateChange()
    {

    TReal clipFrameRate = iProcessor->GetVideoClipFrameRate();
    TReal movieFrameRate = iProcessor->GetMovieFrameRate();

    // Do re-encoding only when reducing frame rate, 
    // otherwise we would have to come up with new frames
    if ( movieFrameRate > 0 && clipFrameRate > movieFrameRate )
        return ETrue;

    return EFalse;
        
    }

// ---------------------------------------------------------
// CVideoProcessor::DetermineFrameRateChange
// This function checks if the bitrate must be changed
// => clip re-encoded
// (other items were commented in a header).
// ---------------------------------------------------------
//
TBool CVideoProcessor::DetermineBitRateChange()
    {

    // : AVC bitrate transcoding from a higher level
    //       to lower if resolution transcoding is not needed

    if ( iProcessor->GetMovieVideoBitrate() > 0 ) // movie has bitrate restriction => need to transcode
        return ETrue;
    
    if ( iProcessor->GetOutputVideoType() == EVedVideoTypeH263Profile0Level10 )
    {
        if (iDataFormat == EDataH263)
        {
            if ( (iProcessor->GetCurrentClipVideoType() != EVedVideoTypeH263Profile0Level10) &&
                 (iProcessor->GetCurrentClipVideoType() != EVedVideoTypeUnrecognized) )
                return ETrue;
        }
        
        else if (iDataFormat == EDataMPEG4)
        {
            // level 0 and level 1 max bitrate is 64 kb/s
            // others need to be transcoded
            if (iInputMPEG4ProfileLevelId != 8 && iInputMPEG4ProfileLevelId != 1)
                return ETrue;
        }
    }

    return EFalse;

    }


// ---------------------------------------------------------
// CVideoProcessor::GetFrameDuration
// Calculates the duration of current frame
// (other items were commented in a header).
// ---------------------------------------------------------
//
TInt CVideoProcessor::GetFrameDuration(TInt aFrameNumber)
{
    // calculate frame duration in ticks
    TInt startFrame = iProcessor->GetOutputNumberOfFrames() - iNumberOfFrames;
    TInt absFrameNumber = startFrame + aFrameNumber;
    TInt cur = absFrameNumber;
    TInt next = cur+1;
        
    // frameDuration is in ticks, with timescale of the current input clip
    if(next >= iProcessor->GetOutputNumberOfFrames())	
    {                		
    	return I64INT(iProcessor->GetVideoClipDuration() - iProcessor->VideoFrameTimeStamp(cur) );
    }
    else
    {
    	return I64INT( iProcessor->VideoFrameTimeStamp(next) - iProcessor->VideoFrameTimeStamp(cur) );                	
    }
}

// ---------------------------------------------------------
// CVideoProcessor::CheckVosHeaderL
// Checks whether the resynch bit is set if set then resets to zero
// (other items were commented in a header).
// @return TBool 
// ---------------------------------------------------------
//

TBool CVideoProcessor::CheckVosHeaderL(TPtrC8& aBuf)
{
	return iDecoder->CheckVOSHeaderL((TPtrC8&)aBuf);
}


// ---------------------------------------------------------
// CVideoProcessor::RenderFrame
// The H.263 decoder calls this function when a decoded
// frame is available for retrieving
// @return TInt
// ---------------------------------------------------------
//
TInt CVideoProcessor::RenderFrame(TAny* aFrame)
{	
	iDecoder->FrameRendered(aFrame);		
	return KErrNone;
}

// ---------------------------------------------------------
// CVideoProcessor::MtoTimerElapsed
// Called when timer has elapsed
// ---------------------------------------------------------
//
void CVideoProcessor::MtoTimerElapsed(TInt aError)
{   

    PRINT((_L("CVideoProcessor::MtoTimerElapsed() begin")));     

    if (aError != KErrNone)
    {
        iMonitor->Error(aError);
        return;   
    }
    
    VDASSERT(iFrameInfoArray[0].iEncodeFrame == 1, 110);        

    // if next frame in encode queue is an intermediate modification frame
    // and modification has not yet been applied, start waiting timer again        
    if ( ( (iFrameInfoArray[0].iTransitionFrame == 1) ||
           (iProcessor->GetColorEffect() != EVedColorEffectNone) ) &&
           iFrameInfoArray[0].iModificationApplied == 0 )
    {
        PRINT((_L("CVideoProcessor::MtoTimerElapsed() - modification not done yet, set timer")));
        
        iTimer->SetTimer( TTimeIntervalMicroSeconds32( GetEncodingDelay() ) );
        return;
    }
       
    PRINT((_L("CVideoProcessor::MtoTimerElapsed() - removing pic with ts %d ms"), 
        I64INT(iProcessor->GetVideoTimeInMsFromTicks(iFrameInfoArray[0].iTimeStamp, EFalse)) ))

    // save frame number to be able to recover in case the frame 
    // gets encoded regardless of the delay    
    iSkippedFrameNumber = iFrameInfoArray[0].iFrameNumber;
    
    // remove skipped frame from queue
    iFrameInfoArray.Remove(0);        
    
    PRINT((_L("CVideoProcessor::MtoTimerElapsed() - %d items in queue"), iFrameInfoArray.Count()));

    if (iDecodingSuspended && !iStreamEndRead)
    {
        if (iFrameInfoArray.Count() < iMaxItemsInProcessingQueue && !iDelayedWrite)
        {            
            PRINT((_L("CVideoProcessor::MtoTimerElapsed() - Resume decoding")));
            iDecodingSuspended = EFalse;
            // activate object to start decoding
            TRequestStatus *status = &iStatus;
            User::RequestComplete(status, KErrNone);
            return;
        }
    }    
    
    if ( !IsEncodeQueueEmpty() )
    {    
        // if there are still frames to be encoded, and next one is waiting,
        // set timer again
        if ( IsNextFrameBeingEncoded() )
        {
            if ( !iTimer->IsPending() )
            {
                PRINT((_L("CVideoProcessor::MtoTimerElapsed(), set timer again")));   
                iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
            }
        }
        return;
    }        
        
    if (iDelayedWrite)
    {     
        PRINT((_L("CVideoProcessor::MtoTimerElapsed(), writing delayed frame")));
        // write delayed frame
        TRAPD( error, WriteDelayedFrameL() );
        if (error != KErrNone)
        {
            iMonitor->Error(aError);
            return;   
        }
    }          
    
    if ( iStreamEndRead )
    {
        if ( iFrameInfoArray.Count() != 0 )
        {            
            // return now if we have read stream end, but there are still frames waiting
            // to be decoded => processing will be completed in MtroPictureFromTranscoder   
            PRINT((_L("CVideoProcessor::MtoTimerElapsed(), end read but frames in progress, return")));
            return;
        }
        
        else
        {
            // activate to stop processing
            PRINT((_L("CVideoProcessor::MtoTimerElapsed(), end read and all frames processed, stopping")));
            iProcessingComplete = ETrue;
        }
    }

    if (!IsActive())    
    {
        SetActive();
        iStatus = KRequestPending;
    }    
    // activate object to continue/end processing
    TRequestStatus *status = &iStatus;
    User::RequestComplete(status, KErrNone);               
    PRINT((_L("CVideoProcessor::MtoTimerElapsed() end")));
}

// ---------------------------------------------------------
// CVideoProcessor::WriteBufferL
// Called by transcoder to pass an encoded buffer
// ---------------------------------------------------------
//
void CVideoProcessor::WriteBufferL(CCMRMediaBuffer* aBuffer)
{
    if ( iFrameInfoArray.Count() == 0 )
        {
        PRINT((_L("CVideoProcessor::WriteBufferL() not ready to receive buffer, return")));
        return;
        }

    if ( ((iFrameInfoArray[0].iTranscoderMode != EFullWithIM) &&
          (iFrameInfoArray[0].iTranscoderMode != EFull)) ||
         (iFrameInfoArray[0].iEncodeFrame != 1) )
        {
        PRINT((_L("CVideoProcessor::WriteBufferL() encoded picture received but not expected, ignore & return")));
        return;
        }
        
               
    // cancel timer
    iTimer->CancelTimer();                	
	
	if (aBuffer->Type() == CCMRMediaBuffer::EVideoMPEG4DecSpecInfo)
	{
	    // should not happen
	    return;
	}		

    TTimeIntervalMicroSeconds encodedTs = aBuffer->TimeStamp();        
    
    PRINT((_L("CVideoProcessor::WriteBufferL(), timestamp %d ms, keyFrame = %d"),
               I64INT( encodedTs.Int64() ) / 1000, aBuffer->RandomAccessPoint() ));
    
    TBool removeItem = ETrue;
    TInt64 timeStamp = 0;    
    TInt frameNumber = 0;
    
    while (iFrameInfoArray.Count())
    {
        TTimeIntervalMicroSeconds ts = (iProcessor->GetVideoTimeInMsFromTicks(iFrameInfoArray[0].iTimeStamp, EFalse)) * 1000;

        if (ts < encodedTs)
        {            
            // a frame has been skipped
            iFrameInfoArray.Remove(0);
            PRINT((_L("CVideoProcessor::WriteBufferL() frame skipped - number of items in queue: %d"), iFrameInfoArray.Count()));    
        } 
        else if (ts > encodedTs)
        {
            // this frame has most likely been treated as skipped using timer, 
            // but it was encoded regardless
            removeItem = EFalse;
            frameNumber = iSkippedFrameNumber;
            timeStamp = iProcessor->GetVideoTimeInTicksFromMs( encodedTs.Int64() / 1000, EFalse );

            PRINT((_L("CVideoProcessor::WriteBufferL() frame skipped falsely, ts in ticks = %d"), I64INT(timeStamp)));            
            break;
        }       
        else
        {
            // normal case, encoded frame timestamp is as expected
            timeStamp = iFrameInfoArray[0].iTimeStamp;
            frameNumber = iFrameInfoArray[0].iFrameNumber;
            break;
        }
    }
    
    VDASSERT(iFrameInfoArray.Count(), 50);    
    
    // set descriptor for writing the frame
    TPtr8 writeDes(0,0);			
	writeDes.Set(const_cast<TUint8*>(aBuffer->Data().Ptr()), 
	             aBuffer->Data().Length(), aBuffer->Data().Length());

    HBufC8* tempBuffer = 0;
    TInt error;           

    if ( (iProcessor->GetOutputVideoType() == EVedVideoTypeMPEG4SimpleProfile) &&
         (!iOutputVolHeaderWritten) && (frameNumber >= iFirstIncludedFrameNumber) )         
    {
	    VDASSERT(iOutputVolHeader, 51);
	    
	    // MPEG-4 output:
	    // Encoded frame is the first one of the clip, insert VOL header at the beginning
	    // Allocate a temp buffer to include vol header and	the encoded frame	    
	    TInt length = iOutputVolHeader->Length() + aBuffer->Data().Length();	    	   
	    TRAP(error, tempBuffer = (HBufC8*) HBufC8::NewL(length) );
	    
	    if (error != KErrNone)
        {
            iMonitor->Error(error);
            return;
        }        
	    
	    TPtr8 ptr( tempBuffer->Des() );
	    ptr.Copy(iOutputVolHeader->Des());	    
	    ptr.Append(aBuffer->Data());
	    
	    writeDes.Set(tempBuffer->Des());
	    iOutputVolHeaderWritten = ETrue;
	}
	
#ifdef VIDEOEDITORENGINE_AVC_EDITING
	if (iProcessor->GetOutputVideoType() == EVedVideoTypeAVCBaselineProfile)
	{		   

	   // get number of NAL units	   
       TUint8* tmp = const_cast<TUint8*>(aBuffer->Data().Ptr() + aBuffer->Data().Length());
       
       tmp -= 4;
       TInt numNalUnits = TInt(tmp[0]) + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);
              
       TInt totalLength = 0;
              
       // get nal_unit_type of first NAL
       TUint8* type = const_cast<TUint8*>(aBuffer->Data().Ptr());
       TInt nalType = *type & 0x1F;       
       
       PRINT((_L("CVideoProcessor::WriteBufferL() - # of NAL units = %d, frame # = %d, nal_unit_type = %d"), 
           numNalUnits, frameNumber, nalType));       
       
       if (nalType != 1 && nalType != 5)
       {
           // there are extra SPS/PPS units in the beginning
           // of the buffer, skip those
           numNalUnits--;
           
           if (numNalUnits == 0)
           {
               PRINT((_L("CVideoProcessor::WriteBufferL() No NAL units left, return")));            
               return;
           }
           
           // point to first length field
           tmp = const_cast<TUint8*>(aBuffer->Data().Ptr() + aBuffer->Data().Length());
           tmp -= 4;  // #
           tmp -= numNalUnits * 8; // offset & length for each NAL
           tmp += 4;  // skip offset

           // get NAL length
           TInt len = TInt(tmp[0]) + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);           
           type += len;
           nalType = *type & 0x1F;
           
           while (nalType != 1 && nalType != 5 && numNalUnits)
           {
               numNalUnits--;
               tmp += 8;
               len = TInt(tmp[0]) + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);
               type += len;
               nalType = *type & 0x1F;
           }
           tmp = const_cast<TUint8*>(aBuffer->Data().Ptr() + aBuffer->Data().Length()) - 4;
       }
       
       if (numNalUnits == 0)
       {
           PRINT((_L("CVideoProcessor::WriteBufferL() No NAL units left, return")));
           return;
       }
       
       // rewind to last length field
       tmp -= 4;
       
       // get total length of slices
       for (TInt x = numNalUnits; x > 0; x--)
       {
           totalLength += TInt(tmp[0]) + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);
           tmp -= 8;
       }

       TInt tempLength = totalLength + numNalUnits*4;
              
       // allocate output buffer
	   TRAP(error, tempBuffer = (HBufC8*) HBufC8::NewL(tempLength) );
       if (error != KErrNone)
       {
           iMonitor->Error(error);
           return;  
       }

	   TUint8* dst = const_cast<TUint8*>(tempBuffer->Des().Ptr());
	   TUint8* src = const_cast<TUint8*>(aBuffer->Data().Ptr());
       
       // point to first offset field
       tmp += 4;

       for (TInt x = numNalUnits; x > 0; x--)
       {
           // get length
           tmp += 4;
           TInt length = TInt(tmp[0]) + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);
           
           // set length           
           dst[0] = TUint8((length >> 24) & 0xff);
           dst[1] = TUint8((length >> 16) & 0xff);
           dst[2] = TUint8((length >> 8) & 0xff);
           dst[3] = TUint8(length & 0xff);
           dst += 4;
           
           // copy data
           TPtr8 ptr(dst, length);
           ptr.Copy(src, length);
           
           dst += length;
           src += length;
           
           // point to next offset field
           tmp +=4;
       }       

       writeDes.Set(tempBuffer->Des());
       writeDes.SetLength(tempLength);

	}
#endif
	
	// Figure out are we writing frames from the first
	// or second clip in color transition
			
    TBool colorTransitionFlag = ETrue;
    TInt index = KNumTransitionFrames / 4;    
	
	if ( iFrameInfoArray[0].iTransitionFrame == 1 &&
         iFrameInfoArray[0].iTransitionPosition == EPositionStartOfClip && 
         iStartTransitionColor == EColorTransition )
	{
	    if ( ( (iFrameInfoArray[0].iTransitionFrameNumber == index) && 
	           (iFrameInfoArray[0].iRepeatFrame == 0) ) ||
	            iFrameInfoArray[0].iTransitionFrameNumber < index )
	    {
            colorTransitionFlag = EFalse;
	    }
	}				

    // write frame
    error = iProcessor->WriteVideoFrameToFile((TDesC8&)writeDes, 
                     timeStamp, 0 /*dummy*/, 
                     aBuffer->RandomAccessPoint(), EFalse, colorTransitionFlag, ETrue );

    if (tempBuffer)    
        delete tempBuffer;                         
                     
    if (error == KErrCompletion)
    {
        PRINT((_L("CVideoProcessor::WriteBufferL() - processing complete")));    
        // stop processing
        iProcessingComplete = ETrue;
        iFrameInfoArray.Reset();
        VDASSERT(iTranscoderStarted, 51);
        iTransCoder->StopL();
        iTranscoderStarted = EFalse;
        if (!IsActive())
        {
            SetActive();
            iStatus = KRequestPending;
        }        
            
        // activate object to end processing
        TRequestStatus *status = &iStatus;
        User::RequestComplete(status, KErrNone);       
        return;
    }
    
    else if (error != KErrNone)
    {
        iMonitor->Error(error);
        return;
    }        
                     
    TInt startFrame = iProcessor->GetOutputNumberOfFrames() - iNumberOfFrames;
    TInt absFrameNumber = startFrame + frameNumber;
    
    // save frame number
    iLastWrittenFrameNumber = frameNumber;
    
    iProcessor->SetFrameType(absFrameNumber, aBuffer->RandomAccessPoint());
    
    if (removeItem)
    {        
        iFrameInfoArray.Remove(0);     
           
        PRINT((_L("CVideoProcessor::WriteBufferL() - removed encoded pic, %d items in queue"), iFrameInfoArray.Count()));
    } 
    else
        PRINT((_L("CVideoProcessor::WriteBufferL() - did not remove encoded pic, %d items in queue"), iFrameInfoArray.Count()));
        
           
    if (iDecodingSuspended && !iStreamEndRead)
    {
        if (iFrameInfoArray.Count() < iMaxItemsInProcessingQueue && !iDelayedWrite)
        {            
            PRINT((_L("CVideoProcessor::WriteBufferL() - Resume decoding")));
            iDecodingSuspended = EFalse;
            // activate object to start decoding
            TRequestStatus *status = &iStatus;
            User::RequestComplete(status, KErrNone);
            return;
        }
    }
        
    // if there are still frames to be encoded, start timer again        
    if ( !IsEncodeQueueEmpty() )
    {
        // check if the next frame in queue is waiting to be encoded, set timer if so
        if ( IsNextFrameBeingEncoded() )
        {
            if ( !iTimer->IsPending() )
            {
                PRINT((_L("CVideoProcessor::WriteBufferL(), set timer")));   
                iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
            }
        }
        return;
    }

    if (iStreamEndRead && !iDelayedWrite)
    {
    
        PRINT((_L("CVideoProcessor::WriteBufferL() - stream end read & !iDelayedWrite")));    
    
        // stream end has been read
        if (iFrameInfoArray.Count() == 0)
        {
            PRINT((_L("CVideoProcessor::WriteBufferL() - stream end read, no frames left")));
            // end
            if (!IsActive())
            {
                SetActive();
                iStatus = KRequestPending;
            }        
            iProcessingComplete = ETrue;
            // activate object to end processing
            TRequestStatus *status = &iStatus;
            User::RequestComplete(status, KErrNone);                   
        }        
        // else there are frames to be decoded, processing will be completed
        // MtroPictureFromTranscoder
        return;
    }

    if (iDelayedWrite)
    {
        if ( IsEncodeQueueEmpty() )
        {
            PRINT((_L("CVideoProcessor::WriteBufferL() writing delayed frame")));            
            
            TRAP(error, WriteDelayedFrameL());
            if (error != KErrNone)
            {
                iMonitor->Error(error);
                return;
            }

            if ( iStreamEndRead )
            {
                if ( iFrameInfoArray.Count() != 0 )
                {            
                    // return now if we have read stream end, but there are still frames waiting
                    // to be decoded => processing will be completed in MtroPictureFromTranscoder   
                    PRINT((_L("CVideoProcessor::WriteBufferL(), end read but frames in progress, return")));
                    return;
                }                
                else
                {
                    // activate to stop processing
                    PRINT((_L("CVideoProcessor::WriteBufferL(), end read and all frames processed, stopping")));
                    iProcessingComplete = ETrue;
                }
            }
            
            if (!IsActive())
            {
                SetActive();
                iStatus = KRequestPending;
            }
            // activate object to continue/end processing
            TRequestStatus *status = &iStatus;
            User::RequestComplete(status, KErrNone);
            return;
        }
        else
        {                
            // check if the next frame in queue is waiting to be encoded, set timer if so
            if ( IsNextFrameBeingEncoded() )
            {
                if ( !iTimer->IsPending() )
                {
                    PRINT((_L("CVideoProcessor::WriteBufferL() - iDelayedWrite, set timer")));   
                    iTimer->SetTimer( TTimeIntervalMicroSeconds32( iMaxEncodingDelay ) );
                }            
                return;
            }
        }
    }        
      
}

// ---------------------------------------------------------
// CVideoProcessor::IsEncodeQueueEmpty
// (other items were commented in a header)
// ---------------------------------------------------------
//
TBool CVideoProcessor::IsEncodeQueueEmpty()
{

    // check if there are still frames waiting to be encoded
    for (TInt i = 0; i < iFrameInfoArray.Count(); i++)
    {
         if (iFrameInfoArray[i].iEncodeFrame == 1)             
         {
             return EFalse;         
         }
    }
    return ETrue;
    
}

// ---------------------------------------------------------
// CVideoProcessor::IsNextFrameBeingEncoded
// (other items were commented in a header)
// ---------------------------------------------------------
//
TBool CVideoProcessor::IsNextFrameBeingEncoded()
{
   
    // check if the next frame in queue is waiting to be encoded
    if ( iFrameInfoArray.Count() && (iFrameInfoArray[0].iEncodeFrame == 1) )
    {
        
        VDASSERT( ( iFrameInfoArray[0].iTranscoderMode == EFull ||
                    iFrameInfoArray[0].iTranscoderMode == EFullWithIM ), 120 );
        
        if ( (iFrameInfoArray[0].iTranscoderMode == EFull) ||
             (iFrameInfoArray[0].iModificationApplied == 1) )
        {
            return ETrue;            
        }
    }
       
    return EFalse;
    
}

// ---------------------------------------------------------
// CVideoProcessor::GetEncodingDelay
// (other items were commented in a header)
// ---------------------------------------------------------
//
TInt CVideoProcessor::GetEncodingDelay()
{

    // number of decode only -frames in queue before first encode frame
    TInt numDecodeFrames = 0;
    
    TInt i;
    for (i = 0; i < iFrameInfoArray.Count(); i++)
    {
        // get index of next encode frame in queue
        if (iFrameInfoArray[i].iEncodeFrame == 1)
            break;
        else 
            numDecodeFrames++;
    }
    
    VDASSERT(i < iFrameInfoArray.Count(), 112);
    
    TInt delay = iMaxEncodingDelay;
    
    // If the next frame in encoding queue is an intermediate modification frame
    // (either transition frame or color effect has to be applied)    
    // and modification has not been applied to it, double the default delay    
    if ( ( (iFrameInfoArray[0].iTransitionFrame == 1) ||
           (iProcessor->GetColorEffect() != EVedColorEffectNone) ) &&
           iFrameInfoArray[0].iModificationApplied == 0 )
    {
        PRINT((_L("CVideoProcessor::GetEncodingDelay() - double the delay")));
        delay <<= 1;
    }        
    
    // add time to process decode-only frames to delay
    delay += numDecodeFrames * (iMaxEncodingDelay / 2);
    
    PRINT((_L("CVideoProcessor::GetEncodingDelay() - encoding delay = %d ms, num decode frames %d"), delay/1000, numDecodeFrames));
            
    return delay;
        
    
    
}

// ---------------------------------------------------------
// CVideoProcessor::WriteDelayedFrameL
// (other items were commented in a header)
// ---------------------------------------------------------
//
void CVideoProcessor::WriteDelayedFrameL()
{

    PRINT((_L("CVideoProcessor::WriteDelayedFrameL() begin")));
    
    // write the delayed frame
    TPtr8 ptr(iDelayedBuffer->Des());            
    
    TInt error = iProcessor->WriteVideoFrameToFile(ptr, 
                iDelayedTimeStamp, 0 /*dummy*/, 
                iDelayedKeyframe, EFalse, EFalse, EFalse );
                
    if (error == KErrCompletion)
    {
        PRINT((_L("CVideoProcessor::WriteDelayedFrameL() write delayed frame, processing complete")));
        VDASSERT(iTranscoderStarted, 51);
        iTransCoder->StopL();
        iTranscoderStarted = EFalse;
        iFrameInfoArray.Reset();
        iTimer->CancelTimer();
        iProcessingComplete = ETrue;                                  
    } 
    else if (error != KErrNone)
    {
        User::Leave(error);        
    }      
    
    // save frame number
    iLastWrittenFrameNumber = iDelayedFrameNumber;
    
    delete iDelayedBuffer;
    iDelayedBuffer = 0;
    iDelayedWrite = EFalse;        
    
    PRINT((_L("CVideoProcessor::WriteDelayedFrameL() end")));   
    
}
            
TInt CVideoProcessor::SetVideoFrameSize(TSize /*aSize*/)
{

    PRINT((_L("CVideoProcessor::SetVideoFrameSize()")))    
    
    return KErrNone;
}
            
TInt CVideoProcessor::SetAverageVideoBitRate(TInt /*aBitRate*/)
{

    PRINT((_L("CVideoProcessor::SetAverageVideoBitRate()")))
    
    return KErrNone;
}
        
   
TInt CVideoProcessor::SetMaxVideoBitRate(TInt /*aBitRate*/)
{
    PRINT((_L("CVideoProcessor::SetMaxVideoBitRate()")))
    
    return KErrNone;
}
            
TInt CVideoProcessor::SetAverageAudioBitRate(TInt /*aBitRate*/)
{
    PRINT((_L("CVideoProcessor::SetAverageAudioBitRate()")))    
    
    return KErrNone;
}

// ---------------------------------------------------------
// CVideoProcessor::SetVideoCodecL()
// Interpret and store video mime type
// ---------------------------------------------------------
//
void CVideoProcessor::SetOutputVideoCodecL(const TPtrC8& aMimeType)
    {
    TBuf8<256> string;
    TBuf8<256> newMimeType;
    string = KVedMimeTypeH263;
    string += _L8( "*" );		

    iMaxOutputFrameRate = 15.0;
    iArbitrarySizeAllowed = EFalse;

    if ( aMimeType.MatchF( (const TDesC8& )string ) != KErrNotFound ) 
        {
        // H.263

        newMimeType = KVedMimeTypeH263;

        if ( aMimeType.MatchF( _L8("*profile*") ) != KErrNotFound )
            {
            // profile given, check if we support it
            if ( aMimeType.MatchF( _L8("*profile=0*")) != KErrNotFound )
                {
                // profile 0 requested
                newMimeType += _L8( "; profile=0" );
                }
            else
                {
                // no other profiles supported
                PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported profile")));
                User::Leave(KErrNotSupported);
                }
            }
        else
            {
            // no profile is given => assume 0
            newMimeType += _L8( "; profile=0" );
            }

        if ( aMimeType.MatchF( _L8("*level=10*") ) != KErrNotFound )
            {
    		iMaxOutputBitRate = iOutputBitRate = KVedBitRateH263Level10;
    		iMaxOutputResolution = KVedResolutionQCIF;
    		//dataBufferSize = KMaxCodedPictureSizeQCIF;
            newMimeType += _L8( "; level=10" );
            }
        else if ( aMimeType.MatchF( _L8("*level=45*") ) != KErrNotFound )
            {
    		iMaxOutputBitRate = iOutputBitRate = KVedBitRateH263Level45;
    		iMaxOutputResolution = KVedResolutionQCIF;
    		//dataBufferSize = KMaxCodedPictureSizeQCIF;
            newMimeType += _L8( "; level=45" );
            }
        else if ( aMimeType.MatchF( _L8("*level*") ) != KErrNotFound )
            {
            // no other levels supported
            PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported level")));
            User::Leave(KErrNotSupported);
            }
        else
            {
            // if no level is given assume 10
    		iMaxOutputBitRate = iOutputBitRate = KVedBitRateH263Level10;
    		iMaxOutputResolution = KVedResolutionQCIF;
    		//dataBufferSize = KMaxCodedPictureSizeQCIF;
            newMimeType += _L8( "; level=10" );
            }
        }
    else
        {
        string = KVedMimeTypeMPEG4Visual;
        string += _L8( "*" );

        if ( aMimeType.MatchF( string ) != KErrNotFound ) 
            {
            // MPEG-4 Visual
            newMimeType = KVedMimeTypeMPEG4Visual;
            if ( aMimeType.MatchF( _L8("*profile-level-id=8*") ) != KErrNotFound )
                {
                // simple profile level 0
        		iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level0;
        		iMaxOutputResolution = KVedResolutionQCIF;
                // define max size 10K
                //dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
                newMimeType += _L8("; profile-level-id=8");
                }
            else if ( aMimeType.MatchF( _L8("*profile-level-id=9*") ) != KErrNotFound )
                {
                // simple profile level 0b
        		iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level0;
        		iMaxOutputResolution = KVedResolutionQCIF;
                // define max size 10K
                //dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
                newMimeType += _L8("; profile-level-id=9");
                }
            else if ( aMimeType.MatchF( _L8("*profile-level-id=1*") ) != KErrNotFound )
                {
                // simple profile level 1
        		iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level0;
        		iMaxOutputResolution = KVedResolutionQCIF;
                // define max size 10K
                //dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
                iArbitrarySizeAllowed = ETrue;                
                newMimeType += _L8("; profile-level-id=1");
                }
            else if ( aMimeType.MatchF( _L8("*profile-level-id=2*") ) != KErrNotFound )
                {
                // simple profile level 2
			    //dataBufferSize = KMaxCodedPictureSizeMPEG4CIF;
        		iMaxOutputResolution = KVedResolutionCIF;
			    iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level2;
                iArbitrarySizeAllowed = ETrue;                
                newMimeType += _L8("; profile-level-id=2");
                }
            else if ( aMimeType.MatchF( _L8("*profile-level-id=3*") ) != KErrNotFound )
                {
                // simple profile level 3
			    //dataBufferSize = KMaxCodedPictureSizeMPEG4CIF;
			    iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level2;
        		iMaxOutputResolution = KVedResolutionCIF;
			    iMaxOutputFrameRate = 30.0;
                iArbitrarySizeAllowed = ETrue;                
                newMimeType += _L8("; profile-level-id=3");
                }
            else if ( aMimeType.MatchF( _L8("*profile-level-id=4*") ) != KErrNotFound )
                {
                // simple profile level 4a
			    iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level4A;	        	
			    //dataBufferSize = KMaxCodedPictureSizeVGA;
        		iMaxOutputResolution = KVedResolutionVGA;
			    iMaxOutputFrameRate = 30.0;
                iArbitrarySizeAllowed = ETrue;                
                newMimeType += _L8("; profile-level-id=4");
                }
            else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound )
                {
                // no other profile-level ids supported
                PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported MPEG-4 profile-level")));
                User::Leave(KErrNotSupported);
                }
            else
                {
                // Default is level 0 in our case (normally probably level 1)
        		iMaxOutputBitRate = iOutputBitRate = KVedBitRateMPEG4Level0;
        		iMaxOutputResolution = KVedResolutionQCIF;
                // define max size 10K
                //dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
                newMimeType += _L8("; profile-level-id=8");
                }
            }
                       
        else
            {
            
#ifdef VIDEOEDITORENGINE_AVC_EDITING
            string = KVedMimeTypeAVC;
            string += _L8( "*" );
            
            if ( aMimeType.MatchF( string ) != KErrNotFound ) 
                {
                // AVC
                newMimeType = KVedMimeTypeAVC;
                if ( aMimeType.MatchF( _L8("*profile-level-id=42800A*") ) != KErrNotFound )
                    {
                    // baseline profile level 1
            		iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel1;
            		iMaxOutputResolution = KVedResolutionQCIF;                    
                    newMimeType += _L8("; profile-level-id=42800A");
                    }                    
                else if ( aMimeType.MatchF( _L8("*profile-level-id=42900B*") ) != KErrNotFound )
                    {
                    // baseline profile level 1b
            		iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel1b;
            		iMaxOutputResolution = KVedResolutionQCIF;                    
                    newMimeType += _L8("; profile-level-id=42900B");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=42800B*") ) != KErrNotFound )
                    {
                    // baseline profile level 1.1
            		iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel1_1;
            		iMaxOutputResolution = KVedResolutionCIF;                    
                    newMimeType += _L8("; profile-level-id=42800B");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=42800C*") ) != KErrNotFound )
                    {
                    // baseline profile level 1.2
            		iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel1_2;
            		iMaxOutputResolution = KVedResolutionCIF;                    
                    newMimeType += _L8("; profile-level-id=42800C");
                    }
                //WVGA task
                else if ( aMimeType.MatchF( _L8("*profile-level-id=42801E*") ) != KErrNotFound )
                    {
                    // baseline profile level 3.0
                    iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel3;
                    iMaxOutputResolution = KVedResolutionWVGA;                    
                    newMimeType += _L8("; profile-level-id=42801E");
                    }
                
                else if ( aMimeType.MatchF( _L8("*profile-level-id=42801F*") ) != KErrNotFound )
                    {
                    // baseline profile level 3.1
            		iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel3_1;
            		iMaxOutputResolution = KVedResolutionWVGA;                    
                    newMimeType += _L8("; profile-level-id=42801F");
                    }        
                else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound )
                    {
                    // no other profile-level ids supported
                    PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported AVC profile-level")));
                    User::Leave(KErrNotSupported);
                    }
                else
                    {
                        // Default is level 1 (?)
            	 	    iMaxOutputBitRate = iOutputBitRate = KVedBitRateAVCLevel1;
            	 	    iMaxOutputResolution = KVedResolutionQCIF;
            		    newMimeType += _L8("; profile-level-id=42800A");
                    }                
                }

            else
                {
                // unknown mimetype
                User::Leave( KErrNotSupported );
                }
#else
           
               // unknown mimetype
               User::Leave( KErrNotSupported );
           
#endif
            }
        }

    // successfully interpreted the input mime type
    iOutputMimeType = newMimeType;
        
    /*if ( iDataBuffer )
        {
        delete iDataBuffer;
        iDataBuffer = NULL;
        }
	iDataBuffer = (HBufC8*) HBufC8::NewL(dataBufferSize);    */
	
    }
    
// ---------------------------------------------------------
// CVideoProcessor::GetVosHeaderSize()
// Gets the size of MPEG-4 VOS header (from encoder)
// ---------------------------------------------------------
//
TInt CVideoProcessor::GetVosHeaderSize()
{
    VDASSERT(iOutputVolHeader, 190);
    
    return iOutputVolHeader->Length();
}
    
// ---------------------------------------------------------
// CCallbackTimer::NewL()
// Two-phased constructor
// ---------------------------------------------------------
//
CCallbackTimer* CCallbackTimer::NewL(MTimerObserver& aObserver)
{
 
    CCallbackTimer* self = new (ELeave) CCallbackTimer(aObserver);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    
    return self;    
}

// ---------------------------------------------------------
// CCallbackTimer::CCallbackTimer()
// C++ default constructor.
// ---------------------------------------------------------
//
CCallbackTimer::CCallbackTimer(MTimerObserver& aObserver)  :
    CActive(EPriorityStandard), iObserver(aObserver)
    
{
}

// ---------------------------------------------------------
// CCallbackTimer::~CCallbackTimer()
// Destructor
// ---------------------------------------------------------
//
CCallbackTimer::~CCallbackTimer()
{ 
    Cancel();
       
    if ( iTimerCreated )
	{
        iTimer.Close();
		iTimerCreated = EFalse;
	}
}

// ---------------------------------------------------------
// CCallbackTimer::ConstructL()
// Symbian 2nd phase constructor 
// ---------------------------------------------------------
//
void CCallbackTimer::ConstructL()
{
  	// Create a timer 
	User::LeaveIfError(iTimer.CreateLocal());
	iTimerCreated = ETrue;
	
	// Add us to active scheduler
	CActiveScheduler::Add(this);	
}

// ---------------------------------------------------------
// CCallbackTimer::SetTimer()
// Set timer
// ---------------------------------------------------------
//
void CCallbackTimer::SetTimer(TTimeIntervalMicroSeconds32 aDuration)
{

//    __ASSERT_DEBUG(!iTimerRequestPending != 0, -5000); //CSI: #174-D: expression has no effect, just an assert debug no effect intended    
//    __ASSERT_DEBUG(iTimerCreated, -5001);
    
    PRINT((_L("CCallbackTimer::SetTimer()")))
    
    // activate timer to wait for encoding
    SetActive();
    iStatus = KRequestPending;        
    iTimer.After(iStatus, aDuration);
    iTimerRequestPending = ETrue;        
    
}

// ---------------------------------------------------------
// CCallbackTimer::CancelTimer()
// Cancel timer
// ---------------------------------------------------------
//
void CCallbackTimer::CancelTimer()
{ 
     PRINT((_L("CCallbackTimer::CancelTimer()")))
     Cancel();
}

// ---------------------------------------------------------
// CCallbackTimer::RunL()
// AO running method
// ---------------------------------------------------------
//
void CCallbackTimer::RunL()
{
    if ( iTimerRequestPending )
    {
        iTimerRequestPending = EFalse;
        
        // call observer
        iObserver.MtoTimerElapsed(KErrNone);                
    }
}

// ---------------------------------------------------------
// CCallbackTimer::DoCancel()
// AO cancelling method 
// ---------------------------------------------------------
//
void CCallbackTimer::DoCancel()
{

    // Cancel our timer request if we have one
    if ( iTimerRequestPending )
    {
        iTimer.Cancel();
        iTimerRequestPending = EFalse;
        return;
    }
    
}

// ---------------------------------------------------------
// CCallbackTimer::RunError()
// AO RunL error method
// ---------------------------------------------------------
//
TInt CCallbackTimer::RunError(TInt aError)
{
    Cancel();
    
    // call observer
    iObserver.MtoTimerElapsed(aError);

    return KErrNone;
}


// End of File