camcordermmfplugin/mediarecorder/Src/CCMRMDFVideoRecorder.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 00:20:52 +0200
changeset 2 c7e61a0077eb
parent 1 2d3e1993fb02
child 8 6bc4220d7f67
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2002-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Implementation for video recorder
*
*/


// INCLUDE FILES
#include "mmf/common/mmfbase.h"
#include "CCMRRecorderBase.h"
#include "CCMRVideoSettings.h"      // default video settings
#include "CCMRSupportedCodecs.h"
#include "CCMRVideoHWParams.h"
#include "CCMRVideoRecorder.h"
#include "CCMRMediaRecorder.h"      // for bitrate control mode
#include "CCMRVideoThreadProxy.h"
#include "CCMRFifo.h"
#include "CCMRActiveOutput.h"
#include "CCMRVideoCodecDataH263.h"
#include "CCMRVideoCodecDataMPEG4.h"
#include "CCMRVideoCodecDataH264AVC.h"
#include <mmf/common/mmfvideo.h>

/*
#include "OstTraceDefinitions.h"
#ifdef OST_TRACE_COMPILER_IN_USE
#include "CCMRMDFVideoRecorderTraces.h"
#endif
*/

// MACROS
// Assertion macro wrapper for code cleanup
#define VRASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CCMRMDFVIDEORECORDER"), EInternalAssertionFailure))

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

// ============================= LOCAL FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// convertFrameRateToInterval Converts framerate to frame time interval
// (time between 2 consecutive frames).
// Returns: TInt time between 2 consecutive frames
// -----------------------------------------------------------------------------
//
static TInt convertFrameRateToInterval(TReal32 aFrameRate)
    {
    return (TInt(1E6/aFrameRate + 0.5));
    }


// -----------------------------------------------------------------------------
// convertFrameRateToInterval Converts framerate to frame time interval
// (time between 2 consecutive frames).
// Returns: TInt time between 2 consecutive frames
// -----------------------------------------------------------------------------
//
static TInt TLinearOrderFuncVideoSizeRate(const TPictureRateAndSize& aPictureRateAndSize1,
										  const TPictureRateAndSize& aPictureRateAndSize2 )
	{
	if ( (aPictureRateAndSize1.iPictureSize.iWidth == aPictureRateAndSize2.iPictureSize.iWidth) &&
		 (aPictureRateAndSize1.iPictureSize.iHeight == aPictureRateAndSize2.iPictureSize.iHeight) &&
		 (aPictureRateAndSize1.iPictureRate == aPictureRateAndSize2.iPictureRate) )
		{
		return 0;
		}

	if ( (aPictureRateAndSize1.iPictureSize.iWidth < aPictureRateAndSize2.iPictureSize.iWidth) ||
		 (aPictureRateAndSize1.iPictureSize.iHeight < aPictureRateAndSize2.iPictureSize.iHeight) ||
		 (aPictureRateAndSize1.iPictureRate < aPictureRateAndSize2.iPictureRate))
		{
		return -1;
		}
	else
		{
		return 1;
		}
	}

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

// ---------------------------------------------------------
// CCMRVideoRecorder::NewL
// Two-phased constructor.
// ---------------------------------------------------------
//
CCMRVideoRecorder* CCMRVideoRecorder::NewL(MAsyncEventHandler& aEventHandler, CCMRConfigManager* aConfig )
    {
    PRINT((_L("CCMRVideoRecorder::NewL(), In: MDF")))

    CCMRVideoRecorder* self = new (ELeave) CCMRVideoRecorder(aEventHandler);
    CleanupStack::PushL( self );
    self->ConstructL(aConfig);
    CleanupStack::Pop();

    PRINT((_L("CCMRVideoRecorder::NewL(), Out: MDF")))
    return self;
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::ConstructL()
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------
//
void CCMRVideoRecorder::ConstructL(CCMRConfigManager* aConfig)
    {
    PRINT((_L("CCMRVideoRecorder::ConstructL(), In")))

    SetState(EStateNone);

    iConfig = aConfig;
    iNumCameraBuffers = iConfig->PluginSettings().iCMRNumCameraBuffers;
    // Create input fifo
    iSourceFifo = CCMRFifo::NewL(iNumCameraBuffers);
    iCodingFifo = CCMRFifo::NewL(iNumCameraBuffers);

    iOutputSinkBuffer = new (ELeave) CCMRMediaBuffer;

    iSizeIndex = -1;
    iSizeIndex420 = -1;
    iSizeIndex422 = -1;
    iSizeIndexDCEncoder = -1;
    iRateIndex = -1;
    iRateIndex420 = -1;
    iRateIndex422 = -1;
    iRateIndexDCEncoder = -1;
    iDevVideoRec = NULL;
    iEncoderHWDeviceId = 0;
    iPreProcessorHWDeviceId = 0;
    iOutputVideoBuffer = NULL;
    iVideoBufferType = CCMRMediaBuffer::EVideoH263;
    iClockSource = NULL;
    iDecSpecInfoLength = 0;
    iPreferredEncoderUID = KNullUid;
    iPreferredEncapsulationSet = EFalse;
    iFrameSize.SetSize( KCMRFrameWidth, KCMRFrameHeight );
    iSourceFrameRate = KCMRFrameRate;
    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
    iEncodingFrameRate = KCMRFrameRate;
    iMaxFrameRate4GivenSize = KCMRFrameRate;
    iRequestedFrameRate = KCMRFrameRate;
    CCMRRecorderBase::SetTargetBitRateL( KCMRTargetBitRate );

    iMinRandomAccessPeriodInSeconds = KCMRMinRandomAccessPeriod;

    iMimeType = KCMRMimeTypeH263BaselineProfile;    //copy
    iMimeType += _L8( "; level=10" );    // append
    iVideoCodecData = new (ELeave) CCMRVideoCodecDataH263(10);    // default is H.263 level 10

    iBitRateMode = EBitRateConstant;

    iTimeWhenPaused = 0;
    iTotalPausedTime = 0;

    iErrorCode = KErrNone;

    iEncoderInputQueueLength = 0;

    iNumberOfCapturedFrames = 0;
    iNumberOfEncodedFrames = 0;

    iMutexObj.CreateLocal();
    iMutexCreated = ETrue;
    iBufferReturnAO = CCMRReturnAO::NewL(this);

    iFatalError = EFalse;
    iInputEnd = EFalse;
    iStreamEnd = EFalse;

    // Direct capture
    iDirectCapture = EFalse;
    iCameraHandle = 0;
    iSkipBuffers = EFalse;
    iDriftFrameSkipCount = 0;
    iAddedFrameDurationCount = 0;
    iPreviousCameraFrameIndex = 0;

#ifdef _DEBUG
    iLastCapture = 0;
    iCumulativeEncodingTime = iCumulativeCaptureTime = 0;
    iAverageEncodingTime = iAverageCaptureTime = 0;
#endif
	iDevVideoRec = CMMFDevVideoRecord::NewL( *this );
	iAvailableVideoEncoders.Reset();
	iAvailableVideoFrameSizesRates.Reset();

	PRINT((_L("CCMRVideoRecorder::ConstructL() looking for defaul video codec encoder(s)")));
	iDevVideoRec->FindEncodersL(iMimeType, 0 /* aPreProc */, iAvailableVideoEncoders, EFalse );
	PRINT((_L("CCMRVideoRecorder::ConstructL() search found %d encoder(s)"), iAvailableVideoEncoders.Count() ));

	if ( iConfig )
		{
		iConfig->SetVideoCodec(iMimeType);
		iConfig->SetVideoPixelAspectRatio(KCMRAspectRatioNum, KCMRAspectRatioDenom);

		// fill out defaults for Rate Control from ICM.
	    iRateControlOptions.iPictureQuality = iConfig->PluginSettings().iCMRPictureQuality;
	    iRateControlOptions.iLatencyQualityTradeoff = iConfig->PluginSettings().iCMRLatencyQualityTradeoff; // latency vs. quality
	    iRateControlOptions.iQualityTemporalTradeoff = iConfig->PluginSettings().iCMRQualityTemporalTradeoff; // spatial vs. temporal quality
		}
    UpdateSupportedVideoFrameSizesRates();
    PRINT((_L("CCMRVideoRecorder::ConstructL(), Out")))
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::~CCMRVideoRecorder()
// Destructor
// ---------------------------------------------------------
//
CCMRVideoRecorder::~CCMRVideoRecorder()
    {
    PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder(), In")));
    // This is the counterpart to NewL & OpenL, e.g. Close & Delete
    // free all memory allocated and uninitalize & delete objects created, e.g. DevVideoRecord

#if defined VIDEO_FILE_OUTPUT || defined VIDEO_BS_FILE_OUTPUT
    iOutputFile.Close();
    iFs.Close();
#endif

    // to make PC Lint happy
    iOutputVideoBuffer = NULL;
    iOutput = NULL;
    iClockSource = NULL;

    // delete DevVideoRecord instance
    delete iDevVideoRec;
    PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() devvideorec deleted")));

    iAvailableVideoFrameSizesRates.Close();
    iAvailableVideoEncoders.Close();

    delete iOutputSinkBuffer;
    iOutputSinkBuffer = NULL;

    delete iVideoCodecData;
    iVideoCodecData = NULL;

    // empty the source fifo, just in case once more; this should be done a) by encoder and b) by MdvroStreamEnd()
    MFrameBuffer* cbuffer;
    if ( iSourceFifo )
        {
        while ( !iSourceFifo->IsEmpty() )
            {
            cbuffer = reinterpret_cast<MFrameBuffer*>(iSourceFifo->Get());
            // Release camera API buffer
            cbuffer->Release();
            }
        delete iSourceFifo;
        iSourceFifo = NULL;
        }
    TVideoPicture* picture;
    if ( iCodingFifo )
        {
        // delete the empty devvr picture-holders stored in the fifo
        while ( !iCodingFifo->IsEmpty() )
            {
            picture = reinterpret_cast<TVideoPicture*>(iCodingFifo->Get());
            PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() deleting %x"),picture));
            delete picture;
            }
        delete iCodingFifo;
        iCodingFifo = NULL;
        }
    PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() fifos deleted")));

    if ( iDecSpecInfo )
        {
        // We still have MPEG-4 decoder configuration info stored
        delete iDecSpecInfo;
        iDecSpecInfo = NULL;
        }

    // delete camera
    delete iSource;
    iSource = NULL;
    PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder() camera deleted")));

    if ( iBufferReturnAO )
        {
        iBufferReturnAO->Cancel();
        delete iBufferReturnAO;
        }

    if ( iThreadHandleOpened )
        {
        iOutputThreadHandle.Close();
        iThreadHandleOpened = EFalse;
        }

    if ( iMutexCreated )
        {
        iMutexObj.Close();
        }

    SetState(EStateNone);

    PRINT((_L("CCMRVideoRecorder::~CCMRVideoRecorder(), Out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetOutputL
// Sets output active object
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetOutputL(CCMRActiveOutput* aOutput)
    {
    iOutput = aOutput;
    iOutput->RegisterSourceL( this );
    if ( iSource && iThreadHandleOpened )
        {
        SetState( EStateOpen );
        }
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::SetClockSourceL
// Set clock source
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetClockSource(MMMFClockSource* aClockSource)
    {
    iClockSource = aClockSource;
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::SetOutputThreadIdL
// Sets id of the output thread
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetOutputThreadIdL(TUint aThreadId)
    {
    User::LeaveIfError( iOutputThreadHandle.Open(aThreadId) );

    iThreadHandleOpened = ETrue;
    if ( iOutput && iSource )
        {
        SetState( EStateOpen );
        }
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetCameraHandleL
// Sets camera handle and creates camera instance
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetCameraHandleL(TInt aCameraHandle)
    {
    PRINT((_L("CCMRVideoRecorder::SetCameraHandleL(), In")))

    // Create video source
#ifdef VIDEO_FILE_INPUT
    iSource = CCMRVideoFileSource::NewL(this);
#else
    iSource = CCMRVideoCameraSource::NewL(this, aCameraHandle);
#endif

    // Store a camera handle for future use
    iCameraHandle = aCameraHandle;

    // get camera info
    iSource->CameraInfo(iCameraInfo);

#if defined VIDEO_FILE_OUTPUT || defined VIDEO_BS_FILE_OUTPUT
    User::LeaveIfError(iFs.Connect());
    User::LeaveIfError(iOutputFile.Replace(iFs, _L("videorec_out.bin"), EFileWrite | EFileShareExclusive));
#endif

    if ( iOutput && iThreadHandleOpened )
        {
        SetState( EStateOpen );
        }

    PRINT((_L("CCMRVideoRecorder::SetCameraHandleL(), Out")))
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::SetupEncoderL
// Private helper method to select & setup the encoder
// plugin devvr must use
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetupEncoderL()
    {
#ifdef _DEBUG
    TBuf<256> mime;
    mime.Copy(iMimeType);
    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() in, video mime-type: %S "), &mime ));
#endif

    if ( iPreferredEncoderUID != KNullUid )
        {// We have preferred encoder UID from client - override encoder search and use it instead.
        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using API user encoder: %d "), iPreferredEncoderUID.iUid));
        iAvailableVideoEncoders.Reset();
        iAvailableVideoEncoders.AppendL(iPreferredEncoderUID);
        }
    else if ( iConfig &&
            ( iConfig->IsICMConfigDataAvailable() ) &&
            ( iConfig->VideoQualitySettings().iVideoEncoderUID != KNullUid ) )
        {// Video quality set has set UID value - override encoder search and use it instead.
        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using ICM config encoder: %d "), iPreferredEncoderUID.iUid));
        iAvailableVideoEncoders.Reset();
        iAvailableVideoEncoders.AppendL(iPreferredEncoderUID);
        }

    // uncompressed format structures for YUV420 planar
    TBool cameraSupports420 = ETrue;

    if ( (iSizeIndex420 < 0) || (iRateIndex420 < 0) )
        {
        cameraSupports420 = EFalse;
        }
    else
        {
        cameraSupports420 = ETrue;
        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() camera supports YUV420 planar") ));
        }

    // uncompressed format structures for YUV422
    TBool cameraSupports422 = ETrue;
    if ( (iSizeIndex422 < 0) || (iRateIndex422 < 0) )
        {
        cameraSupports422 = EFalse;
        }
    else
        {
        cameraSupports422 = ETrue;
        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() camera supports YUV422 interleaved") ));
        }

    // Output format
    CCompressedVideoFormat *comprFormat = CCompressedVideoFormat::NewL( iMimeType );
    CleanupStack::PushL( comprFormat );

    // index for encoder candidate. Have to go through the list to find an accerated encoder
    TInt encoderIndex = -1;
    TUncompressedVideoFormat encoderUncompFormat;

    // encoder info for retrieving capabilities
    CVideoEncoderInfo* encoderInfo = NULL;

    // this is needed if init of HW accelerated codec failed and we retry => forces to select ARM codec
    TBool alreadyFailedWithHWAccelerated = iVideoCodecHWAccelerated;
    iVideoCodecHWAccelerated = EFalse;

    TInt infoError = KErrNone;
    TBool encoderSupports422 = EFalse;
    TBool encoderSupports420 = EFalse;

    TYuvCoefficients preproInputYuvCoefficient;
    TYuvCoefficients preproOutputYuvCoefficient;
    TYuvCoefficients encoderInputYuvCoefficient;
    TUint aspectRatioNum = 0;
    TUint aspectRatioDenom = 0;
    TVideoDataUnitEncapsulation outputFormatEncapsulation = EDuElementaryStream;

    if( KCMRMimeTypeH263() == iMimeType.Left( KCMRMimeTypeH263().Length() ))
        {// H.263
        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - setting H.263 YUVs") ));
        preproInputYuvCoefficient = EYuvBt601Range1;
        preproOutputYuvCoefficient = EYuvBt601Range0;
        encoderInputYuvCoefficient = EYuvBt601Range0;
        iVideoBufferType = CCMRMediaBuffer::EVideoH263;
        // pixel aspect ratios
        if ( iConfig && iConfig->IsICMConfigDataAvailable() )
	        {
	        aspectRatioNum = iConfig->VideoQualitySettings().iVideoPixelAspectRatioNum;
	        aspectRatioDenom = iConfig->VideoQualitySettings().iVideoPixelAspectRatioDenom;
	        }
        else
	        {
	        aspectRatioNum = KCMRAspectRatioNum;
	        aspectRatioDenom = KCMRAspectRatioDenom;
	        }
        }
    else if ( KCMRMimeTypeMPEG4V() == iMimeType.Left( KCMRMimeTypeMPEG4V().Length() ))
        {// MPEG-4
        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - setting MPEG4 YUVs") ));
        preproInputYuvCoefficient = EYuvBt709Range1;
        preproOutputYuvCoefficient = EYuvBt709Range1;
        encoderInputYuvCoefficient = EYuvBt709Range1;
        // pixel aspect ratios
        if ( iConfig && iConfig->IsICMConfigDataAvailable() )
	        {
	        aspectRatioNum = iConfig->VideoQualitySettings().iVideoPixelAspectRatioNum;
	        aspectRatioDenom = iConfig->VideoQualitySettings().iVideoPixelAspectRatioDenom;
	        }
        else
	        {
	        aspectRatioNum = KCMRMPEG4AspectRatioNum;
	        aspectRatioDenom = KCMRMPEG4AspectRatioDenom;
	        }
        iVideoBufferType = CCMRMediaBuffer::EVideoMPEG4;
        }
    else
        {// H.264 AVC
        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - setting H.264 AVC YUVs") ));
        preproInputYuvCoefficient = EYuvBt709Range1;
        preproOutputYuvCoefficient = EYuvBt709Range1;
        encoderInputYuvCoefficient = EYuvBt709Range1;
        // pixel aspect ratios 1:1
        if ( iConfig && iConfig->IsICMConfigDataAvailable() )
	        {
	        aspectRatioNum = iConfig->VideoQualitySettings().iVideoPixelAspectRatioNum;
	        aspectRatioDenom = iConfig->VideoQualitySettings().iVideoPixelAspectRatioDenom;
	        }
        else
	        {
	        aspectRatioNum = KCMRMPEG4AspectRatioNum;
	        aspectRatioDenom = KCMRMPEG4AspectRatioDenom;
	        }
        // output format encapsulation
        iVideoBufferType = CCMRMediaBuffer::EVideoH264NAL;
        outputFormatEncapsulation = EDuGenericPayload;
        }

    TBool directCaptureEncoder = EFalse;
    TInt supportedEncoderInputsCount = 0;
    // find an encoder with matching capabilities
    for ( TInt i = 0 ; i < iAvailableVideoEncoders.Count(); i++ )
        {
        encoderInfo = NULL;
        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - getting info from a plugin index[%d] with Uid 0x%x"), i, iAvailableVideoEncoders[i].iUid ));
        TRAPD(error, (encoderInfo = ReadEncoderInfoL(iAvailableVideoEncoders[i])) );

        if ( encoderInfo == NULL )
            {
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - getting info from a plugin failed, skipping") ));
            infoError = error;
            }
        else
            {
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - got an info from a plugin, checking...") ));

            // item was popped in CheckEncoderInfoL, push it back to stack
            CleanupStack::PushL( encoderInfo );

            // check if compressed video format matches
            if ( encoderInfo->SupportsOutputFormat(*comprFormat) )   // max picture size & bit-rate was checked in the level of comprFormat
                {
                // check input format of encoder.
                // a candidate encoder supporting the required compressed format was found
                encoderSupports422 = EFalse;
                encoderSupports420 = EFalse;

                RArray<TUncompressedVideoFormat> supportedEncoderInputs = encoderInfo->SupportedInputFormats();
                supportedEncoderInputsCount = supportedEncoderInputs.Count();
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports %d input format(s), checking for support"), i, supportedEncoderInputs.Count() ));

                // Go through supported input format and look for match to important parameters.
                for(TInt j = 0; j < supportedEncoderInputsCount; j++ )
                    {
                    if ( !encoderSupports422 &&
                         cameraSupports422 &&
                         supportedEncoderInputs[j].iDataFormat == EYuvRawData &&
                         supportedEncoderInputs[j].iYuvFormat.iCoefficients == encoderInputYuvCoefficient &&
                         ( supportedEncoderInputs[j].iYuvFormat.iDataLayout == EYuvDataInterleavedLE ||
                           supportedEncoderInputs[j].iYuvFormat.iDataLayout == EYuvDataInterleavedBE ) &&
                         supportedEncoderInputs[j].iYuvFormat.iYuv2RgbMatrix == NULL &&
                         supportedEncoderInputs[j].iYuvFormat.iRgb2YuvMatrix == NULL &&
                         supportedEncoderInputs[j].iYuvFormat.iAspectRatioNum ==  aspectRatioNum &&
                         supportedEncoderInputs[j].iYuvFormat.iAspectRatioDenom ==  aspectRatioDenom &&
                         ( supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv422Chroma1 ||
                         supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv422Chroma2 ) )
                        {
                        // YUV 422 input format can be used with this encoder
                        encoderSupports422 = ETrue;
                        encoderUncompFormat = supportedEncoderInputs[j];
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports YUV422 interleaved"), i ));
                        break;
                        }
                    if ( !encoderSupports420 &&
                         !encoderSupports422 &&
                         cameraSupports420 &&
                         supportedEncoderInputs[j].iDataFormat == EYuvRawData &&
                         supportedEncoderInputs[j].iYuvFormat.iCoefficients == encoderInputYuvCoefficient &&
                         supportedEncoderInputs[j].iYuvFormat.iDataLayout == EYuvDataPlanar &&
                         supportedEncoderInputs[j].iYuvFormat.iYuv2RgbMatrix == NULL &&
                         supportedEncoderInputs[j].iYuvFormat.iRgb2YuvMatrix == NULL &&
                         supportedEncoderInputs[j].iYuvFormat.iAspectRatioNum ==  aspectRatioNum &&
                         supportedEncoderInputs[j].iYuvFormat.iAspectRatioDenom ==  aspectRatioDenom &&
                         ( supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv420Chroma1 ||
                           supportedEncoderInputs[j].iYuvFormat.iPattern == EYuv420Chroma2 ) )
                        {
                        // YUV 420 planar input format can be used with this encoder
                        encoderSupports420 = ETrue;
                        encoderUncompFormat = supportedEncoderInputs[j];
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports YUV420 planar"), i ));
                        if( !cameraSupports422 )
                            {
                            break;
                            }
                        }
                    }
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports: 420[%d], 422[%d]"), i, encoderSupports420, encoderSupports422 ));

                // Check directCapture support for current codec
                directCaptureEncoder = encoderInfo->SupportsDirectCapture();
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Encoder at index[%d] supports DirectCapture:[%d]."), i, directCaptureEncoder));

                // determine H.264 AVC encapsulation
                if ( (iVideoBufferType == CCMRMediaBuffer::EVideoH264NAL) ||
                     (iVideoBufferType == CCMRMediaBuffer::EVideoH264Bytestream) )
                    {
                    if (( iPreferredEncapsulationSet ) &&
                        ( encoderInfo->SupportedDataUnitEncapsulations() & iPreferredEncapsulation ))
                        {
                        outputFormatEncapsulation = iPreferredEncapsulation;
                        }
                    else
                        {
                        if (encoderInfo->SupportedDataUnitEncapsulations() & EDuGenericPayload)
                            {
                            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() H.264 Encoder at index[%d] set to EDuGenericPayload encapsulation."), i));
                            outputFormatEncapsulation = EDuGenericPayload;
                            }
                        else
                            {
                            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() H.264 Encoder at index[%d] set to EDuElementaryStream encapsulation."), i));
                            outputFormatEncapsulation = EDuElementaryStream;
                            }
                        }

                    if ( outputFormatEncapsulation == EDuGenericPayload )
                        {
                        iVideoBufferType = CCMRMediaBuffer::EVideoH264NAL;
                        }
                    else
                        {
                        iVideoBufferType = CCMRMediaBuffer::EVideoH264Bytestream;
                        }
                    }

                if (directCaptureEncoder && (supportedEncoderInputsCount != 0))
                    {
                    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Warning - Encoder at index[%d] publish input formats even though it supports directcapture - ERROR!."), i));
                    }

                if ( encoderSupports422 || encoderSupports420 || (directCaptureEncoder && (supportedEncoderInputsCount == 0)) )
                    {
                    // encoder's input format matches with camera's output
                    if ( encoderInfo->Accelerated() && (alreadyFailedWithHWAccelerated == EFalse) )
                        // assume there is only 1 HW accelerated codec, and if it was selected previously we come here only if the init failed
                        // => must use non-hw-accelerated codec
                        {
                        // no need to search for more, accelerated encoder is preferred
                        encoderIndex = i;
                        iVideoCodecHWAccelerated = ETrue;
                        iDirectCapture = directCaptureEncoder;
                        // HW accelerated is preferred regardless of the input format, but if both formats are supported, then 422 is preferred
                        // need to set the camera variables accordingly
                        if ( !(directCaptureEncoder && (supportedEncoderInputsCount == 0)) )
                            {
                            if ( encoderSupports422 )
                                {
                                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV422 interleaved selected as input format") ));
                                iSizeIndex = iSizeIndex422;
                                iRateIndex = iRateIndex422;
                                iVideoFormat = CCamera::EFormatYUV422;
                                }
                            else if (encoderSupports420)
                                {
                                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV420 planar selected as input format") ));
                                iSizeIndex = iSizeIndex420;
                                iRateIndex = iRateIndex420;
                                iVideoFormat = CCamera::EFormatYUV420Planar;
                                }
                            }
                        // check max framerate for given picture size
                        RArray<TPictureRateAndSize> rateAndSize = encoderInfo->MaxPictureRates();
                        TUint rates = rateAndSize.Count();
                        for ( TUint j = 0; j < rates; j++ )
                            {
                            if ( rateAndSize[j].iPictureSize == iFrameSize )
                                {
                                iMaxFrameRate4GivenSize = rateAndSize[j].iPictureRate;
                                break;
                                }
                            }
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - there is a suitable HW accelerated plugin, don't check other plugins") ));
                        CleanupStack::PopAndDestroy( encoderInfo );
                        break;
                        }
                    else if ( encoderIndex < 0 )
                        {
                        // accept also non-accelerated if no other is available
                        encoderIndex = i;
                        // encoder is selected regardless of the input format, but if both formats are supported, then 422 is preferred
                        // need to set the camera variables accordingly
                        if ( !(directCaptureEncoder && (supportedEncoderInputsCount == 0)) )
                            {
                            if ( encoderSupports422 )
                                {
                                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV422 interleaved selected as input format") ));
                                iSizeIndex = iSizeIndex422;
                                iRateIndex = iRateIndex422;
                                iVideoFormat = CCamera::EFormatYUV422;
                                }
                            else if (encoderSupports420)
                                {
                                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() YUV420 planar selected as input format") ));
                                iSizeIndex = iSizeIndex420;
                                iRateIndex = iRateIndex420;
                                iVideoFormat = CCamera::EFormatYUV420Planar;
                                }
                            }

                        // check max framerate for given picture size
                        RArray<TPictureRateAndSize> rateAndSize = encoderInfo->MaxPictureRates();
                        TUint rates = rateAndSize.Count();

                        for ( TUint j = 0; j < rates; j++ )
                            {
                            if ( rateAndSize[j].iPictureSize == iFrameSize )
                                {
                                iMaxFrameRate4GivenSize = rateAndSize[j].iPictureRate;
                                break;
                                }
                            }
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - there is a suitable SW plugin.") ));
                        }
                    else
                        {
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - there is already similar encoder - preferring first.") ));
                        // this kind of encoder already found
                        }

                    }
                else
                    {
                    // skip this encoder, done in the following lines
                    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() encoder doesn't support YUV420/YUV422 input format or isn't directcapture encoder") ));
                    }
                }
            else
                {
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() encoder at index[%d] doesn't support given compressed output format"), i ));
                }
            CleanupStack::PopAndDestroy( encoderInfo );
            }
        }

    TUncompressedVideoFormat preproInputFormat = encoderUncompFormat;
    TUncompressedVideoFormat preproOutputFormat = encoderUncompFormat;
    preproInputFormat.iYuvFormat.iCoefficients = preproInputYuvCoefficient;
    preproOutputFormat.iYuvFormat.iCoefficients = preproOutputYuvCoefficient;

    if ( encoderIndex >= 0 )
        {
        if ( iVideoCodecHWAccelerated )
            {
            iNumCameraBuffers = iConfig->PluginSettings().iCMRNumCameraBuffers;
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - found a suitable HW accelerated video encoder")));
            }
        else
            {
            iNumCameraBuffers = iConfig->PluginSettings().iCMRNumCameraBuffersARM;
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() - found a suitable ARM video encoder")));
            }

        // if encoder doesn´t support directcapture try to find preprocessor that does.
        if ( !iDirectCapture && iVideoCodecHWAccelerated )
            {
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Searching preprocessor.")));
            RArray<TUid> preprocessors;
            CleanupClosePushL( preprocessors );
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Search starting")));

            TInt preproSearchErr = KErrNone;
            TRAP(preproSearchErr, iDevVideoRec->FindPreProcessorsL(EPpYuvToYuv, preprocessors));
            if (preproSearchErr == KErrNone)
                {
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Search found %d preprocessor(s)"), preprocessors.Count() ));
                CPreProcessorInfo* preprocessorInfo = NULL;
                // find a preprocessor with matching capabilities to encoder
                for ( TInt k = 0; k < preprocessors.Count(); k++ )
                    {
                    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Checking preprocessor at index[%d] with Uid 0x%x"), k, preprocessors[k].iUid ));
                    preprocessorInfo = iDevVideoRec->PreProcessorInfoLC(preprocessors[k]);

                    if ( preprocessorInfo->SupportsInputFormat(preproInputFormat) &&
                         preprocessorInfo->SupportsOutputFormat(preproOutputFormat) &&
                         preprocessorInfo->SupportsDirectCapture() )
                        {
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() preprocessor[%d] is suitable, setting it as preprocessor"), k ));
                        iDirectCapture = ETrue;
                        iPreProcessorHWDeviceId = iDevVideoRec->SelectPreProcessorL(preprocessors[k]);
                        PRINT((_L("CCMRVideoRecorder::SetupEncoderL() preprocessor selected")));
                        CleanupStack::PopAndDestroy(preprocessorInfo);
                        break;
                        }
                    CleanupStack::PopAndDestroy(preprocessorInfo);
                    }
                }
            else if (preproSearchErr == KErrNotFound)
                {
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() didn't find any preprocessors")));
                }
            else
                {
                PRINT((_L("CCMRVideoRecorder::SetupEncoderL() preprocessors search error: %d"), preproSearchErr));
                CleanupStack::PopAndDestroy(); //preprocessors
                User::Leave(preproSearchErr);
                }
            CleanupStack::PopAndDestroy(); //preprocessors
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Searching preprocessor done.")));
            }
        }
    else
        {
        if ( infoError != KErrNone )
            {
            // there is an encoder but it can't be used
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() there is an encoder but it can't be used - info error=%d"), infoError ));
            User::Leave( infoError );
            }
        else
            {
            // No suitable encoder found. This should not be possible if the codec was properly set beforehand
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() No suitable encoder found.")));
            User::Leave( KErrNotSupported );
            }
        }

    iEncoderHWDeviceId = iDevVideoRec->SelectEncoderL(iAvailableVideoEncoders[encoderIndex]);
    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() encoder selected")));

    // Set input format only for non-directcapture encoders
    if ( (directCaptureEncoder && (supportedEncoderInputsCount == 0)) )
        {
        // Direct capture encoders should ignore
        TUncompressedVideoFormat ignoredFormat;
        iDevVideoRec->SetInputFormatL(iEncoderHWDeviceId, ignoredFormat, iFrameSize);
        }
    else
        {
        iDevVideoRec->SetInputFormatL(iEncoderHWDeviceId, encoderUncompFormat, iFrameSize);
        }

    if ( iPreProcessorHWDeviceId )
        {
        iDevVideoRec->SetInputFormatL(iPreProcessorHWDeviceId, preproInputFormat, iFrameSize);
        }

    // Buffer options
    TEncoderBufferOptions bufferOptions;
    bufferOptions.iHrdVbvParams.Set(NULL, 0);
    bufferOptions.iHrdVbvSpec = EHrdVbvNone;
    bufferOptions.iMaxPreEncoderBufferPictures = iConfig->PluginSettings().iCMRNumCameraBuffers;
    bufferOptions.iMinNumOutputBuffers = iConfig->PluginSettings().iCMRMinNumOutputBuffers;

    bufferOptions.iMaxCodedSegmentSize =
        bufferOptions.iMaxOutputBufferSize =
        bufferOptions.iMaxCodedPictureSize = iVideoCodecData->MaxBufferLength(iFrameSize);

    iDevVideoRec->SetBufferOptionsL(bufferOptions);

    // Set output format
    iDevVideoRec->SetOutputFormatL(iEncoderHWDeviceId, *comprFormat, EDuCodedPicture,
                                   outputFormatEncapsulation, EFalse /* aSegmentationAllowed */);

    if( iPreProcessorHWDeviceId)
    {
        iDevVideoRec->SetOutputFormatL(iPreProcessorHWDeviceId, preproOutputFormat);
    }

    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() MinRandomAccess= %d"), iMinRandomAccessPeriodInSeconds ));
    if ( iConfig && iConfig->IsICMConfigDataAvailable() )
        {
        iMinRandomAccessPeriodInSeconds = iConfig->VideoQualitySettings().iRandomAccessRate;
        }
    else
        {
        if ( (iFrameSize.iWidth >= KCMRCIFWidth) && (iFrameSize.iHeight >= KCMRCIFHeight) )
	        {
	        iMinRandomAccessPeriodInSeconds = KCMRMinRandomAccessPeriodHighRes;
	        }
        }
    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Set to MinRandomAccess= %d"), iMinRandomAccessPeriodInSeconds ));

    // Set random access in fps
    if ( iMinRandomAccessPeriodInSeconds > 0 )
        {
        iDevVideoRec->SetMinRandomAccessRate( TReal(1) / TReal(iMinRandomAccessPeriodInSeconds) );
        }
    else
        {
        // there is no concept of disabling random access in MSL, hence use the default
        iDevVideoRec->SetMinRandomAccessRate( TReal(1) / TReal(KCMRMinRandomAccessPeriod) );
        }

    CleanupStack::PopAndDestroy( comprFormat );

    // set codec specific settings
    iVideoCodecData->SetPreInitParamsL(iDevVideoRec);

    if (iDirectCapture)
        {
        TInt status = KErrNone;
        // Set the data source to a camera
        TRAP( status, iDevVideoRec->SetSourceCameraL( iCameraHandle, TReal(iSourceFrameRate)) );

        if ( status != KErrNone )
            {
            // Probably it's not supported, although directCapture was declared in the hwdevice info.
            // Leave or to give one more chance to encoder, to use src memory as a source ?
            // Yes, otherwise User::Leave(status);
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() Setting camerasource to MDF failed.")));
            }
        else
            {
            if ( iClockSource )
                {
                iDevVideoRec->SetClockSource( iClockSource );
                }
            // Ok, use direct capture
            PRINT((_L("CCMRVideoRecorder::SetupEncoderL() out")));
            return;
            }
        }

    // Set source memory is allocated & released by camera API
    iDevVideoRec->SetSourceMemoryL( TReal(iSourceFrameRate), ETrue, KCMREncodingRealTime);
    // Set the source to memory buffers
    iDirectCapture = EFalse;
    PRINT((_L("CCMRVideoRecorder::SetupEncoderL() out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::ReadEncoderInfoL
// Read encoder information object. The object is popped from
// stack and MUST be handled properly by the caller
// (other items were commented in a header).
// ---------------------------------------------------------
//
CVideoEncoderInfo* CCMRVideoRecorder::ReadEncoderInfoL(TUid aUid)
    {
    PRINT((_L("CCMRVideoRecorder::ReadEncoderInfoL(), In")))
    CVideoEncoderInfo* info = iDevVideoRec->VideoEncoderInfoLC( aUid );
    CleanupStack::Pop(info);

    PRINT((_L("CCMRVideoRecorder::ReadEncoderInfoL(), Out")))
    return info;
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::PrepareL
// Prepares the recorder for recording
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::PrepareL()
    {
    PRINT((_L("CCMRVideoRecorder::PrepareL(), In")));

    if ( (State() != EStateOpen) && (State() != EStateReadyToRecord) )
        {
        PRINT((_L("CCMRVideoRecorder::PrepareL() wrong state")));
        User::Leave( KErrNotReady );
        }

	if ( State() == EStateReadyToRecord )
		{
		// No prepare needed... already ready.
		// everything ok, inform observer that we are prepared.
		PRINT((_L("CCMRVideoRecorder::PrepareL(), Already prepared. Return right away")));
        DoSendEventToClient( KCMRPrepareComplete, KErrNone );
		return;
		}

	if (iDevVideoRec)
		{
		delete iDevVideoRec;
		iDevVideoRec = NULL;
		}

	iDevVideoRec = CMMFDevVideoRecord::NewL( *this );

    // reset error code
    iErrorCode = KErrNone;

    // If the user of the recorder API has not set valid settings,
    // use default ones

    if ( ((iSizeIndex420 < 0) && (iSizeIndex422 < 0) && (iSizeIndexDCEncoder < 0))
        || ((iSizeIndex420 >= iCameraInfo.iNumVideoFrameSizesSupported) && (iSizeIndex422 >= iCameraInfo.iNumVideoFrameSizesSupported)) )
        {
        // set default frame size
        SetFrameSizeL( TSize( KCMRFrameWidth, KCMRFrameHeight ) );
        }

    if ( ((iRateIndex420 < 0) && (iRateIndex422 < 0) && (iRateIndexDCEncoder < 0))
        || ((iRateIndex420 >= iCameraInfo.iNumVideoFrameRatesSupported) && (iRateIndex422 >= iCameraInfo.iNumVideoFrameRatesSupported)) )
        {
        // set default frame rate
        SetFrameRateL( KCMRFrameRate );
        }

    // if during previous run a new frame rate was requested; when requested it affected only on encoding rate
    if ( iRequestedFrameRate != iSourceFrameRate )
        {
        SetState(EStateOpen);//change state to make the SetFrameRate work correctly
        SetFrameRateL( iRequestedFrameRate );
        }

    // reset init completion flags
    iEncoderInitComplete = EFalse;
    iSourceInitComplete = EFalse;
    iVideoCodecHWAccelerated = EFalse;
    // Select & set parameters to video encoder
    TRAPD(err, SetupEncoderL());
    if ( err == KErrHardwareNotAvailable && iVideoCodecHWAccelerated )
        {
        // HW codec exists but can't be used, try again with ARM codec
        SetupEncoderL();
        }
    else if ( err != KErrNone )
        {
        // some other error
        PRINT((_L("CCMRVideoRecorder::PrepareL(), error [%d]"), err));
        User::Leave( err );
        }

    SetState(EStatePreparing);

    // Reserve camera for use
    // Possibly asynchronous call (if not already reserved), completion is anyway informed using this->ReserveComplete()
    // iSource has to be reserved only if we don't set hwdevice to use DirectCapture.
    if ( !iDirectCapture )
        {
        iSource->Reserve();
        }

    // Initialize DevVideoRec
    // asynchronous call, completion informed using this->MdvroInitializeComplete()
    iDevVideoRec->Initialize();

    PRINT((_L("CCMRVideoRecorder::PrepareL(), Out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::RecordL
// Starts recording
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::RecordL()
    {
	PRINT((_L("CCMRVideoRecorder::RecordL() - START - iRequestStatus: 0x%08x"), iRequestStatus ));

    if ( (State() == EStateRecording) || (State() == EStatePaused) )
        {
        // ignore, already recording
        PRINT((_L("CCMRVideoRecorder::RecordL() ignore")));
        return;
        }

    if ( State() != EStateReadyToRecord )
        {
        PRINT((_L("CCMRVideoRecorder::RecordL() not ready")));
        User::Leave(KErrNotReady);
        }

    // check exposure setting from camera => decide framerates
    CheckExposure();

#ifdef _DEBUG
    iRecordStartTime.UniversalTime();
    iLastCapture.UniversalTime();
#endif
    iNumberOfCapturedFrames = 0;
    iNumberOfEncodedFrames = 0;
    iEncoderInputQueueLength = 0;
    iDriftFrameSkipCount = 0;
    iAddedFrameDurationCount = 0;
    iPreviousCameraFrameIndex = 0;
    iDecSpecInfoLength = 0;

    // reset pause time adjustments variables
    iTimeWhenPaused = 0;
    iTotalPausedTime = 0;
    iSystemClockDelta = 0;
    iLatestUsedTimeStamp = -iSourceFrameInterval;
    iLatestAbsoluteTimeStamp = 0;
    iNumberOfCapturedFrames = 0;
    iNumberOfVideoOutputBuffers = 0;

    if ( iVideoCodecData->DecoderConfigInfoUsed() )
        {
        // Read decoder specific information from the encoder
        PRINT((_L("CCMRVideoRecorder::RecordL() asking CodingStandardSpecificInitOutputLC from the encoder.")));
        iDecSpecInfo = iDevVideoRec->CodingStandardSpecificInitOutputLC();
        if ( iDecSpecInfo )
            {
            PRINT((_L("CCMRVideoRecorder::RecordL() CodingStandardSpecificInitOutputLC received.")));
            // it was placed to cleanupstack, pop it now since it takes some time before
            // this ptr can be destructed, and if destructed from the stack, there may
            // be newer objects in the stack at that time. The ptr is also now stored
            // to member variable which must not be in stack
            CleanupStack::Pop(iDecSpecInfo);

            // Inform the output that we have new data; it will read it in callback
            if ( iRequestStatus )
                {
				PRINT((_L("CCMRVideoRecorder::RecordL() - completing output request..." )));
                iOutputThreadHandle.RequestComplete( iRequestStatus, KErrNone );
                }
            }
        else
            {
            // This codec should have decoder specific info field in metadata, hence leave with error
            PRINT((_L("CCMRVideoRecorder::RecordL() no decoder specific info available from the encoder!?!")));
            User::Leave( KErrNotSupported );
            }
        }

    // Start encoding
    iDevVideoRec->Start();
    iSkipBuffers = EFalse;

    iInputEnd = EFalse;
    iStreamEnd = EFalse;

    // Start capturing
    // StartCapture in case, if we don't use direct capture mode
    if ( !iDirectCapture )
        {
        iSource->StartCapture();
        }

    SetState(EStateRecording);

	PRINT((_L("CCMRVideoRecorder::RecordL() - END - iRequestStatus: 0x%08x"), iRequestStatus ));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::StopL
// Stops recording
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::StopL()
    {
    PRINT((_L("CCMRVideoRecorder::StopL(), In")))

    if ( (State() == EStateRecording) || (State() == EStatePaused) )
        {
        PRINT((_L("CCMRVideoRecorder::StopL(), Stop capture")));

        // Stop capturing
        // Stop capture only incase, if we don't use direct capture mode
        if ( !iDirectCapture )
            {
            iSource->StopCapture();
            PRINT((_L("CCMRVideoRecorder::StopL() camera stopped")));
            }


        // Stopping is async => state can't be "recording"
        SetState(EStateStopping);

        // Stop encoding
        if ( !iFatalError )
            {
            iInputEnd = ETrue;
            PRINT((_L("CCMRVideoRecorder::StopL(), calling DevVideo::InputEnd().")));                
            iDevVideoRec->InputEnd();
            // try to free buffers for video adaptation to complete video bitstream / EOS marker.
            PRINT((_L("CCMRVideoRecorder::StopL(), flushing written frames back to DevVideo.")));                
            iBufferReturnAO->Flush();
            
            // get all available buffers from devvideo
            PRINT((_L("CCMRVideoRecorder::StopL(), getting all encoded frames from DevVideo.")));                
            TVideoOutputBuffer* buffer = NULL;
            for (;;)
                {
                TRAPD( err, ( buffer = iDevVideoRec->NextBufferL()));
                if ( err != KErrNone || buffer == NULL)
                    {
                    break;
                    }
                // enter restricted area
                iMutexObj.Wait();
                // store
                TInt timestamp = I64INT(buffer->iCaptureTimestamp.Int64());
                PRINT((_L("CCMRVideoRecorder::StopL(), storing buffer: 0x%x, timestamp:%d"), buffer, timestamp ));                  
                iVideoOutputBufferInputQue.AddLast(*buffer);
                iNumberOfVideoOutputBuffers++;

                // leave restricted area
                iMutexObj.Signal();
                }
            }
        else
            {
            PRINT((_L("CCMRVideoRecorder::StopL(), Fatal error was reported by devVideo, next step is to delete it")));

            // set state & inform MR => it can return from stop
            SetState( EStateReadyToRecord );

            // everything ok, inform observer that we are ready for a new recording (iStopping does it too, though).
            DoSendEventToClient( KCMRRecordingComplete, KErrNone );
            }

        PRINT((_L("CCMRVideoRecorder::StopL() out, must wait for state change before stop completed")));
        }
    else
        {
        DoSendEventToClient( KCMRRecordingComplete, KErrNone );
        PRINT((_L("CCMRVideoRecorder::StopL() out, already stopped")));
        }
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::RequestBuffersAndWaitEOSL
// While stopping keep requesting buffers from adaptation and waiting for EOS marker encodc signal
// (other items were commented in a header).
// ---------------------------------------------------------
//

void CCMRVideoRecorder::RequestBuffersAndWaitEOSL(TInt& aVideoEOSReached)
    {
    PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), in")))
    PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), flushing written frames back to DevVideo.")));                
    iBufferReturnAO->Flush();

    // get all available buffers from devvideo
    PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), getting all encoded frames from DevVideo.")));                
    TVideoOutputBuffer* buffer = NULL;
    for (;;)
        {
        TRAPD( err, ( buffer = iDevVideoRec->NextBufferL()));
        if ( err != KErrNone || buffer == NULL)
            {
            break;
            }
        // enter restricted area
        iMutexObj.Wait();
        // store
        TInt timestamp = I64INT(buffer->iCaptureTimestamp.Int64());
        PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL(), storing buffer: 0x%x, timestamp:%d"), buffer, timestamp));                  
        iVideoOutputBufferInputQue.AddLast(*buffer);
        iNumberOfVideoOutputBuffers++;

        // leave restricted area
        iMutexObj.Signal();
        }
    
    aVideoEOSReached = iStreamEnd;
    PRINT((_L("CCMRVideoRecorder::RequestBuffersAndWaitEOSL() out, aVideoEOSReached=%d"), aVideoEOSReached));
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::PauseL
// Pauses recording
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::PauseL()
    {
    PRINT((_L("CCMRVideoRecorder::PauseL(), In")))

    if ( State() != EStateRecording )
        {
        return;
        }

    SetState( EStatePaused );

    // Take the time stamp and later subtract it from real stamps
    iTimeWhenPaused.UniversalTime();
    PRINT((_L("CCMRVideoRecorder::PauseL() at %i:%i"),I64LOW(iTimeWhenPaused.Int64()), I64HIGH(iTimeWhenPaused.Int64()) ));

    // Adjust in the clock time changes, so we don't add it in twice during resume
    iTimeWhenPaused = iTimeWhenPaused + iSystemClockDelta;
    PRINT((_L("CCMRVideoRecorder::PauseL() at %i:%i"),I64LOW(iTimeWhenPaused.Int64()), I64HIGH(iTimeWhenPaused.Int64()) ));

    // Pause encoding
    iDevVideoRec->Pause();
    PRINT((_L("CCMRVideoRecorder::PauseL(), In")))
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::ResumeL
// Resumes recording
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::ResumeL()
    {
    PRINT((_L("CCMRVideoRecorder::ResumeL(), In")))

    if ( State() != EStatePaused )
        {
        return;
        }

    // Resume encoding
    iDevVideoRec->Resume();

    // measure the time we were paused; remember that this could have been Nth pause
    TTime current;
    current.UniversalTime();
    iTotalPausedTime = iTotalPausedTime.Int64() + current.MicroSecondsFrom(iTimeWhenPaused-iSystemClockDelta).Int64();
    PRINT((_L("CCMRVideoRecorder::ResumeL() at %i:%i, iTotalPausedTime now %d, iSystemClockDelta now %d"),I64LOW(current.Int64()),
                                                                                                          I64HIGH(current.Int64()),
                                                                                                          I64INT(iTotalPausedTime.Int64()),
                                                                                                          I64INT(iSystemClockDelta.Int64()) ));

    SetState( EStateRecording );
    PRINT((_L("CCMRVideoRecorder::ResumeL(), Out")))
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::SetVideoCodecL
// Set video codec.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::SetVideoCodecL(const TDesC8& aMimeType)
    {
    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() in")));
    if ( ( State() != EStateOpen ) && ( State() != EStateReadyToRecord ) )
        {
        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() wrong state")));
        User::Leave(KErrNotReady);
        }

    if ( iMimeType == aMimeType )
        {
        // the same codec was already selected, no need to change anything
        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() out, no change needed. Requested codec already in use.")));
        return;
        }

	TInt numerator = KCMRAspectRatioNum;
	TInt denominator = KCMRAspectRatioDenom;
    TInt videoCodecLevel = 10;  // default: H.263 p0 level 10
    TBuf8<256> newMimeType;
    if ( aMimeType == KNullDesC8 )
        {
        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() Requested NULL video codec, default H.263 Baseline profile, level 10 in use.")));
        // use default (H.263 p0 level 10); theoretically this could be useful if codec is first set to smth else and then reset to default
        newMimeType = KCMRMimeTypeH263BaselineProfile;  //copy the contents
        newMimeType += _L8( "; level=10" );    //append level
        videoCodecLevel = 10;
        }
    else {
        // check the given type first
        TBuf8<256> string;
        string = KCMRMimeTypeH263;
        string += _L8( "*" );

        // the client-class checked the availability of the codec in the system already

        if ( aMimeType.MatchF( (const TDesC8& )string ) != KErrNotFound )
            {
            // H.263
            PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263 requested")));
            newMimeType = KCMRMimeTypeH263; //copy the contents

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

            if ( aMimeType.MatchF( _L8("*level=10*") ) != KErrNotFound )
                {
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 10 requested.")));
                videoCodecLevel = 10;
                newMimeType += _L8( "; level=10" );    //append
                }
            else if ( aMimeType.MatchF( _L8("*level=20*") ) != KErrNotFound )
                {
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 20 requested.")));
                videoCodecLevel = 20;
                newMimeType += _L8( "; level=20" );    //append
                }
            else if ( aMimeType.MatchF( _L8("*level=30*") ) != KErrNotFound )
                {
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 30 requested.")));
                videoCodecLevel = 30;
                newMimeType += _L8( "; level=30" );    //append
                }
            else if ( aMimeType.MatchF( _L8("*level=40*") ) != KErrNotFound )
                {
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 40 requested.")));
                videoCodecLevel = 40;
                newMimeType += _L8( "; level=40" );    //append
                }
            else if ( aMimeType.MatchF( _L8("*level=45*") ) != KErrNotFound )
                {
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 45 requested.")));
                videoCodecLevel = 45;
                newMimeType += _L8( "; level=45" );    //append
                }
            else if ( aMimeType.MatchF( _L8("*level=50*") ) != KErrNotFound )
                {
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, level 50 requested.")));
                videoCodecLevel = 50;
                newMimeType += _L8( "; level=50" );    //append
                }
            else if ( aMimeType.MatchF( _L8("*level*") ) != KErrNotFound )
                {
                // no other levels supported
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported level requested.")));
                User::Leave(KErrNotSupported);
                }
            else
                {
                // if no level is given assume 10
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263, no level requested - default to 10.")));
                newMimeType += _L8( "; level=10" );    //append
                videoCodecLevel = 10;
                }

            // recreate the codec data object
            PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.263 recreating codecdata.")));
            delete iVideoCodecData;
            iVideoCodecData = NULL;
            iVideoCodecData = new (ELeave) CCMRVideoCodecDataH263(videoCodecLevel);
            }
        else
            {
			numerator = KCMRMPEG4AspectRatioNum;
			denominator = KCMRMPEG4AspectRatioDenom;

            string = KCMRMimeTypeMPEG4V;
            string += _L8( "*" );

            if ( aMimeType.MatchF( string ) != KErrNotFound )
                {
                // MPEG-4 Visual
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4 Visual requested")));
                newMimeType = KCMRMimeTypeMPEG4VSP; //copy the contents
                if ( aMimeType.MatchF( _L8("*profile-level-id=8*") ) != KErrNotFound )
                    {
                    // simple profile level 0
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 0 requested.")));
                    videoCodecLevel = 0;
                    newMimeType += _L8("8");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=9*") ) != KErrNotFound )
                    {
                    // simple profile level 0b
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 0b requested.")));
                    videoCodecLevel = KCMRMPEG4SPLevel0B;
                    newMimeType += _L8("9");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=1*") ) != KErrNotFound )
                    {
                    // simple profile level 1
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 1 requested.")));
                    videoCodecLevel = 1;
                    newMimeType += _L8("1");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=2*") ) != KErrNotFound )
                    {
                    // simple profile level 2
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 2 requested.")));
                    videoCodecLevel = 2;
                    newMimeType += _L8("2");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=3*") ) != KErrNotFound )
                    {
                    // simple profile level 3
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 3 requested.")));
                    videoCodecLevel = 3;
                    newMimeType += _L8("3");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=4*") ) != KErrNotFound )
                    {
                    // simple profile level 4
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 4a requested.")));
                    videoCodecLevel = 4;
                    newMimeType += _L8("4");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=5*") ) != KErrNotFound )
                    {
                    // simple profile level 5
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 5 requested.")));
                    videoCodecLevel = 5;
                    newMimeType += _L8("5");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=6*") ) != KErrNotFound )
                    {
                    // simple profile level 6
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, simple profile level 6 requested.")));
                    videoCodecLevel = 6;
                    newMimeType += _L8("6");
                    }
                else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound )
                    {
                    // no other profile-level ids supported
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported profile-level requested.")));
                    User::Leave(KErrNotSupported);
                    }
                else
                    {
                    // Default is level 1
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4, no profile requested - defaulting to 1.")));
                    videoCodecLevel = 1;
                    newMimeType += _L8("1");
                    }

                // recreate the codec data object
                PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() MPEG-4 recreating codecdata.")));
                delete iVideoCodecData;
                iVideoCodecData = NULL;
                iVideoCodecData = new (ELeave) CCMRVideoCodecDataMPEG4(videoCodecLevel);
                }
            else
                {
				numerator = KCMRMPEG4AspectRatioNum;
				denominator = KCMRMPEG4AspectRatioDenom;

                string = KCMRMimeTypeH264AVC;
                string += _L8( "*" );

                if ( aMimeType.MatchF( string ) != KErrNotFound )
                    {
                    // H.264/AVC
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC requested")));
                    newMimeType = KCMRMimeTypeH264AVCProfileId; //copy the contents
                    if ( aMimeType.MatchF( _L8("*profile-level-id=42800A*") ) != KErrNotFound )
                        {
                        // baseline profile level 1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10;
                        newMimeType += _L8("42800A");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=42900B*") ) != KErrNotFound )
                        {
                        // baseline profile level 1b
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1b requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10b;
                        newMimeType += _L8("42900B");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=42800B*") ) != KErrNotFound )
                        {
                        // baseline profile level 1.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel11;
                        newMimeType += _L8("42800B");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=42800C*") ) != KErrNotFound )
                        {
                        // baseline profile level 1.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel12;
                        newMimeType += _L8("42800C");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=42800D*") ) != KErrNotFound )
                        {
                        // baseline profile level 1.3
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 1.3 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel13;
                        newMimeType += _L8("42800D");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=428014*") ) != KErrNotFound )
                        {
                        // baseline profile level 2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel20;
                        newMimeType += _L8("428014");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=428015*") ) != KErrNotFound )
                        {
                        // baseline profile level 2.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 2.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel21;
                        newMimeType += _L8("428015");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=428016*") ) != KErrNotFound )
                        {
                        // baseline profile level 2.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 2.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel22;
                        newMimeType += _L8("428016");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=42801E*") ) != KErrNotFound )
                        {
                        // baseline profile level 3
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 3 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel30;
                        newMimeType += _L8("42801E");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=42801F*") ) != KErrNotFound )
                        {
                        // baseline profile level 3.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 3.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel31;
                        newMimeType += _L8("42801F");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=428020*") ) != KErrNotFound )
                        {
                        // baseline profile level 3.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 3.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel32;
                        newMimeType += _L8("428020");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=428028*") ) != KErrNotFound )
                        {
                        // baseline profile level 4
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, baseline profile level 4 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel40;
                        newMimeType += _L8("428028");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400A*") ) != KErrNotFound )
                        {
                        // main profile level 1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10;
                        newMimeType += _L8("4D400A");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D500B*") ) != KErrNotFound )
                        {
                        // main profile level 1b
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1b requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10b;
                        newMimeType += _L8("4D500B");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400B*") ) != KErrNotFound )
                        {
                        // main profile level 1.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel11;
                        newMimeType += _L8("4D400B");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400C*") ) != KErrNotFound )
                        {
                        // main profile level 1.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel12;
                        newMimeType += _L8("4D400C");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D400D*") ) != KErrNotFound )
                        {
                        // main profile level 1.3
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 1.3 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel13;
                        newMimeType += _L8("4D400D");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4014*") ) != KErrNotFound )
                        {
                        // main profile level 2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel20;
                        newMimeType += _L8("4D4014");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4015*") ) != KErrNotFound )
                        {
                        // main profile level 2.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 2.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel21;
                        newMimeType += _L8("4D4015");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4016*") ) != KErrNotFound )
                        {
                        // main profile level 2.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 2.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel22;
                        newMimeType += _L8("4D4016");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D401E*") ) != KErrNotFound )
                        {
                        // main profile level 3
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 3 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel30;
                        newMimeType += _L8("4D401E");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D401F*") ) != KErrNotFound )
                        {
                        // main profile level 3.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 3.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel31;
                        newMimeType += _L8("4D401F");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4020*") ) != KErrNotFound )
                        {
                        // main profile level 3.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 3.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel32;
                        newMimeType += _L8("4D4020");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=4D4028*") ) != KErrNotFound )
                        {
                        // main profile level 4
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, main profile level 4 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel40;
                        newMimeType += _L8("4D4028");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=64400A*") ) != KErrNotFound )
                        {
                        // high profile level 1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10;
                        newMimeType += _L8("64400A");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=644009*") ) != KErrNotFound )
                        {
                        // high profile level 1b
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1b requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10b;
                        newMimeType += _L8("644009");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=64400B*") ) != KErrNotFound )
                        {
                        // high profile level 1.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel11;
                        newMimeType += _L8("64400B");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=64400C*") ) != KErrNotFound )
                        {
                        // high profile level 1.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel12;
                        newMimeType += _L8("64400C");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=64400D*") ) != KErrNotFound )
                        {
                        // high profile level 1.3
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 1.3 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel13;
                        newMimeType += _L8("64400D");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=644014*") ) != KErrNotFound )
                        {
                        // high profile level 2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel20;
                        newMimeType += _L8("644014");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=644015*") ) != KErrNotFound )
                        {
                        // high profile level 2.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 2.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel21;
                        newMimeType += _L8("644015");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=644016*") ) != KErrNotFound )
                        {
                        // high profile level 2.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 2.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel22;
                        newMimeType += _L8("644016");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=64401E*") ) != KErrNotFound )
                        {
                        // high profile level 3
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 3 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel30;
                        newMimeType += _L8("64401E");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=64401F*") ) != KErrNotFound )
                        {
                        // high profile level 3.1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 3.1 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel31;
                        newMimeType += _L8("64401F");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=644020*") ) != KErrNotFound )
                        {
                        // high profile level 3.2
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 3.2 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel32;
                        newMimeType += _L8("644020");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=644028*") ) != KErrNotFound )
                        {
                        // high profile level 4
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, high profile level 4 requested.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel40;
                        newMimeType += _L8("644028");
                        }
                    else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound )
                        {
                        // no other profile-level ids supported
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() unsupported profile-level requested.")));
                        User::Leave(KErrNotSupported);
                        }
                    else
                        {
                        // Default is level 1
                        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC, no profile requested - defaulting to 1.")));
                        videoCodecLevel = KCMRH264AVCCodecLevel10;
                        newMimeType += _L8("42800A");
                        }

                    // recreate the codec data object
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() H.264/AVC recreating codecdata.")));
                    delete iVideoCodecData;
                    iVideoCodecData = NULL;
                    iVideoCodecData = new (ELeave) CCMRVideoCodecDataH264AVC(videoCodecLevel);
                    }
                else
                    {
                    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() Unknown mimetype requested.")));
                    // unknown mimetype
                    }
                }
            }
        }

    // successfully interpreted the input mime type
    if ( newMimeType != iMimeType )
	    {
        iMimeType = newMimeType; //copy the contents
		PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() new supported video codec requested - updating available encoders.")));
		iAvailableVideoEncoders.Reset();
        if ( iPreferredEncoderUID != KNullUid )
            {// We have preferred encoder UID from client - override encoder search and use it instead.
            PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using API user encoder: %d "), iPreferredEncoderUID.iUid));
            iAvailableVideoEncoders.AppendL(iPreferredEncoderUID);
            }
        else if ( iConfig &&
                ( iConfig->IsICMConfigDataAvailable() ) &&
                ( iConfig->VideoQualitySettings().iVideoEncoderUID != KNullUid ) )
            {// Video quality set has set UID value - override encoder search and use it instead.
            PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() skipping encoder search. Using ICM config encoder: %d "), iPreferredEncoderUID.iUid));
            iAvailableVideoEncoders.AppendL(iPreferredEncoderUID);
            }
        else
            {
            iDevVideoRec->FindEncodersL(iMimeType, 0 /* aPreProc */, iAvailableVideoEncoders, EFalse );
            PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() search found %d encoder(s)"), iAvailableVideoEncoders.Count() ));
            }
        
        if ( iConfig )
            {
            iConfig->SetVideoCodec(iMimeType);
            iConfig->SetVideoPixelAspectRatio(numerator, denominator);
            }

        UpdateSupportedVideoFrameSizesRates();

        // user has to call this->PrepareL() now that a setting has been changed !!!
        // allow to start recording only when the state is "EReadyToRecord"
        PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() codec set, prepare needed before recording.")));
        SetState(EStateOpen);
        DoSendEventToClient( KCMRPrepareNeeded, iErrorCode );   // use iErrorCode in case we had stored error; it may be KErrNone too
        iErrorCode = KErrNone;
	    }

    PRINT((_L("CCMRVideoRecorder::SetVideoCodecL() out")));
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::GetVideoCodec
// Get the used video codec.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::GetVideoCodecL( TDes8& aVideoMimeType ) const
    {
    aVideoMimeType = iMimeType;
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetTargetBitRateL
// Sets new target bitrate
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetTargetBitRateL(TInt aBitRate)
    {
    PRINT((_L("CCMRVideoRecorder::SetTargetBitRate, aBitrate = % d"),aBitRate));

    if ( aBitRate == KMMFVariableVideoBitRate )
        {
        // Variable rate requested; normalize the bit-rate (temporarily only in this function)
        // but set a mode
        aBitRate = iVideoCodecData->MaxBitRate();
        iBitRateMode = EBitRateVariable;
        }
    else
        {
        iBitRateMode = EBitRateConstant;
        }

    // check that values are reasonable; check max bitrate only when the level is expected to be used for MMS
    if ( (aBitRate < KCMRMinAcceptedBitRate) || ((iVideoCodecData->LevelForMMS()) && (aBitRate > iVideoCodecData->MaxBitRate())) )
        {
        PRINT((_L("CCMRVideoRecorder::SetTargetBitRateL() illegal bitrate")));
        User::Leave(KErrArgument);
        }

    // call base class implementation
    CCMRRecorderBase::SetTargetBitRateL(aBitRate);

    // inform the max bitrate to the sink
    User::LeaveIfError( iOutput->SetMaxVideoBitRate( aBitRate ) );

    //inform the estimated average bitrate to sink; use a HW-specific scaler to estimate the average
    TReal videoBitrateScaler = 0;
    if ( iConfig )
    	{
        videoBitrateScaler = iConfig->PluginSettings().iCMRAvgVideoBitRateScaler;
    	}

    // make sure we never get scaler value 0 (ends up Div0 error)
    if ( videoBitrateScaler == 0 )
    	{
    	videoBitrateScaler = KCMRAvgVideoBitRateScaler;
    	}

    TInt br = static_cast<TInt>(aBitRate*videoBitrateScaler);
    User::LeaveIfError( iOutput->SetAverageVideoBitRate( br ) );

    if ( StateRequiresDynamicSetting() )
        {
        // we have prepared => new value must be given via dynamic methods
        FillRateControlOptions( iRateControlOptions );
        iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported
        }
    else
        {
        // we are not recording or prepared => value will be given forward in prepare
        }
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::TargetBitRateL
// Gets current target bitrate
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::TargetBitRateL(TInt& aBitRate)
    {
    PRINT((_L("CCMRVideoRecorder::TargetBitRate")));


    if ( iBitRateMode == EBitRateConstant )
        {
        aBitRate = iTargetBitRate;
        }
    else
        {
        aBitRate = KMMFVariableVideoBitRate;
        }
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetFrameSizeL
// Sets new input & output frame size
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetFrameSizeL(const TSize& aSize)
    {

    PRINT((_L("CCMRVideoRecorder::SetFrameSizeL(), In, size: %dx%d"), aSize.iWidth, aSize.iHeight ));

    // allow settings only when in "open" or "readytorecord" states
    if ( ( State() != EStateOpen ) && ( State() != EStateReadyToRecord ) )
        {
        PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() wrong state")));
        User::Leave(KErrNotReady);
        }

    // check that size is acceptable
    if ( !iVideoCodecData->MaxFrameSize( aSize ) )
        {
        PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() illegal frame size")));
        User::Leave(KErrArgument);//could be also KErrNotSupported
        }

    TSize size;
    TInt i = 0;
    TInt j = 0;
   	TInt k = 0;

    PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() looking match for frame size: %d x %d from camera"), aSize.iWidth, aSize.iHeight ));

    // Some explanation of the logic here. Camera API must support the same rates for all formats, since there
    // is just a single variable in the info class to check the number of rates.
    // But the indices may differ and that's why we need enumerations
    if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV420Planar )
        {
        // check YUV420 planar
        for ( i = 0; i < iCameraInfo.iNumVideoFrameSizesSupported; i++ )
            {
            iSource->EnumerateVideoFrameSizes(size, i, CCamera::EFormatYUV420Planar);
            PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV420Planar %d x %d found from camera"), size.iWidth, size.iHeight ));

            if ( size == aSize )
                {
                PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV420Planar %d x %d Matched."), size.iWidth, size.iHeight ));
                iSizeIndex420 = i;
                break;
                }
            }
        }
    else
        {
        i = iCameraInfo.iNumVideoFrameSizesSupported;
        PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera doesn't support EFormatYUV420Planar")));
        }

    if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV422 )
        {
        // check YUV422 interleaved
        for ( j = 0; j < iCameraInfo.iNumVideoFrameSizesSupported; j++ )
            {
            iSource->EnumerateVideoFrameSizes(size, j, CCamera::EFormatYUV422 );
            PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV422 %d x %d found from camera"), size.iWidth, size.iHeight ));

            if ( size == aSize )
                {
                PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera EFormatYUV422 %d x %d Matched."), size.iWidth, size.iHeight ));
                iSizeIndex422 = j;
                break;
                }
            }
        }
    else
        {
        j = iCameraInfo.iNumVideoFrameSizesSupported;
        PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() Camera doesn't support EFormatYUV422")));
        }

	// Search if we have direct capture encoder available -> no need to care about camera supported sizes.
	if ( iAvailableVideoFrameSizesRates.Count() )
		{
        // check direct capture encoder size array
        for ( k = 0; k < iAvailableVideoFrameSizesRates.Count(); k++ )
            {
            // All target resolutions that are below higher resolution found from encoders are accepted.
            if ( (iAvailableVideoFrameSizesRates[k].iPictureSize.iWidth >= aSize.iWidth) &&
            	 (iAvailableVideoFrameSizesRates[k].iPictureSize.iHeight >= aSize.iHeight) )
                {
                PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() DirectCapture encoder %d x %d Matched."), aSize.iWidth, aSize.iHeight ));
				iSizeIndexDCEncoder = k;
                break;
                }
            }
		}
	else
		{
		PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() no directcapture encoder available for given size.")));
		}

    if ( (i == iCameraInfo.iNumVideoFrameSizesSupported) &&
    	 (j == iCameraInfo.iNumVideoFrameSizesSupported) &&
    	 (k == iAvailableVideoFrameSizesRates.Count()) )
        {
        // Requested size not supported by camera API or the directcapture encoder
        PRINT((_L("CCMRVideoRecorder::SetFrameSizeL(), Camera and/or direct capture encoder does not support this resolution")));
        User::Leave(KErrNotSupported);
        }

    iFrameSize = aSize;
    iOutput->SetVideoFrameSize(aSize);

    // user has to call this->PrepareL() now that a setting has been changed !!!
    // allow to start recording only when the state is "EReadyToRecord"
    SetState(EStateOpen);
    DoSendEventToClient( KCMRPrepareNeeded, iErrorCode );   // use iErrorCode in case we had stored error; it may be KErrNone too
    iErrorCode = KErrNone;

    // update MaxFrameRate to new frame size
    iMaxFrameRate4GivenSize = iVideoCodecData->MaxFrameRate( iFrameSize );

    // framerate is tied with framesize; if it was set before update it accordingly
    // this may be overridden by user e.g. with a higher rate; this sets the rates <= previous encoding rate
    if ( (iRateIndex420 >= 0) || (iRateIndex422 >= 0) || (iRateIndexDCEncoder >= 0) )
        {
        // must use iEncodingFrameRate, since other rates may raise encoding rate higher than wanted; this allows camera frame rate to be higher
        TInt success = KErrNone;
        do
            {
            TRAP( success, SetFrameRateL( iEncodingFrameRate ));
            if ( success == KErrNone )
                {
                break;
                }
            // if picture size was increased, we may need to decrease framerate
            iEncodingFrameRate--;
            } while ( iEncodingFrameRate > 0 );
            if ( success != KErrNone )
                {
                // This framesize - framerate combination not possible
                PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() illegal frame size - rate combination")));
                User::Leave(success);
                }
        }

    PRINT((_L("CCMRVideoRecorder::SetFrameSizeL(), Out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::FrameSizeL
// Gets current frame size
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::FrameSizeL(TSize& aSize) const
    {
    PRINT((_L("CCMRVideoRecorder::FrameSizeL()")));
    aSize = iFrameSize;
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetFrameRateL
// Sets new target frame rate
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetFrameRateL(TReal32 aFrameRate)
    {
    PRINT((_L("CCMRVideoRecorder::SetFrameRate(), requested rate %f"), aFrameRate));

    // Size has to be set before setting frame rate !!!
    if ( (State() == EStateNone) || ((iSizeIndex420 < 0) && (iSizeIndex422 < 0) && (iSizeIndexDCEncoder < 0)) )
        {
        PRINT((_L("CCMRVideoRecorder::SetFrameRateL() wrong state")));
        User::Leave(KErrNotReady);
        }

    // check that values are reasonable
    if ( (aFrameRate <= 0) || (aFrameRate > iVideoCodecData->MaxFrameRate(iFrameSize)) )
        {
        PRINT((_L("CCMRVideoRecorder::SetFrameSizeL() illegal frame rate")));
        User::Leave(KErrArgument);
        }

    // encoding frame rate is always the requested one
    if ( aFrameRate <= iMaxFrameRate4GivenSize ) // actually iMaxFrameRate4GivenSize is valid only after prepare
        {
        // requested rate looks ok
        iEncodingFrameRate = aFrameRate;
        }
    else if ( iEncodingFrameRate < iMaxFrameRate4GivenSize )
        {
        // too high rate requested, but the current rate is still lower than max possible, so we can set the rate higher anyway
        iEncodingFrameRate = static_cast<TReal32>(iMaxFrameRate4GivenSize);
        PRINT((_L("CCMRVideoRecorder::SetFrameRate(), requested rate is too high for the used encoder, but set it to this rate: %f"), iMaxFrameRate4GivenSize));
        }
    else
        {
        // The change has no effect; the used encoder is already set to max possible rate and can't be configured for the requested rate
        // for now camera api capability is not checked; e.g. if H.263 level is 20 => framerate could be 30fps for QCIF but if max encoder
        // impl. rate is 10fps, we don't leave, but just ignore
        PRINT((_L("CCMRVideoRecorder::SetFrameRate(), requested rate is too high for the used encoder, max rate %f"), iMaxFrameRate4GivenSize));
        return;
        }

    if ( StateRequiresDynamicSetting() )
        {
        // we are running, change only encoding rate now

        // store the requested rate also, to be taken into use in the next prepare
        if ( !iNightMode )
            {
            iRequestedFrameRate = aFrameRate;
            }

        if ( iEncodingFrameRate > iSourceFrameRate )
            {
            // can't be higher than capture rate, limit it
            iEncodingFrameRate = iSourceFrameRate;
            }

        // set the rate control params
        FillRateControlOptions( iRateControlOptions );
        iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported
        }
    else
        {
        // we are in initialization phase, change also camera rate

        TReal32 rate;
        TInt i;

        iRateIndex420 = -1; //reset just in case, needed to determine if the loop below was successful
        iRateIndex422 = -1; //reset just in case, needed to determine if the loop below was successful
        iRateIndexDCEncoder = -1;

        // Some explanation of the logic here. Camera API must support the same rates for all formats, since there
        // is just a single variable in the info class to check the number of rates.
        // But the indices may differ and that's why we need enumerations
        // Since we prefer YUV422, it can override the member variables.

        if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV420Planar )
            {
            // check YUV420 planar

            // search for an exact match from camera's supported rates
            for ( i = 0; i < iCameraInfo.iNumVideoFrameRatesSupported; i++ )
                {

                iSource->EnumerateVideoFrameRates(rate, i, CCamera::EFormatYUV420Planar, iSizeIndex420,
                                                  CCamera::EExposureAuto);

                if ( rate == aFrameRate )
                    {
                    iRateIndex420 = i;
                    iSourceFrameRate = aFrameRate;
                    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
                    PRINT((_L("CCMRVideoRecorder::SetFrameRate, asked framerate found")));
                    break;
                    }
                else if ( rate > aFrameRate )
                    {
                    // this is higher but could be used (encoder can match the rates)
                    // Check the other rates too if a better is found
                    iRateIndex420 = i;
                    iSourceFrameRate = rate;
                    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
                    PRINT((_L("CCMRVideoRecorder::SetFrameRate, a higher source framerate found")));
                    }
                }
            }

        if ( iCameraInfo.iVideoFrameFormatsSupported & CCamera::EFormatYUV422 )
            {
            // check YUV422 interleaved

            // search for an exact match from camera's supported rates
            for ( i = 0; i < iCameraInfo.iNumVideoFrameRatesSupported; i++ )
                {
                iSource->EnumerateVideoFrameRates(rate, i, CCamera::EFormatYUV422, iSizeIndex422,
                                                  CCamera::EExposureAuto);

                if ( rate == aFrameRate )
                    {
                    iRateIndex422 = i;
                    iSourceFrameRate = aFrameRate;
                    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
                    PRINT((_L("CCMRVideoRecorder::SetFrameRate, asked framerate found")));
                    break;
                    }
                else if ( rate > aFrameRate )
                    {
                    // this is higher but could be used (encoder can match the rates)
                    // Check the other rates too if a better is found
                    iRateIndex422 = i;
                    iSourceFrameRate = rate;
                    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
                    PRINT((_L("CCMRVideoRecorder::SetFrameRate, a higher source framerate found")));
                    }
                }
            }

        if ( iAvailableVideoFrameSizesRates.Count() && (iSizeIndexDCEncoder >= 0) && (iSizeIndexDCEncoder < iAvailableVideoFrameSizesRates.Count()) )
            {
            // check Direct capture encoder supported rates.

            // search for an exact match from encoders supported rates
            for ( i = 0; i < iAvailableVideoFrameSizesRates.Count(); i++ )
                {
                if ( (iAvailableVideoFrameSizesRates[i].iPictureRate == aFrameRate) &&
                	 (iAvailableVideoFrameSizesRates[i].iPictureSize == iAvailableVideoFrameSizesRates[iSizeIndexDCEncoder].iPictureSize) )
                    {
                    iRateIndexDCEncoder = i;
                    iSizeIndexDCEncoder = i;
                    iSourceFrameRate = aFrameRate;
                    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
                    PRINT((_L("CCMRVideoRecorder::SetFrameRate, asked framerate found")));
                    break;
                    }
                else if ( (iAvailableVideoFrameSizesRates[i].iPictureRate >= aFrameRate) &&
                	 	  (iAvailableVideoFrameSizesRates[i].iPictureSize.iWidth >= iAvailableVideoFrameSizesRates[iSizeIndexDCEncoder].iPictureSize.iWidth ) &&
                	 	  (iAvailableVideoFrameSizesRates[i].iPictureSize.iHeight >= iAvailableVideoFrameSizesRates[iSizeIndexDCEncoder].iPictureSize.iHeight ) )
                    {
                    // this is higher but could be used (encoder can match the rates)
                    // Check the other rates too if a better is found
                    iRateIndexDCEncoder = i;
                    iSizeIndexDCEncoder = i;
                    iSourceFrameRate = aFrameRate;
                    iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);
                    PRINT((_L("CCMRVideoRecorder::SetFrameRate, a higher source framerate found: %dx%d at %f"), iAvailableVideoFrameSizesRates[i].iPictureSize.iWidth,
                    																							iAvailableVideoFrameSizesRates[i].iPictureSize.iHeight,
                    																							iAvailableVideoFrameSizesRates[i].iPictureRate ));
                    }
                }
            }


        if ( (iRateIndex420 < 0) && (iRateIndex422 < 0) && (iRateIndexDCEncoder < 0) )
            {
            // there is no suitable frame rate available, not even a higher one, return error
            PRINT((_L("CCMRVideoRecorder::SetFrameRate, no suitable framerate found from Camera API and/or direct capture encoder.")));
            User::Leave(KErrNotSupported);
            }

        // set to the actual rate to prevent trying set the rate again from PrepareL
        iRequestedFrameRate = iSourceFrameRate;

        // user has to call this->PrepareL() now that a setting has been changed !!!
        // allow to start recording only when the state is "EReadyToRecord"
        if ( State() != EStateOpen )
            {
            SetState(EStateOpen);
            DoSendEventToClient( KCMRPrepareNeeded, iErrorCode );   // use iErrorCode in case we had stored error; it may be KErrNone too
            iErrorCode = KErrNone;
            }
        }
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::FrameRateL
// Get the used encoding frame rate
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::FrameRateL(TReal32& aFrameRate) const
    {
    PRINT((_L("CCMRVideoRecorder::FrameRateL()")));
    aFrameRate = iEncodingFrameRate;
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetVideoCodingOptionsL
// Set misc video coding options
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetVideoCodingOptionsL(const TCCMRVideoCodingOptions& aOptions)
    {
    if ( ( State() != EStateOpen ) && ( State() != EStateReadyToRecord ) )
        {
        PRINT((_L("CCMRVideoRecorder::SetVideoCodingOptionsL() wrong state")));
        User::Leave( KErrNotReady );
        }
    if ( iMinRandomAccessPeriodInSeconds != KCMRUseDefault )
        {
        iMinRandomAccessPeriodInSeconds = aOptions.iMinRandomAccessPeriodInSeconds;
        }

    iVideoCodecData->SetVideoCodingOptionsL(aOptions);
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetVideoRateControlOptionsL
// Set video rate control options
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetVideoRateControlOptionsL(const TRateControlOptions& aOptions)
    {
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() in")));
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() TBitrateControlType iControl: %d"), aOptions.iControl));
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iBitrate: %d"), aOptions.iBitrate));
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iPictureQuality: %d"), aOptions.iPictureQuality));
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iPictureRate: %f"), aOptions.iPictureRate));
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iQualityTemporalTradeoff: %f"), aOptions.iQualityTemporalTradeoff));
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() iLatencyQualityTradeoff: %f"), aOptions.iLatencyQualityTradeoff));

    if ( !StateRequiresDynamicSetting() )
    	{
        PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() illegal state for dynamic settings")));
    	User::Leave(KErrNotReady);
    	}

	// Handle new bitrate value:
    if ( (aOptions.iBitrate < KCMRMinAcceptedBitRate) || ((iVideoCodecData->LevelForMMS()) && (aOptions.iBitrate > iVideoCodecData->MaxBitRate())) )
        {// check that values are reasonable; check max bitrate only when the level is expected to be used for MMS
        PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() illegal bitrate")));
        User::Leave(KErrArgument);
        }
    CCMRRecorderBase::SetTargetBitRateL(aOptions.iBitrate);
    // inform the max bitrate to the sink
    User::LeaveIfError( iOutput->SetMaxVideoBitRate( aOptions.iBitrate ) );
    //inform the estimated average bitrate to sink; use a HW-specific scaler to estimate the average
    TReal videoBitrateScaler = 0;
    if ( iConfig )
    	{
        videoBitrateScaler = iConfig->PluginSettings().iCMRAvgVideoBitRateScaler;
    	}
    if ( videoBitrateScaler == 0 )
    	{// make sure we never get scaler value 0 (ends up Div0 error)
    	videoBitrateScaler = KCMRAvgVideoBitRateScaler;
    	}
    TInt br = static_cast<TInt>(aOptions.iBitrate*videoBitrateScaler);
    User::LeaveIfError( iOutput->SetAverageVideoBitRate( br ) );


    //Handle new framerate value:
    if ( (aOptions.iPictureRate <= 0) || (aOptions.iPictureRate > iVideoCodecData->MaxFrameRate(iFrameSize)) )
        {// check that values are reasonable
        PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() illegal frame rate, %f"), aOptions.iPictureRate));
        User::Leave(KErrArgument);
        }
    if ( aOptions.iPictureRate <= iMaxFrameRate4GivenSize ) // actually iMaxFrameRate4GivenSize is valid only after prepare
        {// encoding frame rate is always the requested one
        iEncodingFrameRate = aOptions.iPictureRate;        // requested rate looks ok
        }
    else if ( iEncodingFrameRate < iMaxFrameRate4GivenSize )
        {// too high rate requested, but the current rate is still lower than max possible, so we can set the rate higher anyway
        iEncodingFrameRate = static_cast<TReal32>(iMaxFrameRate4GivenSize);
        PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL(), requested rate is too high for the used encoder, but set it to this rate: %f"), iMaxFrameRate4GivenSize));
        }
    if ( !iNightMode )
        {// store the requested rate also, to be taken into use in the next prepare
        iRequestedFrameRate = aOptions.iPictureRate;
        }
    if ( iEncodingFrameRate > iSourceFrameRate )
        {// can't be higher than capture rate, limit it
        iEncodingFrameRate = iSourceFrameRate;
        }

    iRateControlOptions = aOptions;
    iRateControlOptions.iPictureRate = iEncodingFrameRate;
    if ( iDevVideoRec )
    	{
        PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() settings stored and sending them to Devvideo.")));
        iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported
    	}
    else
    	{
        PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() no DevVideoRec! Leaving KErrNotReady -18")));
    	User::Leave(KErrNotReady);
    	}
    PRINT((_L("CCMRVideoRecorder::SetVideoRateControlOptionsL() out")));
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::GetVideoRateControlOptionsL
// Get video rate control options
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::GetVideoRateControlOptionsL(TRateControlOptions& aOptions)
    {
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() in")));
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() TBitrateControlType iControl: %d"), iRateControlOptions.iControl));
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iBitrate: %d"), iRateControlOptions.iBitrate));
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iPictureQuality: %d"), iRateControlOptions.iPictureQuality));
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iPictureRate: %f"), iRateControlOptions.iPictureRate));
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iQualityTemporalTradeoff: %f"), iRateControlOptions.iQualityTemporalTradeoff));
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() iLatencyQualityTradeoff: %f"), iRateControlOptions.iLatencyQualityTradeoff));

    if ( !StateRequiresDynamicSetting() )
        {
        PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() illegal state for dynamic settings")));
        User::Leave(KErrNotReady);
        }
    aOptions = iRateControlOptions;
    PRINT((_L("CCMRVideoRecorder::GetVideoRateControlOptionsL() out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::SetPreferredVideoEncoderL
// Set video encoder using its UID. Usage optional.
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetPreferredVideoEncoderL(TUid& aEncoder)
    {
    PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncoderL() in")));
    iPreferredEncoderUID = aEncoder;

    if ( iPreferredEncoderUID != KNullUid )
        {// We have preferred encoder UID from client - override encoder search and use it instead.
        PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncoderL() skipping encoder search. Using API user encoder: %d "), iPreferredEncoderUID.iUid));
        iAvailableVideoEncoders.Reset();
        iAvailableVideoEncoders.AppendL(iPreferredEncoderUID);
        UpdateSupportedVideoFrameSizesRates();
        }

    PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncoderL() out")));
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::SetPreferredVideoEncapsulationL
// Set video encoder output format encapsulation. Usage optional.
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetPreferredVideoEncapsulationL(TVideoDataUnitEncapsulation aCapsulation)
    {
    PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncapsulationL() in")));
    iPreferredEncapsulation = aCapsulation;
    iPreferredEncapsulationSet = ETrue;
    PRINT((_L("CCMRVideoRecorder::SetPreferredVideoEncapsulationL() out")));
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::SetSegmentTargetSize
// Set video segment target size
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::SetSegmentTargetSizeL(TUint aLayer, TUint aSizeBytes, TUint aSizeMacroblocks)
    {
    PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() in")));
    PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() aLayer: %d"), aLayer));
    PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() aSizeBytes: %d"), aSizeBytes));
    PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() aSizeMacroblocks: %d"), aSizeMacroblocks));

    if ( !StateRequiresDynamicSetting() )
        {
        PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() illegal state for dynamic settings")));
        User::Leave(KErrNotReady);
        }

    if ( iDevVideoRec )
        {
        PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() sending SetSegmentTargetSize to Devvideo.")));
        iDevVideoRec->SetSegmentTargetSize(aLayer, aSizeBytes, aSizeMacroblocks); // only base layer (layer 0) supported
        }
    else
        {
        PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() no DevVideoRec! Leaving KErrNotReady -18")));
        User::Leave(KErrNotReady);
        }
    PRINT((_L("CCMRVideoRecorder::SetSegmentTargetSize() out")));
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::AdjustTimeStampsL
// Adjust time stamps of video
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::AdjustTimeStampsL(const TInt aAdjustmentMs)
    {
    if ( State() != EStateRecording )
        {
        PRINT((_L("CCMRVideoRecorder::AdjustTimeStampsL() wrong state")));
        User::Leave( KErrNotReady );
        }

    iAdjustmentTimeUs = TInt64( aAdjustmentMs * 1000 );

    PRINT((_L("CCMRVideoRecorder::AdjustTimeStampsL() by %d us"),I64INT(iAdjustmentTimeUs)));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MvsoReserveComplete
// Called by camera API when camera API has been reserved
// for exclusive use
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MvsoReserveComplete(TInt aError)
    {
    PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() in")));

    // Should not be called, if we use direct capture mode
    if (iDirectCapture)
        {
        VRASSERT(0);
        }

    // need to set this already here if returns unsuccesfully, to enable error handling when encoder init completes
    iSourceInitComplete = ETrue;

    if ( iEncoderInitComplete && (iErrorCode != KErrNone) )
        {
        // there was an error in the encoder initialisation, but the reporting was
        // waiting for the completion of the source initialisation => report it now
        PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() but error in video encoder: %d"), iErrorCode));
        DoSendEventToClient( KCMREncoderInitError, iErrorCode );
        iErrorCode = KErrNone;
        return;
        }

    if ( aError != KErrNone )
        {
        if ( iEncoderInitComplete )
            {
            PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() with error: %d"), aError));
            DoSendEventToClient( KCMRCameraReserveError, aError );
            }
        else
            {
            // report only when encoder is completed too
            PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() with error: %d, but must wait for encoder init completion"), aError));
            iErrorCode = aError;
            }
        return;
        }

    TInt error;

    TRAP(error, iSource->PrepareCaptureL(iVideoFormat, iSizeIndex, iRateIndex,
                                         iNumCameraBuffers, KCMRNumFramesInCameraBuffer));

    PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() camera prepared, error %d"),error));
    if ( error != KErrNone )
        {
        if ( iEncoderInitComplete )
            {
            DoSendEventToClient( KCMRCameraPrepareError, error );
            }
        else
            {
            // report only when encoder is completed too
            iErrorCode = error;
            }
        return;
        }


    if ( iEncoderInitComplete )
        {
        SetState(EStateReadyToRecord);

        // everything ok, inform observer that we are prepared.
        DoSendEventToClient( KCMRPrepareComplete, KErrNone );
        }

    PRINT((_L("CCMRVideoRecorder::MvsoReserveComplete() out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MvsoFrameBufferReady
// Called by camera API when a frame (or several frames)
// has been captured
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MvsoFrameBufferReady(MFrameBuffer* aFrameBuffer, TInt aError)
    {
    // Should not be called, if we use direct capture mode
    if (iDirectCapture)
        {
        VRASSERT(0);
        }

    if ( aError != KErrNone || aFrameBuffer == NULL )
        {
        // some errors, inform observer and return
        DoSendEventToClient( KCMRCameraCaptureError, aError );
        if ( aFrameBuffer )
            {
            // in case of errors, aFrameBuffer may be NULL
            aFrameBuffer->Release();
            }
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady with error %d"), aError));
        return;
        }

    PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady in %x, frame & time & systemdrift\t%d\t%d\t%d"),aFrameBuffer,
                                                                                       aFrameBuffer->iIndexOfFirstFrameInBuffer,
                                                                                       I64INT(aFrameBuffer->iElapsedTime.Int64()),
                                                                                       I64INT(iSystemClockDelta.Int64())
                                                                                       ));

#ifdef VIDEO_FILE_OUTPUT

    // Write the frame to a file for testing purposes
    TInt error = KErrNone;
    TRAPD(error2, error = iOutputFile.Write( *(aFrameBuffer->DataL(0)) ));

    // release frame
    aFrameBuffer->Release();

    if (error != KErrNone || error2 != KErrNone)
        {
        DoSendEventToClient( KCMRRunTimeError, error );
        }


#else
    // the real deal

    if ( (State() != EStateRecording) || (iErrorCode != KErrNone) )
        {
        // we are paused or stopping or there was an error => return the framebuffer immediately
        // if system clock has been changed during pause take that account in future frame timestamp calculations.
        if ( (((aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) < iLatestAbsoluteTimeStamp.Int64()) ||
             ((aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) > (iLatestAbsoluteTimeStamp.Int64() + 2*iSourceFrameInterval))) &&
             (aFrameBuffer->iIndexOfFirstFrameInBuffer == iPreviousCameraFrameIndex + 1) )
             {
             // something has changed system clock during pause, add cumulatively to drift delta.
             iSystemClockDelta = (iLatestAbsoluteTimeStamp.Int64() + iSourceFrameInterval) -
                                 (aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64())
                                 + iSystemClockDelta.Int64();

             PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() System time change: aFrameBuffer->iElapsedTime = %d, iSystemClockDelta = %d, iLatestAbsoluteTimeStamp = %d, iSourceFrameInterval = %d"),
                                                                                              I64INT(aFrameBuffer->iElapsedTime.Int64()),
                                                                                              I64INT(iSystemClockDelta.Int64()),
                                                                                              I64INT(iLatestAbsoluteTimeStamp.Int64()),
                                                                                              iSourceFrameInterval));
             }

        iLatestAbsoluteTimeStamp = aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64();
        iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer;
        aFrameBuffer->Release();
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() not recording, skip this one")));
        return;
        }


#if ( defined (__WINS__) || defined (__WINSCW__) )
    if ( iEncoderInputQueueLength > 0 )
        {
        // Too many pictures already in the encoder's input queue - skip this one. In Wins the criteria is more strict since performance is lower
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() - encoder already has one frame under processing, skip this one")));
        iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer;
        aFrameBuffer->Release();
        return;
        }
#else
    if ( iEncoderInputQueueLength >= KCMRMaxPreEncoderBufferPictures )
        {
        // Too many pictures already in the encoder's input queue - skip this one
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() - Encoder input/output queue(s) already full, must skip a captured frame")));
        iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer;
        aFrameBuffer->Release();
        return;
        }
#endif

    // Regulate timestamp to avoid too small or too large variations

    // use frame index instead of associated buffer timestamp, since timestamps may be
    // less accurate and may cause rounding problems when converted to e.g. H.263 TRs
    TInt64 frameTimeStamp;
    frameTimeStamp = TInt64((aFrameBuffer->iIndexOfFirstFrameInBuffer - iDriftFrameSkipCount + iAddedFrameDurationCount) * 1E6/iSourceFrameRate + 0.5);   // use accurate division here since rounded value in multiplication multiplies also the rounding error

    // However, relying purely on frameindex causes drifting if the used source framerate value here is not exactly
    // the camera input rate. Hence we need to do some adjustments.
    // The frameindex may also be exclude skipped frames, but that should considered a bug in camera drivers, although the Camera API spec is not fully unambiguous about this
    TInt64 expectedNewTimeStamp;
    if ( iNumberOfCapturedFrames > 0 )
        {
        expectedNewTimeStamp = iLatestAbsoluteTimeStamp.Int64() + iSourceFrameInterval;
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), expectedNewTimeStamp (abs)\t%d\t"),I64INT(expectedNewTimeStamp)));
        }
    else
        {
        //first frame
        expectedNewTimeStamp = 0;
        iDriftFrameSkipCount = 0;
        iAddedFrameDurationCount = 0;
        iPreviousCameraFrameIndex = 0;
        }

    TInt frameDropCount = aFrameBuffer->iIndexOfFirstFrameInBuffer - iPreviousCameraFrameIndex - 1;
    iPreviousCameraFrameIndex = aFrameBuffer->iIndexOfFirstFrameInBuffer;
    //
    // Handle case where camera has dropped frames.
    //
    if ( frameDropCount > 0 )
        {// Camera dropped frame
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), Camera dropped %d frame(s), drift from expected: \t%d\t"),
                                                frameDropCount,
                                                I64INT((frameTimeStamp - expectedNewTimeStamp ))));
        frameTimeStamp = expectedNewTimeStamp + (frameDropCount*iSourceFrameInterval);
        }
	//
	// Handle case where camera frame timestamp is more than previous encoded timestamp + specified camera frame duration.
	//
    else if ( aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() > expectedNewTimeStamp )
        {
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted timestamp since it was greater than expected timestamp and we have delayed timestamps earlier\t%d\t"),I64INT((expectedNewTimeStamp - frameTimeStamp))));
        // we have adjusted timestamps more to positive direction (delayed timestamps), try to compensate it now
        // if camera frames have drifted more than 1 frame duration increase frame time stamp with one frame duration (as if frame dropped).
        if ((aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() - expectedNewTimeStamp) > iSourceFrameInterval )
        	{
        	iAddedFrameDurationCount++;
        	PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), Camera timestamp has drifted more than 1 frame duration - adding 1 frame duration to timestamp from now on!\t%d\t"), iAddedFrameDurationCount ));
        	expectedNewTimeStamp = iLatestAbsoluteTimeStamp.Int64() + 2*iSourceFrameInterval;
            PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), new expectedNewTimeStamp (abs)\t%d\t"),I64INT(expectedNewTimeStamp)));
        	}
        frameTimeStamp = expectedNewTimeStamp;
        }
	//
	// Handles case where camera frame timestamp is less than previous encoded frame timestamp
	// * happens when Camera is producing higher FPS that target FPS causing frame timestamp to drift below calculated cumulative recording time.
	//
    else if ( aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() < iLatestAbsoluteTimeStamp.Int64() )
        {
        // frame with the timestamp of this frame was already encoded
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), drift between expected and frame buffer timestamp more than 1 frame duration, dropping frame!")));
        iDriftFrameSkipCount++;
        aFrameBuffer->Release();
        return;
        }
	//
	// Handle case where (camera frame index * framerate) is less than camera frame timestamp - specified camera frame duration
	// * happens when Camera is skipping frames without extra increase in frame index count.
	//
    else if ( frameTimeStamp < ( (aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()) - iSourceFrameInterval ) )
        {
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted timestamp since frame counter was too small compared to elapsed time: difference\t%d\t"),I64INT(aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64() - frameTimeStamp)));
        // frame numbers & elapsed time do not match, probably camera is skipping frames but doesn't know it / doesn't inform it to us
        frameTimeStamp = Max( aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64(), expectedNewTimeStamp );
        }
    //
    // Handle case where (camera frame index * framerate) is less than calculated estimated timestamp value for currect frame
    // (based on previous encoded frame timestamp + specified camera frame duration)
    //
    else if ( frameTimeStamp < expectedNewTimeStamp )
        {
        // timestamp should not be too close to the previous timestamp (video codecs set max for framerate <=> min for ts diff)
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted timestamp since it was smaller than expected timestamp, difference\t%d\t"),I64INT(expectedNewTimeStamp - frameTimeStamp)));
        frameTimeStamp = expectedNewTimeStamp;
        }
    else
        {
        // leave it as it is
        }

    // for now we've been playing with absolute times, excluding all pauses & adjustments. Save this value as reference for determining timestamp for the next frame
    iLatestAbsoluteTimeStamp = frameTimeStamp;

    if ( iAdjustmentTimeUs != 0 )
        {
        // at the moment, initial and pause values are in opposite direction (+/-)
        // for initial adjustment:
        // if audio is ahead (iAdjustmentTimeUs > 0) => video should fast forward (video timestamps should be increased),
        // if audio is behind (iAdjustmentTimeUs < 0) => video should "pause" for a while (video timestamps should be decreased)
        // note that we modify here the iPausedTime which is subtracted from aFrameBuffer->iElapsedTime, so these
        // changes affect kind of reverse way

        if ( ( frameTimeStamp - (iTotalPausedTime.Int64() - iAdjustmentTimeUs) ) >= (iLatestUsedTimeStamp.Int64() + iSourceFrameInterval) )
            {
            // iAdjustmentTimeUs > 0 or < 0 but not too much < 0 so that the resulting timestamp won't be < (latest time stamp + sourceframeinterval)
            iTotalPausedTime = iTotalPausedTime.Int64() - iAdjustmentTimeUs;
            PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), adjusted paused time by %d us"), I64INT(iAdjustmentTimeUs)));
            iAdjustmentTimeUs = 0;
            }
        else
            {
            // iAdjustmentTimeUs < 0 here, we should "pause" video (skip frames) until we reach the required time
            // Skipping is needed to avoid the timestamps to skip back over already captured frames.
            PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), skipped a frame due to time adjustment request %d; buffer->elapsedTime %d; latest time stamp %d"), I64INT(iAdjustmentTimeUs), I64INT(aFrameBuffer->iElapsedTime.Int64() + iSystemClockDelta.Int64()), I64INT(iLatestUsedTimeStamp.Int64()) ));
            aFrameBuffer->Release();
            return;
            }
        }

    // subtract the time we were paused
    // (MSL assumes devvideorecord/hw device does this but we do it here)
    TTimeIntervalMicroSeconds iPrevUsedTimeStamp = iLatestUsedTimeStamp;
    iLatestUsedTimeStamp = frameTimeStamp - iTotalPausedTime.Int64();

    // Increment timestamp in case we dropped frames during pause
    while(( iLatestUsedTimeStamp < iPrevUsedTimeStamp ) && ( iNumberOfCapturedFrames > 0 ))
        {
        PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady() incrementing timestamp by one frame")));
        iLatestUsedTimeStamp = TTimeIntervalMicroSeconds( iLatestUsedTimeStamp.Int64() + iSourceFrameInterval );
        }

    PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), iTotalPausedTime \t%d"), I64INT(iTotalPausedTime.Int64()) ));
    PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady(), iLatestUsedTimeStamp (relative) & drift from elapsed time\t%d"), I64INT(iLatestUsedTimeStamp.Int64()) ));

    EncodeFrame(aFrameBuffer);

    PRINT((_L("CCMRVideoRecorder::MvsoFrameBufferReady, out")));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::EncodeFrame
// Encodes the given video frame.
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::EncodeFrame(MFrameBuffer* aFrameBuffer)
    {
    PRINT((_L("CCMRVideoRecorder::EncodeFrame, in")));

    // Take a TVideoPicture into use
    TVideoPicture* outputPicture = NULL;
    if ( iCodingFifo->IsEmpty() )
        {
        // allocate a new
        outputPicture = new TVideoPicture;
        if ( outputPicture == NULL )
            {
            // out of memory, stop operation
            DoSendEventToClient( KCMRRunTimeError, KErrNoMemory );
            aFrameBuffer->Release();
            return;
            }
        }
    else
        {
        // take an old one from the queue
        outputPicture = reinterpret_cast<TVideoPicture*>(iCodingFifo->Get());
        }

    iNumberOfCapturedFrames++;

#ifdef _DEBUG
    TTime current;
    current.UniversalTime();
    TInt elapsedMs = I64INT((current.MicroSecondsFrom(iLastCapture).Int64())) / 1000;
    iCumulativeCaptureTime += elapsedMs;
    iAverageCaptureTime = TReal(iCumulativeCaptureTime) / TReal(iNumberOfCapturedFrames);

    PRINT((_L("CCMRVideoRecorder::EncodeFrame() recording time %d, ms since last: %d, average capture time: %4.2f"),
        (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) / 1000,
        elapsedMs,
        iAverageCaptureTime));

    iLastCapture = current;
    iEncodingStartTime.UniversalTime();
#endif

    // wrap captured frame to encoder input buffer
    outputPicture->iData.iDataFormat = EYuvRawData;
    outputPicture->iData.iDataSize.iWidth = iFrameSize.iWidth;
    outputPicture->iData.iDataSize.iHeight = iFrameSize.iHeight;
    TRAPD(err, (outputPicture->iData.iRawData = (TPtr8*)aFrameBuffer->DataL(0)));
    if ( err != KErrNone )
        {
        // error, stop operation
        DoSendEventToClient( KCMRRunTimeError, err );
        aFrameBuffer->Release();
        delete outputPicture;
        return;
        }

    outputPicture->iTimestamp = iLatestUsedTimeStamp;
    outputPicture->iOptions = TVideoPicture::ETimestamp;
    outputPicture->iUser = this;

#ifdef _DEBUG__
    TTime current;
    current.UniversalTime();


    PRINT((_L("CCMRVideoRecorder::EncodeFrame()\t%d"),
        (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) ));
#endif


    // Put the captured buffer to iSourceFifo
    TRAP( err, iSourceFifo->PutL( reinterpret_cast<TAny*>(aFrameBuffer) ));
    if ( err != KErrNone )
        {
        // out of memory, stop operation
        DoSendEventToClient( KCMRRunTimeError, err );
        aFrameBuffer->Release();
        delete outputPicture;
        return;
        }


    // give the frame to devVideoRec for encoding
    iEncoderInputQueueLength++;
    TRAP( err, iDevVideoRec->WritePictureL( outputPicture ) );
    if ( err != KErrNone )
        {
        // error, stop operation, aFrameBuffer will be released from fifo when stopped
        DoSendEventToClient( KCMRRunTimeError, err );
        return;
        }

    PRINT((_L("CCMRVideoRecorder::EncodeFrame, picture %x written to devvr"),outputPicture));

#endif // #else if !VIDEO_FILE_OUTPUT
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MdvroInitializeComplete
// Called by DevVideoRecord when its initalization is complete
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MdvroInitializeComplete(TInt aError)
    {
    PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete(), error[%d]"), aError));

    if ( iDirectCapture )
        {
        // Since direct capture is used, it should be true. Actual init CAPI status is
        // included to aError now.
        iSourceInitComplete = ETrue;
        }

    iEncoderInitComplete = ETrue;

    if ( iSourceInitComplete && (iErrorCode != KErrNone) )
        {
        // there was an error in the source initialisation, but the reporting was
        // waiting for the completion of the encoder initialisation => report it now
        PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() but camera reservation had error: %d"), iErrorCode));
        DoSendEventToClient( KCMRCameraReserveError, iErrorCode );
        iErrorCode = KErrNone;
        return;
        }

    if ( aError != KErrNone )
        {
        if ( aError == KErrHardwareNotAvailable && iVideoCodecHWAccelerated )
            {
            PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, retrying with ARM codec")));
            // hw accel codec and init failed due to resource problems => retry with non-hw-accelerated
            iEncoderInitComplete = EFalse;
            PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, delete devvideo")));
            if (iDevVideoRec)
                {
                delete iDevVideoRec;
                iDevVideoRec = NULL;
                }
            TRAPD(err, iDevVideoRec = CMMFDevVideoRecord::NewL( *this ));
            if ( err == KErrNone )
                {
                PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, new devvideo created")));
                TRAP(err,SetupEncoderL());
                if ( err == KErrNone )
                    {
                    // ok, continue waiting for the callback
                    return;
                    }
                else
                    {
                    // store the last error, to be used in the operations below
                    aError = err;
                    }
                }
            else
                {
                // store the last error, to be used in the operations below
                PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() - initialization of HW accelerated video encoder failed, new devvideo creation failed.")));
                aError = err;
                }
            }

        if ( iSourceInitComplete )
            {
            PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() with error: %d"), aError));
            DoSendEventToClient( KCMREncoderInitError, aError );
            }
        else
            {
            // report only when source is completed too
            PRINT((_L("CCMRVideoRecorder::MdvroInitializeComplete() with error: %d, but must wait for camera reserve completion"), aError));
            iErrorCode = aError;
            }
        return;
        }

    if ( aError == KErrNone )
        {
        // If Encoder initialized Ok, give other run-time settings
        // 1. Give dynamic settings to encoder after initializing
        if ( !iVideoCodecHWAccelerated && ( iDevVideoRec->NumComplexityLevels(iEncoderHWDeviceId) > 0 ) )
            {
            iVideoComplexity = iConfig->PluginSettings().iVideoComplexitySetting;
            iDevVideoRec->SetComplexityLevel( iEncoderHWDeviceId, iVideoComplexity );
            }
        // HW codec-specific configuration is HW dependent, and hence outside the scope of Series 60

        // 2. Rate control options
        if ( iEncodingFrameRate > iMaxFrameRate4GivenSize )
            {
            iEncodingFrameRate = static_cast<TReal32>(iMaxFrameRate4GivenSize);
            }

        FillRateControlOptions( iRateControlOptions );
        iDevVideoRec->SetRateControlOptions(0, iRateControlOptions); // only base layer (layer 0) supported
        TRAPD(err,iVideoCodecData->SetPostInitParamsL(iDevVideoRec));
        if ( err ) {}
        // ignore the error, having some post init setting is not crucial

        }

    if ( iSourceInitComplete )
        {
        SetState(EStateReadyToRecord);

        // everything ok, inform observer that we are prepared.
        DoSendEventToClient( KCMRPrepareComplete, KErrNone );
        }
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MdvroReturnPicture
// Called by DevVideoRecord when it does not need the given
// input frame anymore
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MdvroReturnPicture(TVideoPicture* aPicture)
    {
#ifdef _DEBUG
    TTime current;
    current.UniversalTime();


    PRINT((_L("CCMRVideoRecorder::MdvroReturnPicture() time now\t%d"),
        (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) ));
#endif

    // take oldest frame from fifo
    VRASSERT( !iSourceFifo->IsEmpty() );// if empty, for some reason the buffer was already returned!!

    MFrameBuffer* buffer = reinterpret_cast<MFrameBuffer*>(iSourceFifo->Get());

    // check that its the oldest stored captured picture
    TPtr8* tmp = NULL;
    TRAPD(error, (tmp = static_cast<TPtr8*>(buffer->DataL(0))));
    if ( tmp != aPicture->iData.iRawData )
        {
        // pictures are returned in different order than they were sent
		RPointerArray<MFrameBuffer> buffers;
        buffers.Append(buffer);

        TUint i;
        for ( i = 1; i < iNumCameraBuffers; i++ )
            {
            buffers.Append(reinterpret_cast<MFrameBuffer*>(iSourceFifo->Get()));

            TRAP(error, (tmp = static_cast<TPtr8*>(buffers[i]->DataL(0))));
            if ( tmp == aPicture->iData.iRawData )
                {
                // Found it! Put the retrieved buffers back to the queue
                TInt err = KErrNone;
                TUint j;
                for ( j = 0; j < i; j++ )
                    {
                    TRAP( err, iSourceFifo->PutL( reinterpret_cast<TAny*>(buffers[j]) ));
                    // This can't really fail since we just got the buffers from the fifo and in that case PutL doesn't allocate anything => can't leave
                    VRASSERT( err == KErrNone );
                    buffers[j] = NULL;
                    }
                break;
                }
            }
        VRASSERT( i < iNumCameraBuffers );
        buffer = buffers[i];
        buffers.Close();
        }

    // release captured buffer
    PRINT((_L("CCMRVideoRecorder::MdvroReturnPicture() releasing %x"), buffer ));
    buffer->Release();
    buffer = NULL;

    iEncoderInputQueueLength--;


    // save the picture holder to fifo
    TRAPD( err, iCodingFifo->PutL( reinterpret_cast<TAny*>(aPicture) ));
    if ( err != KErrNone )
        {
        // OOM, inform error and stop operation
        DoSendEventToClient( KCMRRunTimeError, err );
        delete aPicture;
        return;
        }
    PRINT((_L("CCMRVideoRecorder::MdvroReturnPicture() stored %x"), aPicture ));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MdvroSupplementalInfoSent
// Called by DevVideoRecord when supplemental info (e.g.,
// VOL header) has been sent to the encoder
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MdvroSupplementalInfoSent()
    {
    PRINT((_L("CCMRVideoRecorder::MdvroSupplementalInfoSent()")));
    User::Panic(_L("CCMRVIDEORECORDER"), KErrGeneral);
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MdvroNewBuffers
// Called by DevVideoRecord when new bitstream buffers are
// available for retrieval
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MdvroNewBuffers()
    {
	PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - START - iRequestStatus: 0x%08x"), iRequestStatus ));
    PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers(), NumDataBuffers[%d]"), iDevVideoRec->NumDataBuffers() ));
    iNumberOfEncodedFrames++;

    TVideoOutputBuffer* buffer = NULL;
    for (;;)
        {
        TRAPD( err, ( buffer = iDevVideoRec->NextBufferL()));

        if ( err != KErrNone )
            {
            return;
            }
        if ( buffer == NULL )
            {
            break;
            }
/*      TInt bufferSize = buffer->iData.Length();
        TInt bufferTimeStamp = I64INT(buffer->iCaptureTimestamp.Int64());
        OstTraceExt2( TRACE_PERFORMANCE, CCMRVIDEORECORDER_MDVRONEWBUFFERS, "CCMRVideoRecorder::MdvroNewBuffers %d %d", bufferSize, bufferTimeStamp );
*/        
        // enter restricted area
        iMutexObj.Wait();
        // store
        PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers(), storing buffer: 0x%x, timestamp: high: %u low: %u"), buffer, I64HIGH(buffer->iCaptureTimestamp.Int64()),I64LOW(buffer->iCaptureTimestamp.Int64())));
        iVideoOutputBufferInputQue.AddLast(*buffer);
        iNumberOfVideoOutputBuffers++;

        // leave restricted area
        iMutexObj.Signal();
        }

    // enter restricted area
    iMutexObj.Wait();
    if ( iRequestStatus )
        {
    	PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - completing output request..." )));
        iOutputThreadHandle.RequestComplete( iRequestStatus, KErrNone );
        }
    else
        {
        // else a new request has not been issued yet
    	PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - skipping RequestComplete" )));
        }
    // leave restricted area
    iMutexObj.Signal();

	PRINT((_L("CCMRVideoRecorder::MdvroNewBuffers() - END - iRequestStatus: 0x%08x"), iRequestStatus ));
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MdvroFatalError
// Called by devVideoRecord when a fatal error has occurred
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MdvroFatalError(TInt aError)
    {
    PRINT((_L("CCMRVideoRecorder::MdvroFatalError(), error[%d]"), aError));

    // Since now don't touch DevVideo that expects only destruction from the client, otherwise panics..
    iFatalError = ETrue;

    // Cancel returning buffers to DevVideo
    iBufferReturnAO->Cancel();

    if ( iDevVideoRec )
    	{
    	delete iDevVideoRec;
    	iDevVideoRec = NULL;
    	}

    if ( State() == EStateStopping )
        {
        // error occurred while stopping => carry out the rest of stopping & inform client
        SetState( EStateReadyToRecord );
        DoSendEventToClient( KCMRRecordingComplete, aError );
        }
    else
        {
        // inform client
        DoSendEventToClient( KCMRRunTimeError, aError );
        iErrorCode = aError;
        }
    }


// ---------------------------------------------------------
// CCMRVideoRecorder::MdvroStreamEnd
// Called by devVideoRecord when all pictures have been processed
// (after InputEnd is called)
// (other items were commented in a header).
// ---------------------------------------------------------
//
void CCMRVideoRecorder::MdvroStreamEnd()
    {
    PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd() in")));

    // MdvroStreamEnd was called by devVideo without InputEnd
    VRASSERT( iInputEnd );

    // get all available buffers from devvideo
    PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd(), getting all encoded frames from DevVideo.")));                
    TVideoOutputBuffer* buffer = NULL;
    for (;;)
        {
        TRAPD( err, ( buffer = iDevVideoRec->NextBufferL()));
        if ( err != KErrNone || buffer == NULL)
            {
            break;
            }
        // enter restricted area
        iMutexObj.Wait();
        // store
        PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd(), storing buffer: 0x%x, timestamp:%d"), buffer, I64INT(buffer->iCaptureTimestamp.Int64())));                  
        iVideoOutputBufferInputQue.AddLast(*buffer);
        iNumberOfVideoOutputBuffers++;

        // leave restricted area
        iMutexObj.Signal();
        }
    
    PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd(), flushing written frames back to DevVideo.")));                
    iBufferReturnAO->Flush();    
    
    // stop
    if ( iDevVideoRec )
    	{
        PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd() iDevVideoRec->Stop called")));    	
        iDevVideoRec->Stop();
    	}

    iStreamEnd = ETrue;
    
    // set state & inform MR => it can return from stop
    SetState( EStateReadyToRecord );

    // everything ok, inform observer that we are ready for a new recording (iStopping does it too, though).
    DoSendEventToClient( KCMRRecordingComplete, KErrNone );

    PRINT((_L("CCMRVideoRecorder::MdvroStreamEnd() out")));
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::RequestNewData
// Output active object is ready to accept new data
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::RequestNewData(TRequestStatus& aStatus)
    {
	PRINT((_L("CCMRVideoRecorder::RequestNewData() - START - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus ));

    // enter restricted area
    iMutexObj.Wait();

    iRequestStatus = &aStatus;
	aStatus = KRequestPending;

    // leave restricted area
    iMutexObj.Signal();

	PRINT((_L("CCMRVideoRecorder::RequestNewData() - END - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus ));
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::RequestNewDataCancel
//
//
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::RequestNewDataCancel(TRequestStatus& aStatus)
    {
	PRINT((_L("CCMRVideoRecorder::RequestNewDataCancel() - START - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus ));

    // enter restricted area
    iMutexObj.Wait();

	if ( &aStatus == iRequestStatus )
		{
		iOutputThreadHandle.RequestComplete( iRequestStatus, KErrCancel );
		}

    // leave restricted area
    iMutexObj.Signal();

	PRINT((_L("CCMRVideoRecorder::RequestNewDataCancel() - END - aStatus: 0x%08x, iRequestStatus: 0x%08x"), &aStatus, iRequestStatus ));
	}


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::GetNextBuffer
// Output active object takes the next output buffer
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCMRMediaBuffer* CCMRVideoRecorder::GetNextBuffer()
    {
    PRINT((_L("CCMRVideoRecorder::GetNextBuffer() in") ));
    if ( iDevVideoRec == NULL || iFatalError )
        {
        // probably we have not been opened yet
        PRINT((_L("CCMRVideoRecorder::GetNextBuffer(), We have not been opened yet, or there's an error from devVideo")));
        return NULL;
        }

    if ( iDecSpecInfo )
        {
        // we have MPEG-4 decoder configuration information, it must be processed first
        PRINT((_L("CCMRVideoRecorder::GetNextBuffer() iDecSpecInfo") ));
        iRemoveHeader = ETrue;
        const TUint8* data = iDecSpecInfo->Ptr();
        iDecSpecInfoLength = iDecSpecInfo->Length();

        CCMRMediaBuffer::TBufferType decSpecType = CCMRMediaBuffer::EVideoMPEG4DecSpecInfo;
        if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264NAL )
            {// H.264 AVC NAL / GenericPayload encapsulation
            decSpecType = CCMRMediaBuffer::EVideoH264NALDecSpecInfo;
            }
        else if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264Bytestream )
            {
            decSpecType = CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo;
            }

        // wrap the relevant data to CCMRMediaBuffer; iOutputSinkBuffer can't be != NULL here since it is created in ConstructL
        iOutputSinkBuffer->Set( TPtrC8(data,iDecSpecInfoLength),
                                decSpecType,
                                iDecSpecInfoLength,
                                EFalse,
                                TTimeIntervalMicroSeconds(0) );

        PRINT((_L("CCMRVideoRecorder::GetNextBuffer() decoder specific info to sink sent")));
        return iOutputSinkBuffer;
        }

    // enter restricted area
    iMutexObj.Wait();
    if (iNumberOfVideoOutputBuffers > 0)
        {
        iOutputVideoBuffer = iVideoOutputBufferInputQue.First();

        // Remove the picture from the list
        if ( iOutputVideoBuffer != NULL )
            {
            iOutputVideoBuffer->iLink.Deque();
            iNumberOfVideoOutputBuffers--;
            }
        // leave restricted area
        iMutexObj.Signal();
        }
    else
        {
        // leave restricted area
        PRINT((_L("CCMRVideoRecorder::GetNextBuffer()returning null, leave restricted area, iNumberOfVideoOutputBuffers == 0 %x"), this));
        iMutexObj.Signal();
        return NULL;
        }

    PRINT((_L("CCMRVideoRecorder::GetNextBuffer() got [0x%x] from devvr"), iOutputVideoBuffer ));

    if ( iOutputVideoBuffer != NULL )
        {
        PRINT((_L("CCMRVideoRecorder::GetNextBuffer() processing iOutputVideoBuffer") ));
        TBool outputMediaBufferSet = EFalse;
        if ( iRemoveHeader )
            {
            // check if we need to remove VOS+VO+VOL header from the bitstream, since it is stored in metadata, and
            // having it in 2 places may cause interoperability problems
            PRINT((_L("CCMRVideoRecorder::GetNextBuffer() remove extra header info") ));
            iRemoveHeader = EFalse;
            if ( iVideoBufferType == CCMRMediaBuffer::EVideoMPEG4 )
                {// MPEG-4
                RemoveSeqHeader( reinterpret_cast<TDesC8*>(&iOutputVideoBuffer->iData) );
                }
            else if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264NAL )
                {// H.264 AVC NAL /  EDuGenericPayload / NAL encapsulation
                // Removes SPS & PPS from first frame from encoder to avoid situation where its both in
                // .mp4 file metadata and in bitstream of video track.
                // Make sure buffer contains only one frame and rewrite encapsulation to make sure its ok.
                RemoveNalDecSpecInfoHeader( reinterpret_cast<TDesC8*>(&iOutputVideoBuffer->iData) );
                outputMediaBufferSet = ETrue;
                }
            else if ( iVideoBufferType == CCMRMediaBuffer::EVideoH264Bytestream )
                {// H.264 AVC NAL /  EDuElementarystream / Bytestream
                // Removes SPS & PPS from first frame from encoder to avoid situation where its both in
                // .mp4 file metadata and in bitstream of video track.
                RemoveByteStreamDecSpecInfoHeader( reinterpret_cast<TDesC8*>(&iOutputVideoBuffer->iData) );
                outputMediaBufferSet = ETrue;
                }
            }

        if ( !outputMediaBufferSet )
        	{
            // wrap the relevant data to CCMRMediaBuffer
	        iOutputSinkBuffer->Set( iOutputVideoBuffer->iData,
									iVideoBufferType,
									iOutputVideoBuffer->iData.Length(),
									iOutputVideoBuffer->iRandomAccessPoint,
									iOutputVideoBuffer->iCaptureTimestamp );
        	}
        PRINT((_L("CCMRVideoRecorder::GetNextBuffer() iOutputSinkBuffer set") ));

#ifdef _DEBUG__
            TTime current;
            current.UniversalTime();
            TInt elapsedMs = (I64INT(current.MicroSecondsFrom(iEncodingStartTime).Int64())) / 1000;
            iCumulativeEncodingTime += elapsedMs;
            iAverageEncodingTime = TReal(iCumulativeEncodingTime) / TReal(iNumberOfEncodedFrames);


            PRINT((_L("CCMRVideoRecorder::GetNextBuffer() %d, time consumed: %d, average encoding time: %4.2f"),
                (I64INT(current.MicroSecondsFrom(iRecordStartTime).Int64())) / 1000,
                (I64INT(current.MicroSecondsFrom(iEncodingStartTime).Int64())) / 1000,
                iAverageEncodingTime));
#endif

#ifdef VIDEO_BS_FILE_OUTPUT
            // Write the frame to a file for testing purposes; have to ignore possible errors
            iOutputFile.Write(videoBuffer->iData);
#endif

        PRINT((_L("CCMRVideoRecorder::GetNextBuffer() a buffer to sink sent with timestamp high: %u low: %u"),I64HIGH(iOutputVideoBuffer->iCaptureTimestamp.Int64()),I64LOW(iOutputVideoBuffer->iCaptureTimestamp.Int64())));        
        return iOutputSinkBuffer;
        }
    else
        {
        PRINT((_L("CCMRVideoRecorder::GetNextBuffer() returning NULL - no new buffers in queue") ));
        // no more new buffers in queue
        return NULL;
        }
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::NumBuffersWaiting
// Return the number of buffers in the source
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CCMRVideoRecorder::NumBuffersWaiting()
    {
    if (iFatalError)
        {
        // NumDataBuffers() cannot be called since fatalError was reported
        return 0;
        }

    if ( iDecSpecInfo )
        {
        // decspecinfo is not counted in iNumberOfVideoOutputBuffers
        return (iNumberOfVideoOutputBuffers+1);
        }
    else
        {
        return iNumberOfVideoOutputBuffers;
        }
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::LatestTimeStampL
// Return the latest time stamp from the input stream
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::LatestTimeStampL(TTimeIntervalMicroSeconds& aTimeStamp) const
    {
    aTimeStamp = iLatestUsedTimeStamp;
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::DurationL
// Get duration of the recording (in practice the same as the latest time stamp)
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::DurationL(TTimeIntervalMicroSeconds& aDuration) const
    {
    LatestTimeStampL( aDuration );
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::ReturnBuffer
// Output active object returns an emptied buffer
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::ReturnBuffer(CCMRMediaBuffer* aBuffer)
    {
    PRINT((_L("CCMRVideoRecorder::ReturnBuffer() buffers 0x%x, 0x%x"),aBuffer, iOutputSinkBuffer));
    VRASSERT( iOutputSinkBuffer == aBuffer );

    if ( iFatalError )
        {
        PRINT((_L("CCMRVideoRecorder::ReturnBuffer(), don't return anything, since there's an error from devVideo")));
        iOutputVideoBuffer = NULL;
        return;
        }

    iOutputSinkBuffer = aBuffer;
    if ( iDecSpecInfo )
        {
        delete iDecSpecInfo;
        iDecSpecInfo = NULL;
        // iOutputVideoBuffer is not used with decspecinfo
        }
    else
        {
        // normal case; iOutputVideoBuffer != NULL if functions are called in correct order
        PRINT((_L("CCMRVideoRecorder::ReturnBuffer() iOutputVideoBuffer 0x%x"), iOutputVideoBuffer));
        VRASSERT( iOutputVideoBuffer != NULL );
        // store the buffer for sending from this thread
        iBufferReturnAO->EnqueueReturnBuffer(iOutputVideoBuffer);

        iOutputVideoBuffer = NULL;
        }
    }



// -----------------------------------------------------------------------------
// CCMRVideoRecorder::FillRateControlOptions
// Fill DevVideoRecord rate control options structure
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::FillRateControlOptions( TRateControlOptions& aRC )
    {
    TRAPD(error,CCMRRecorderBase::TargetBitRateL((TInt&)(aRC.iBitrate)));

    // error can be ignored, it will never be != KErrNone at this stage
    if (error != KErrNone)
        {
        VRASSERT( error == KErrNone );
        }

    if ( iBitRateMode == EBitRateConstant )
        {
        aRC.iControl = EBrControlStream;
        }
    else
        {
        // Variable bitrate; rc.iBitrate is probably not needed but it gives now the upper limit
        aRC.iControl = EBrControlNone;
        }

    aRC.iPictureRate = iEncodingFrameRate;
    // these are filled already in constructor:
    //aRC.iPictureQuality
    //aRC.iLatencyQualityTradeoff
    //aRC.iQualityTemporalTradeoff
    PRINT((_L("CCMRVideoRecorder::FillRateControlOptions() - framerate %f, bitrate %d"), aRC.iPictureRate, aRC.iBitrate));
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CheckExposure
// Check exposure from camera and adjust framerates if needed
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::CheckExposure()
    {
    if ( iSource->GetExposure() == CCamera::EExposureNight )
        {
        iNightMode = ETrue;
        iSourceFrameRate = iConfig->PluginSettings().iVideoNightFrameRate;
        iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);

        // new framerate should be set to the encoder too
        TRAPD(error, SetFrameRateL( iSourceFrameRate ));

        // error can be ignored, it will never be != KErrNone here
        if (error != KErrNone)
            {
            VRASSERT( error == KErrNone );
            }
        }
    else
        {
        // other modes don't affect to framerates, except if we switch back from night mode to normal
        if ( iNightMode )
            {
            iSourceFrameRate = iRequestedFrameRate;
            iSourceFrameInterval = convertFrameRateToInterval(iSourceFrameRate);

            // new framerate should be set to the encoder too
            TRAPD(error,SetFrameRateL( iSourceFrameRate ));

            // error can be ignored, it will never be != KErrNone here
            if (error != KErrNone)
                {
                VRASSERT( error == KErrNone );
                }

            iNightMode = EFalse;
            }
        }

    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::UpdateSupportedFrameSizesRates
// Update supported video frames and sizes table from ECAM and MDF encoders.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::UpdateSupportedVideoFrameSizesRates()
	{
	PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() in")));
	iAvailableVideoFrameSizesRates.Reset();

	if ( iAvailableVideoEncoders.Count() )
		{
	    for ( TInt i = 0 ; i < iAvailableVideoEncoders.Count(); i++ )
	        {
		    // encoder info for retrieving capabilities
		    CVideoEncoderInfo* encoderInfo = NULL;
	        PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() - getting info from a plugin index[%d] with Uid 0x%x"), i, iAvailableVideoEncoders[i].iUid ));
	        TRAPD(error, (encoderInfo = ReadEncoderInfoL(iAvailableVideoEncoders[i])) );

	        if ( (encoderInfo != NULL) && (error == KErrNone))
	            {
                // Check directCapture support for current codec
				if ( encoderInfo->SupportsDirectCapture() )
					{
			        // check max framerate for given picture size
			        RArray<TPictureRateAndSize> rateAndSize = encoderInfo->MaxPictureRates();
			        for ( TUint j = 0; j < rateAndSize.Count(); j++ )
			            {
			            TPictureRateAndSize newSizeRate = rateAndSize[j];
						TInt addError = iAvailableVideoFrameSizesRates.InsertInOrder(newSizeRate, TLinearOrder<TPictureRateAndSize>(TLinearOrderFuncVideoSizeRate) );
						if (addError == KErrNone)
							{
							PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() - Added size: %d x %d, rate: %f"),
																					rateAndSize[j].iPictureSize.iWidth,
																					rateAndSize[j].iPictureSize.iHeight,
																					rateAndSize[j].iPictureRate));
							}
						}
					}
				delete encoderInfo;
	            }
	        }
		}
	PRINT((_L("CCMRVideoRecorder::UpdateSupportedFrameSizesRates() out")));
	}

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::DoSendEventToClient
// Send event to client
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CCMRVideoRecorder::DoSendEventToClient(TUid aEventType, TInt aErrorCode)
    {
    PRINT((_L("CCMRVideoRecorder::DoSendEventToClient(), aEventType %d"),aEventType.iUid));
    TMMFEvent event(aEventType, aErrorCode);
    return iEventHandler.SendEventToClient(event);
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::ReturnBufferToDevVR
// CCMRReturnAO uses this function to return buffer to DevVideoRecord
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::ReturnBufferToDevVR(TVideoOutputBuffer* aBuffer)
    {
    PRINT((_L("CCMRVideoRecorder::ReturnBufferToDevVR() in buffer: 0x%x, timestamp: high: %u low: %u"), aBuffer, I64HIGH(aBuffer->iCaptureTimestamp.Int64()),I64LOW(aBuffer->iCaptureTimestamp.Int64())));
    if (iDevVideoRec)
    	{
        iDevVideoRec->ReturnBuffer(aBuffer);
    	}
    PRINT((_L("CCMRVideoRecorder::ReturnBufferToDevVR() out")));
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::RemoveSeqHeader( TDesC8* aVideoBuffer )
// RemoveSeqHeader remove MPEG4 decoder configuration info (VOS+VO+VOL header)
// from the 1st video packet (it is saved in metadata, and duplication not allowed)
// Returns: TInt number of bytes removed
// -----------------------------------------------------------------------------
//
TInt CCMRVideoRecorder::RemoveSeqHeader( TDesC8* aVideoBuffer )
    {
    // MPEG-4 VOP header == the 1st element in the buffer to not remove
    const TUint8 KHeader[4] = {0x00, 0x00, 0x01, 0xb6};
    const TUint KSampleLength = 4;

    TPtr8* buffer = reinterpret_cast<TPtr8*>(aVideoBuffer);
    // Bitstream start point
    const TUint8* data = buffer->Ptr();
    TUint headerLength;
    TBool iFound = EFalse;

    // Search for VOP start code
    for ( headerLength = 0; headerLength < (buffer->Length() - (KSampleLength - 1)); headerLength++ )
        {
        if ( (data[headerLength] == KHeader[0])
            && (data[headerLength+1] == KHeader[1])
            && (data[headerLength+2] == KHeader[2])
            && (data[headerLength+3] == KHeader[3]) )
            {
            // VOP start code is found => video data starts from here
            iFound = ETrue;
            break;
            }
        }

    if ( (headerLength > 0) && iFound )
        {
        // adjust ptr & length depending which is longer VOP header location or earlier iDecSpecInfoLength length
        if ( iDecSpecInfoLength && (iDecSpecInfoLength <= headerLength ) )
	        {
	        buffer->Delete(0,iDecSpecInfoLength);
	        }
        else
	        {
			buffer->Delete(0,headerLength);
	        }
        }
    return headerLength;
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::RemoveNalDecSpecInfoHeader( TDesC8* aVideoBuffer )
// Removes decoder configuration info (SPS & PPS) from first NAL encapsulated H.264/AVC video buffer
// from encoder to avoid situation where its both in .mp4 file metadata and in bitstream of video track.
// Makes sure buffer contains only one frame and rewrite encapsulation to make sure its ok.
// -----------------------------------------------------------------------------
//
TInt CCMRVideoRecorder::RemoveNalDecSpecInfoHeader( TDesC8* aVideoBuffer )
	{
	// H.264 AVC NAL /  EDuGenericPayload / NAL encapsulation

    // Get reference to the buffer
    TPtr8* ptr = reinterpret_cast<TPtr8*>(aVideoBuffer);
    // Bitstream start point
    TPtr8& buffer(*ptr);
    TInt frameStart = 0;
    TInt frameSize = 0;
    TInt offset = 0;
    TInt bufType = 0;
    TInt i=0;
    TInt totalNALLength = 0;
    TInt firstCopiedNAL = 0;
    TInt nalCount = 0;
    RArray<TInt> nalSizes;
    RArray<TInt> nalStarts;

    PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() in, length: %d "), buffer.Length() ));

	// There should be enough data for the NAL header + frame
    if ( buffer.Length() > 12 )
        {
        // Offset to the end and get NAL unit count
        offset = buffer.Length()-4; //last 4 bytes are the NAL unit count
        nalCount = TInt(buffer[offset]) +
                  (TInt(buffer[offset + 1]) << 8) +
                  (TInt(buffer[offset + 2]) << 16) +
                  (TInt(buffer[offset + 3]) << 24);

        for(i=0; i<nalCount; i++)
            {//go through all NAL units in buffer
            // Offset to the start of NAL Unit infos
            offset = buffer.Length()-4-(8*nalCount); // 4 is the NAL unit count at end of buffer, 8 bytes used per NAL Unit for FrameStartOffset and FrameSize.

            // Get frame start offset
            offset += 8*i;
            frameStart = TInt(buffer[offset]) +
                        (TInt(buffer[offset + 1]) << 8) +
                        (TInt(buffer[offset + 2]) << 16) +
                        (TInt(buffer[offset + 3]) << 24);

            PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() NAL unit %d frame start: %d "), i, frameStart ));

            // Get frame size
            offset += 4;
            frameSize = TInt(buffer[offset]) +
                       (TInt(buffer[offset + 1]) << 8) +
                       (TInt(buffer[offset + 2]) << 16) +
                       (TInt(buffer[offset + 3]) << 24);

           PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() NAL unit %d frame size: %d "), i, frameSize ));
           bufType = buffer[frameStart] & 0x1F;
           PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() NAL unit %d type: %d "), i, bufType ));
           if ( bufType != 7 && //SPS
                bufType != 8 )//PPS
               {
               // we found first NAL unit that isn't SPS or PPS
               nalSizes.Append(frameSize);
               if (firstCopiedNAL==0)
                   {
                   firstCopiedNAL = frameStart;
                   }
               nalStarts.Append(frameStart-firstCopiedNAL);               
               totalNALLength = frameStart+frameSize-firstCopiedNAL;
               PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() new total length: %d, padding: %d "), totalNALLength, totalNALLength%4 ));
               totalNALLength += totalNALLength%4;
               }
           }

        // The buffer should have enough space for the new NAL header

        // We need to write a new NAL header just after the frame end
        PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() writing new header.")));
        offset = firstCopiedNAL + totalNALLength;
        
        if ( (offset + nalSizes.Count()*8 + 4) > buffer.Length() ) 
            {
            PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() Fatal error, cannot create header, non-align 32bit encoder output buffer.")));
            VRASSERT(0);            
            }

        for (TInt j=0; j<nalSizes.Count(); j++)
            {
            PRINT((_L("CCMRVideoRecorder::RemoveNalDecSpecInfoHeader() new header, unit: %d, start: %d, size: %d."), j, nalStarts[j], nalSizes[j] ));            
            // Write NAL unit start position
            buffer[offset + 0] = TUint8(nalStarts[j] & 0xff);
            buffer[offset + 1] = TUint8((nalStarts[j] >> 8) & 0xff);
            buffer[offset + 2] = TUint8((nalStarts[j] >> 16) & 0xff);
            buffer[offset + 3] = TUint8((nalStarts[j] >> 24) & 0xff);

            // Write NAL unit size
            offset +=4;
            buffer[offset + 0] = TUint8(nalSizes[j] & 0xff);
            buffer[offset + 1] = TUint8((nalSizes[j] >> 8) & 0xff);
            buffer[offset + 2] = TUint8((nalSizes[j] >> 16) & 0xff);
            buffer[offset + 3] = TUint8((nalSizes[j] >> 24) & 0xff);

            offset +=4;
            }

        // Write the number of NAL units
        buffer[offset + 0] = TUint8(nalSizes.Count() & 0xff);;
        buffer[offset + 1] = TUint8((nalSizes.Count() >> 8) & 0xff);;
        buffer[offset + 2] = TUint8((nalSizes.Count() >> 16) & 0xff);
        buffer[offset + 3] = TUint8((nalSizes.Count() >> 24) & 0xff);
        }

    // Get a pointer to the position where the frame starts
    TPtrC8 tmp( (buffer.Ptr() + firstCopiedNAL), (totalNALLength + (nalSizes.Count()*8) + 4) );

    // Set output media buffer
    iOutputSinkBuffer->Set( tmp, CCMRMediaBuffer::EVideoH264NAL,
                            tmp.Length(), iOutputVideoBuffer->iRandomAccessPoint,
                            iOutputVideoBuffer->iCaptureTimestamp );

    nalSizes.Close();
    nalStarts.Close();
    return firstCopiedNAL;
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader( TDesC8* aVideoBuffer )
// Removes decoder configuration info (SPS & PPS) from first bytestream encapsulated H.264/AVC video buffer
// from encoder to avoid situation where its both in .mp4 file metadata and in bitstream of video track.
// -----------------------------------------------------------------------------
//
TInt CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader( TDesC8* aVideoBuffer )
	{// H.264 AVC NAL /  EDuElementarystream / Bytestream
    TInt skippedBytes = -1;
    TInt bufType = 0;

    // Get reference to the buffer
    TPtr8* buffer = reinterpret_cast<TPtr8*>(aVideoBuffer);
    // Bitstream start point
    const TUint8* data = buffer->Ptr();

    PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() in, length: %d "), buffer->Length() ));

    // check buffer for bytestream header and possible decSpecInfo (SPS & PPS)
    for (TInt i=0; i+4< buffer->Length(); i++)
    	{
    	// check for bytestream encapsulation [00 00 00 01]
    	if ( data[i] == 0 &&
    		 data[i+1] == 0 &&
    		 data[i+2] == 0 &&
    		 data[i+3] == 1 )
    		{
    	    PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() 0001 header at: %d "), i ));
    		// search buffer that isn't SPS or PPS
    		bufType = data[i+4] & 0x1F;
    		PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() buffer type: %d "), bufType ));
    		if ( (bufType == 7 || //SPS
    			  bufType == 8) && //PPS
    			  skippedBytes == -1 )
    		    {// we need to skip SPS and PPS so activate next if clause
    			skippedBytes = 0;
    		    }
    		if ( bufType != 7 && //SPS
                 bufType != 8 && //PPS
                 skippedBytes == 0)
    		    {// found first non SPS / PPS buffer content -> stop stripping here
    			skippedBytes = i;
    		    PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() skipping: %d bytes"), skippedBytes ));
    			}
    		}
    	}
/*
    if (skippedBytes)
        {
        for (TInt j=0; j<skippedBytes;j++)
            {
            PRINT((_L("CCMRVideoRecorder::RemoveByteStreamDecSpecInfoHeader() skipping %d: %x "), j, data[j] ));
            }
        }
*/
    // Get a pointer to the position where the frame starts
    TPtrC8 tmp(buffer->Ptr() + skippedBytes, buffer->Length() - skippedBytes);

    // Set output media buffer
    iOutputSinkBuffer->Set( tmp, CCMRMediaBuffer::EVideoH264Bytestream,
                            tmp.Length(), iOutputVideoBuffer->iRandomAccessPoint,
                            iOutputVideoBuffer->iCaptureTimestamp );

    return skippedBytes;
	}

// ---------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::NewL
// Two-phased constructor.
// ---------------------------------------------------------
//
CCMRVideoRecorder::CCMRReturnAO* CCMRVideoRecorder::CCMRReturnAO::NewL(CCMRVideoRecorder* aHost)
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::NewL(), In")))

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

    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::NewL(), Out")))
    return self;
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::CCMRReturnAO
// Default constructor for CCMRReturnAO
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCMRVideoRecorder::CCMRReturnAO::CCMRReturnAO(CCMRVideoRecorder* aHost) :
        CActive(EPriorityNormal),
        iVideoOutputBufferReturnQue(_FOFF(TVideoOutputBuffer,iLink)),
        iVideoOutputBufferReturnQueIter(iVideoOutputBufferReturnQue),
        iHost(aHost)
    {
    CActiveScheduler::Add(this);
    }

// ---------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::ConstructL()
// Symbian 2nd phase constructor can leave.
// ---------------------------------------------------------
//
void CCMRVideoRecorder::CCMRReturnAO::ConstructL()
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::ConstructL() in")));
    User::LeaveIfError(iMutexObj.CreateLocal());
    iMutexCreated = ETrue;
    User::LeaveIfError(iVideoThreadHandle.Open(RThread().Id()));
    iThreadHandleOpened = ETrue;

    iStatus = KRequestPending;
    SetActive();
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::ConstructL() out")));
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::~CCMRReturnAO
// Destructor for CCMRReturnAO
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CCMRVideoRecorder::CCMRReturnAO::~CCMRReturnAO()
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::~CCMRReturnAO")));
    if ( iMutexCreated )
        {
        iMutexObj.Close();
        }
    if ( iThreadHandleOpened )
        {
        iVideoThreadHandle.Close();
        }
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer
// Enqueue TVideoOutputBuffer from controller thread to be returned to
// DevVideoRecord from this thread
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer(TVideoOutputBuffer* aBuffer)
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer() in aBuffer=0x%x "), aBuffer));
    // enter restricted area
    iMutexObj.Wait();
    iVideoOutputBufferReturnQue.AddLast(*aBuffer);
    if ( iStatus == KRequestPending )
        {
        TRequestStatus* tmp = &iStatus;
        iVideoThreadHandle.RequestComplete(tmp, KErrNone);
        }
    // leave restricted area
    iMutexObj.Signal();
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::EnqueueReturnBuffer() out")));
    }


// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::Flush
// Flush content of return queueu to DevVideo
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::CCMRReturnAO::Flush()
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::Flush() in.")));
    iMutexObj.Wait();
    while (!iVideoOutputBufferReturnQue.IsEmpty())
        {
        // take the oldest buffer
        TVideoOutputBuffer* tmp = iVideoOutputBufferReturnQue.First();
        // Remove the picture from the list
        tmp->iLink.Deque();
        // send it to DevVR using the CCMRVideoRecorder object
        iHost->ReturnBufferToDevVR(tmp);
        tmp = NULL;
        }
    // leave restricted area
    iMutexObj.Signal();
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::Flush() out")));
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::RunL
// Returns the queued buffers
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::CCMRReturnAO::RunL()
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunL() - iStatus: %d"), iStatus.Int() ));
    SetActive();
    // enter restricted area
    iMutexObj.Wait();
    iStatus = KRequestPending;
    while (!iVideoOutputBufferReturnQue.IsEmpty())
        {
        // take the oldest buffer
        TVideoOutputBuffer* tmp = iVideoOutputBufferReturnQue.First();
        // Remove the picture from the list
        tmp->iLink.Deque();
        // send it to DevVR using the CCMRVideoRecorder object
        iHost->ReturnBufferToDevVR(tmp);
        tmp = NULL;
        }
    // leave restricted area
    iMutexObj.Signal();
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunL() out")));
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::RunError
// Handles errors from RunL
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TInt CCMRVideoRecorder::CCMRReturnAO::RunError(TInt aError)
    {
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunError")));
    // currently RunL can't leave, but keep this here to remind the possible need in the future
    if (aError != KErrNone)
        {
        PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::RunError() error %d"),aError));
        }
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CCMRVideoRecorder::CCMRReturnAO::DoCancel
// Cancels the active object
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CCMRVideoRecorder::CCMRReturnAO::DoCancel()
    {
    // Cancel the request
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::DoCancel() in")));
    if ( iStatus == KRequestPending )
        {
        TRequestStatus *stat = &iStatus;
        User::RequestComplete(stat, KErrCancel);
        }
    PRINT((_L("CCMRVideoRecorder::CCMRReturnAO::DoCancel() out")));
    }

// End of file