camcordermmfplugin/mediarecorder/Src/CCMRMDFVideoRecorder.cpp
changeset 0 9b3e960ffc8a
child 1 2d3e1993fb02
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/camcordermmfplugin/mediarecorder/Src/CCMRMDFVideoRecorder.cpp	Thu Dec 17 08:51:24 2009 +0200
@@ -0,0 +1,4238 @@
+/*
+* 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() ));
+            }
+        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
+        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