multimediacommscontroller/mmccfilesourcesink/src/mccfilevideo.cpp
changeset 0 1bce908db942
child 12 91f50911ea81
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccfilesourcesink/src/mccfilevideo.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,716 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+*
+*/
+
+
+
+
+#include <e32std.h>
+#include <es_sock.h>
+#include <e32math.h>
+#include "mccfilevideo.h"
+#include "mmcccodecinformation.h"
+#include "mccperiodicrunner.h"
+#include "mccfilesourcelogs.h"
+#include "mccfilesourceimpl.h"
+#include "mccinternaldef.h"
+#include "mccresources.h"
+
+
+const TUint32 KMccFileSourceParameterSetsIntervalInMicroSeconds = 2000000;
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::NewL
+// -----------------------------------------------------------------------------
+//
+CMccFileVideo* CMccFileVideo::NewL( 
+    CMccFileSourceImpl& aSource, 
+    MMccResources* aMccResources,
+    TUint32 aEndpointId )
+	{
+	CMccFileVideo* self = 
+        new (ELeave) CMccFileVideo( aSource, aMccResources, aEndpointId );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CMccFileVideo::ConstructL()
+	{
+	CMccFileSourceTypeBase::ConstructL();
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::CMccFileVideo
+// -----------------------------------------------------------------------------
+//
+CMccFileVideo::CMccFileVideo( 
+    CMccFileSourceImpl& aSource, MMccResources* aMccResources, TUint32 aEndpointId )
+	: CMccFileSourceTypeBase ( aSource, KUidMediaTypeVideo ),
+	  iMccResources( aMccResources ),
+	  iEndpointId( aEndpointId ),
+	  iBufferType ( CCMRMediaBuffer::EVideoH263 )
+	{
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::~CMccFileVideo
+// -----------------------------------------------------------------------------
+//
+CMccFileVideo::~CMccFileVideo()
+	{
+	delete iAVCNALUsBuffer;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::FillBufferL
+// -----------------------------------------------------------------------------
+//
+void CMccFileVideo::FillBufferL( 
+    CMMFBuffer* aBuffer,
+    MDataSink* aConsumer )
+	{
+	CMccFileSourceTypeBase::FillBufferL( aBuffer, aConsumer );
+	
+	// There might be pending video frames, read the oldest one immediately
+	WriteBufferL();
+	}
+		
+// -----------------------------------------------------------------------------
+// CMccFileVideo::ParseUpdateAudioDescriptions
+// -----------------------------------------------------------------------------
+//
+TBool CMccFileVideo::ParseUpdateVideoDescriptions( MP4Handle aMP4Handle )
+	{
+	TBool containVideo = EFalse;
+	mp4_u32 timeScale = 0;
+	if ( MP4ParseRequestVideoDescription( aMP4Handle,
+		 ( mp4_u32* ) &iLength,  &iFrameRate, ( mp4_u32* ) &iType,
+	 	 ( mp4_u32* ) &iWidth,  ( mp4_u32* ) &iHeight,
+         ( mp4_u32* ) &timeScale ) 
+         == MP4_OK )
+		{
+		if ( iType == MP4_TYPE_H263_PROFILE_0 )
+		    {
+		    __FILESOURCE_CONTROLL( "CMccFileVideo::ParseUpdateVideoDescriptions \
+MP4_TYPE_H263_PROFILE_0" )
+
+		    iBufferType = CCMRMediaBuffer::EVideoH263;
+		    containVideo = ETrue;
+		    iFourCC = TFourCC( KMccFourCCIdH263 );
+
+            TVideoClipProperties clipProperties;
+        	MP4ParseGetVideoClipProperties( aMP4Handle, clipProperties );
+        	iLevel = clipProperties.iH263Level;
+		    }
+		else if ( iType == MP4_TYPE_MPEG4_VIDEO )
+		    {
+		    __FILESOURCE_CONTROLL( "CMccFileVideo::ParseUpdateVideoDescriptions \
+MP4_TYPE_MPEG4_VIDEO!" )
+
+		    iBufferType = CCMRMediaBuffer::EVideoH263;
+		    containVideo = ETrue;
+		    iFourCC = TFourCC( KMccFourCCIdAVC );
+		    }
+		else if ( IsAVC() )
+		    {
+		    __FILESOURCE_CONTROLL( "CMccFileVideo::\
+ParseUpdateVideoDescriptions AVC!" )
+
+		    iBufferType = CCMRMediaBuffer::EVideoH263;
+		    containVideo = ETrue;
+		    iFourCC = TFourCC( KMccFourCCIdAVC );
+		    iIsFirstFrame = ETrue;
+		    iInsertParameterSets = ETrue;
+		    }
+		else if ( iType != MP4_TYPE_NONE )
+		    {
+		    __FILESOURCE_CONTROLL( "CMccFileVideo::\
+ParseUpdateVideoDescriptions contains unsupported video" )
+		    iFourCC = TFourCC( KMccFourCCUnsupported );
+		    }
+		else
+		    {
+		    // NOP
+		    }
+		}
+        
+	return containVideo;	
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::IsAVC
+// -----------------------------------------------------------------------------
+//
+TBool CMccFileVideo::IsAVC()
+	{
+	if ( ( iType == MP4_TYPE_AVC_PROFILE_BASELINE ) ||
+         ( iType == MP4_TYPE_AVC_PROFILE_MAIN )	 ||
+         ( iType == MP4_TYPE_AVC_PROFILE_EXTENDED )
+       )
+	    {
+	   	return ETrue;
+	    }
+    
+    return EFalse;	
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileVideo::DoSetPositionL
+// -----------------------------------------------------------------------------
+//
+void CMccFileVideo::DoSetPositionL( TUint32 aPosition )
+	{
+	__FILESOURCE_CONTROLL( "CMccFileVideo::DoSetPositionL" )
+
+    __ASSERT_ALWAYS( aPosition <= iLength, User::Leave( KErrArgument ) );
+    mp4_u32 audioPos = 0;
+    // if retrun value is MP4_OK, iPosition is updated
+    if ( MP4ParseSeek( iMP4Handle, ( mp4_u32 ) aPosition,
+         ( mp4_u32* )&audioPos, ( mp4_u32* ) &iPosition, MP4TRUE )
+        != MP4_OK )
+	    {
+	   	User::Leave( KErrGeneral );
+	    }
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::Type
+// -----------------------------------------------------------------------------
+//
+CCMRMediaBuffer::TBufferType CMccFileVideo::Type()
+	{
+	return iBufferType;	
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::GetFourCC
+// -----------------------------------------------------------------------------
+//
+TFourCC CMccFileVideo::GetFourCC()
+	{
+	return iFourCC;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::TickCallBack
+// -----------------------------------------------------------------------------
+//
+TCallBack CMccFileVideo::TickCallBack()
+    {
+    return TCallBack( TickVideoL, this );
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::GetConfigKeyL
+// -----------------------------------------------------------------------------
+//
+HBufC8* CMccFileVideo::GetConfigKeyL()
+    {
+    __ASSERT_ALWAYS( IsAVC(), User::Leave( KErrNotSupported ) );
+    HBufC8* configKey = NULL;
+    ExtractH264ParameterSetNALUsL( &configKey, ETrue );
+    return configKey;
+    }
+    
+// -----------------------------------------------------------------------------
+// CMccFileVideo::Position
+// -----------------------------------------------------------------------------
+//
+TUint32 CMccFileVideo::Position()
+	{
+	return iPosition;
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileVideo::DurationL
+// -----------------------------------------------------------------------------
+//
+TUint32 CMccFileVideo::Duration()
+	{
+	return iLength;	
+	}
+	
+// -----------------------------------------------------------------------------
+// CMccFileVideo::AudioBitRateL
+// -----------------------------------------------------------------------------
+//
+TUint32 CMccFileVideo::AudioBitRate()
+	{
+    return 0;
+	}
+
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::VideoFrameSizeL
+// -----------------------------------------------------------------------------
+//
+TSize CMccFileVideo::VideoFrameSize()
+	{
+	TSize size;
+	size.iWidth = iWidth;
+	size. iHeight = iHeight;
+	
+	return size;	
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::VideoFrameRateL
+// -----------------------------------------------------------------------------
+//
+TReal CMccFileVideo::VideoFrameRateL()
+	{
+	// Round to have zero decimals for clearness sake
+	TReal roundedFrameRate;
+	User::LeaveIfError( Math::Round( roundedFrameRate, iFrameRate, 0 ) );
+    return roundedFrameRate;	
+	}
+ 
+// -----------------------------------------------------------------------------
+// CMccFileVideo::StartTimerL
+// -----------------------------------------------------------------------------
+//                     
+void CMccFileVideo::StartTimerL()        
+	{
+	__FILESOURCE_CONTROLL( "CMccFileVideo::StartTimerL" )
+
+	if ( IsPaused() )
+	    {
+	    SetPaused( EFalse );
+	    
+	    SetPositionL( iPosition, ETrue );
+	    }
+	else
+	    {
+	    SetStartTime();
+	    }
+	    
+	const TReal KMccSecondInMicroSeconds = 1000000;
+	TInt tickIntervalVideo = (TInt)KMccSecondInMicroSeconds;
+    if ( iFrameRate != 0 )
+        {
+        // Set interval for video
+        tickIntervalVideo = (TInt)( KMccSecondInMicroSeconds / iFrameRate ); 
+        
+        // Increase tick rate 22%
+        const TReal KMccTickModifier = 0.78;
+        tickIntervalVideo =(TInt) (tickIntervalVideo * KMccTickModifier);
+        }
+	
+	__FILESOURCE_CONTROLL_INT1( "CMccFileVideo::StartTimer (timer):", 
+                                tickIntervalVideo )
+    
+    iTimerInterval = tickIntervalVideo;
+    iCorrectionInterval = iTimerInterval;
+                            
+	iPeriodicRunner->Start( tickIntervalVideo, TCallBack( TickVideoL, this ));	
+	
+	__FILESOURCE_CONTROLL( "CMccFileVideo::StartTimerL, exit" )
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::TickVideoL
+// -----------------------------------------------------------------------------
+//
+TInt CMccFileVideo::TickVideoL( TAny* aObject )
+	{
+	__FILESOURCE_CONTROLL( "CMccFileVideo::TickVideoL" )
+	
+	static_cast<CMccFileVideo*>(aObject)->ReadFrameL();
+	return KErrNone;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::ReadFrameL
+// -----------------------------------------------------------------------------
+// 
+void CMccFileVideo::ReadFrameL()
+	{
+	__FILESOURCE_CONTROLL( "CMccFileVideo::ReadFrameL" )
+	
+        
+    MP4Err retval = MP4ParseIsFrameAvailable( iMP4Handle, iType );
+    
+  	if (  retval != MP4_OK )
+	  	{
+	    __FILESOURCE_CONTROLL_INT1( "CMccFileVideo::ReadFrameL, no video", retval )
+
+		SetPaused( ETrue );
+		TRAPD( positionErr, SetPositionL( 0 ) );
+		iSource.PauseVideoL( positionErr );	
+        return;
+	  	}
+    
+    // Read the size of next video frame
+  	__FILESOURCE_CONTROLL( "CMccFileVideo::ReadFrameL, reading frame" ) 
+   
+    if ( MP4ParseNextFrameSize( iMP4Handle, iType,
+        ( mp4_u32* ) &iBufferSize ) != MP4_OK )
+	    {
+	    __FILESOURCE_CONTROLL( "CMccFileVideo::ReadFrameL, \
+MP4ParseNextFrameSize not Ok" ) 
+        return;
+	    }
+    
+    TInt aVCNALUsBufferLen = 0;
+    if ( IsAVC() && iIsFirstFrame )
+    	{
+    	delete iAVCNALUsBuffer;
+	    iAVCNALUsBuffer = NULL;	
+
+    	ExtractH264ParameterSetNALUsL( &iAVCNALUsBuffer );
+    	if( iAVCNALUsBuffer )
+	    	{
+	    	aVCNALUsBufferLen += iAVCNALUsBuffer->Length();	
+	    	}
+    	iIsFirstFrame = EFalse;
+    	}
+    	
+    // Allocate a buffer big enough for the next video frame
+  	__FILESOURCE_CONTROLL_INT1( "CMccFileVideo::ReadFrameL, reading frame, size", iBufferSize )
+    HBufC8* mediaBuffer = HBufC8::NewLC( iBufferSize + aVCNALUsBufferLen );
+    TPtr8 mediaSinkBuffer = mediaBuffer->Des();
+    mediaSinkBuffer.SetLength( iBufferSize + aVCNALUsBufferLen );
+    TUint8* ptrMediaBuffer = CONST_CAST(TUint8*, mediaBuffer->Ptr());
+
+    TBool keyFrame = EFalse;
+    
+    TUint32 oldPosition = iPosition;
+    if ( MP4ParseReadVideoFrame( iMP4Handle,
+        ( mp4_u8* ) ptrMediaBuffer, ( mp4_u32 ) iBufferSize,
+        ( mp4_u32* ) &iFrameSize, ( mp4_u32* ) &iPosition,
+        ( mp4_bool* ) &keyFrame, NULL ) != MP4_OK )
+		{
+		__FILESOURCE_CONTROLL( "CMccFileVideo::ReadFrameL, reading frame, NOT OK" )
+		CleanupStack::PopAndDestroy( mediaBuffer );
+        }
+    else
+    	{
+ 		__FILESOURCE_CONTROLL_INT1( "CMccFileVideo::ReadFrameL, reading frame, OK, position", 
+ 		                            iPosition )   		
+
+        DoTimingCorrection( iPosition );
+               
+        // Update read interval (how much position changes on each frame read)
+        iReadInterval = iPosition - oldPosition;
+               
+        if ( IsAVC() )
+	        {
+	        MarkWithNALUDelimiters( iBufferSize, mediaSinkBuffer );
+	    	}
+
+        TTimeIntervalMicroSeconds timeStamp = GetTimeStamp();
+        
+        CMccFrameItem* item = new (ELeave) CMccFrameItem();
+        item->iFrame = mediaBuffer;
+        CleanupStack::Pop( mediaBuffer );
+        CleanupStack::PushL( item );
+        item->iTimeStamp = timeStamp;
+        item->iKeyFrame = keyFrame;
+        iFrames.AppendL( item );
+        CleanupStack::Pop( item );
+        
+        WriteBufferL();
+		}
+    
+    __FILESOURCE_CONTROLL( "CMccFileVideo::ReadFrameL, Time Check 2" )    		
+
+  	__FILESOURCE_CONTROLL( "CMccFileVideo::ReadFrameL, \
+writing buffer to sink complete" ) 		
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::MarkWithNALUDelimiters()
+// -----------------------------------------------------------------------------
+//
+void CMccFileVideo::MarkWithNALUDelimiters( 
+	const TInt aAccessUnitSize, TDes8& aBuffer )
+	{
+    __FILESOURCE_CONTROLL( "CMccFileVideo::MarkWithNALUDelimiters" )
+    
+    TUint8* ptrByte = NULL;
+    TInt indx = 0;
+    TUint32 size;
+    const TUint32 size_field_len = 4;
+    
+    do
+	    {
+    	ptrByte = const_cast<TUint8*> ( aBuffer.Mid( indx ).Ptr() );	// get starting point of NALU size
+    	size = BigEndian::Get32(ptrByte);	// get NALU size
+    	aBuffer[indx+0] = 0x00;
+    	aBuffer[indx+1] = 0x00;
+    	aBuffer[indx+2] = 0x00;
+    	aBuffer[indx+3] = 0x01;
+    	indx = indx + size + size_field_len;
+    	
+	    }while(indx < aAccessUnitSize);
+    
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::ExtractH264ParameterSetNALUsL()
+// -----------------------------------------------------------------------------
+//
+void CMccFileVideo::ExtractH264ParameterSetNALUsL( 
+    HBufC8** aBufferOut, 
+    TBool aSdpFormat )
+	{
+	__FILESOURCE_CONTROLL( "CMccFileVideo::ExtractH264ParameterSetNALUsL" )
+	
+	*aBufferOut = NULL;
+	
+	HBufC8* buffer = NULL;
+	HBufC8* bufferOut = NULL;
+	TUint32 decspecinfosize;
+	TUint8* ptrByte;
+	
+	// Query for size, buffer too small error is ok as we give zero length buffer
+	MP4Err retval = MP4ParseReadVideoDecoderSpecificInfo( 
+	    iMP4Handle, ( mp4_u8* ) NULL, 0, ( mp4_u32* ) &decspecinfosize );
+	    
+	if ( retval != MP4_OK && retval != MP4_BUFFER_TOO_SMALL )
+		{
+		User::Leave(KErrGeneral);
+		}
+	
+	buffer = HBufC8::NewLC(decspecinfosize);
+	ptrByte = const_cast<TUint8*> ( buffer->Des().Ptr() );
+	
+	if( MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle,
+											  ( mp4_u8* ) ptrByte,
+											  ( mp4_u32 ) buffer->Des().MaxSize(),
+											  ( mp4_u32* ) &decspecinfosize
+											 ) != MP4_OK )
+		{
+		User::Leave(KErrGeneral);
+		}
+	else
+		{
+		buffer->Des().SetLength( decspecinfosize );
+		}
+	    
+	const TUint two = 2;
+	bufferOut = HBufC8::NewLC( buffer->Size() * two );
+	TPtr8 ptrBufferOut = bufferOut->Des();
+	TPtr8 ptrBuffer = buffer->Des();
+	    
+	// find NALUs in decoder info and put in buffer by marking with delimiters
+	
+	TUint8 tmpByte;
+	TUint16 size16;
+	TInt indx = 5;		// skip other info in the beginning
+	TInt numNALUs = 0;
+	TInt lp_indx;
+	
+	// get number of seq. parameter set NALUs
+	tmpByte = ptrBuffer[indx++];
+	numNALUs = tmpByte & 0x1F;		// get rid of reserved '111' bits
+	
+	// extract seq. parameter set NALUs
+	
+	for ( lp_indx = 0; lp_indx < numNALUs; lp_indx++ )
+		{
+		size16 = BigEndian::Get16( ptrBuffer.Mid( indx ).Ptr() );
+		indx += 2;
+		
+		if ( aSdpFormat )
+		    {
+		    // TBD: take possibility of multiple nalus into account
+		    HBufC8* base64Encoded = 
+		        MccConversionUtility::Base64EncodeLC( ptrBuffer.Mid( indx, size16 ) ); 
+		    ptrBufferOut.Append( *base64Encoded );
+		    CleanupStack::PopAndDestroy( base64Encoded );
+    		}
+        else
+            {
+            // insert delimiter
+    		tmpByte = 0x00;
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		tmpByte = 0x01;
+    		ptrBufferOut.Append( &tmpByte, 1 );
+
+    		ptrBufferOut.Append( ptrBuffer.Mid( indx, size16 ) );
+	    	}
+	    	
+		indx  += size16;
+		}
+	
+	// get number of pic. parameter set NALUs
+	tmpByte = ptrBuffer[indx++];
+	numNALUs = tmpByte;
+	
+	// extract pic. parameter set NALUs
+	
+	for ( lp_indx = 0; lp_indx < numNALUs; lp_indx++ )
+		{
+		size16 = BigEndian::Get16( ptrBuffer.Mid( indx ).Ptr() );
+		indx += 2;
+		
+		if ( aSdpFormat )
+		    {
+		    // TBD: take possibility of multiple nalus into account
+		    _LIT8( KMccFileSinkNaluSeparator, "," );
+		    ptrBufferOut.Append( KMccFileSinkNaluSeparator );
+		    HBufC8* base64Encoded = 
+		        MccConversionUtility::Base64EncodeLC( ptrBuffer.Mid( indx, size16 ) ); 
+		    ptrBufferOut.Append( *base64Encoded );
+		    CleanupStack::PopAndDestroy( base64Encoded );
+    		}
+        else
+            {
+    		// insert delimiter
+    		tmpByte = 0x00;
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		tmpByte = 0x01;
+    		ptrBufferOut.Append( &tmpByte, 1 );
+    		
+    		ptrBufferOut.Append( ptrBuffer.Mid( indx, size16 ) );
+            }
+		
+		indx  += size16;
+		}
+	
+	CleanupStack::Pop( bufferOut );	
+	CleanupStack::PopAndDestroy( buffer );
+	
+	*aBufferOut = bufferOut;
+	
+	__FILESOURCE_CONTROLL( "CMccFileVideo::ExtractH264ParameterSetNALUsL, exit" )
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::InsertParameterSetNALUs
+// -----------------------------------------------------------------------------
+//
+TBool CMccFileVideo::InsertParameterSetNALUs()
+    {
+    TBool insertParameterSets( iInsertParameterSets );
+    if ( insertParameterSets )
+        {
+        iInsertParameterSets = EFalse;
+        iInsertParameterSetsTime.HomeTime();
+        }
+    else
+        {
+        TTime currentTime;
+        currentTime.HomeTime();
+        if ( currentTime.MicroSecondsFrom( iInsertParameterSetsTime ).Int64() > 
+                KMccFileSourceParameterSetsIntervalInMicroSeconds )
+            {
+            // Enough time elapsed from previous parameter set NALUs,
+            // insert them at next round.
+            iInsertParameterSets = ETrue;
+            }
+        }
+    return insertParameterSets;
+    }
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::GetTimeStamp
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CMccFileVideo::GetTimeStamp()
+	{
+    TInt64 position = iPosition + iPositionModifier;
+    TUint32 position2 = ( position < 0 ) ? 0 : (TUint32)position;
+	TTimeIntervalMicroSeconds timeStamp = 
+	    TTimeIntervalMicroSeconds ( (TInt64) position2 * KMccMicroToMilliConst );
+   	
+   	__FILESOURCE_CONTROLL_INT1( "CMccFileVideo::GetTimeStamp timestamp (without clock frequency):", 
+                                timeStamp.Int64() )
+   	return timeStamp;
+	}
+
+// -----------------------------------------------------------------------------
+// CMccFileVideo::WriteBufferL
+// If AVC NALUS buffer exists, it is passed always before keyframe and it uses
+// timestamp of that frame. It is also passed always at beginning even if first
+// frame wouldn't be keyframe.
+// -----------------------------------------------------------------------------
+//
+void CMccFileVideo::WriteBufferL()
+    {
+    __FILESOURCE_CONTROLL("CMccFileVideo::WriteBufferL")
+    
+    if ( iFrames.Count() && iConsumer && iConsumerBuffer )
+	    {
+	    TBool removeCurrentFrame( ETrue );
+	    
+        CMMFDataBuffer* buf = static_cast<CMMFDataBuffer*>(iConsumerBuffer); 		
+
+        CMccFrameItem* item = iFrames[0];
+        HBufC8* videoFrame = item->iFrame;
+        
+        if ( iAVCNALUsBuffer && InsertParameterSetNALUs() )
+            {
+            videoFrame = iAVCNALUsBuffer;
+            removeCurrentFrame = EFalse;
+            }
+        
+	    if ( buf->Data().MaxLength() >= videoFrame->Des().Length() )
+		    {   
+		    buf->Data().Delete( 0, buf->BufferSize() );
+            	
+			buf->Data().Append( *videoFrame );	
+			
+			iConsumerBuffer->SetTimeToPlay(item->iTimeStamp);
+			iConsumerBuffer->SetLastBuffer(EFalse);
+			iConsumerBuffer->SetFrameNumber( iSequenceNum );
+			
+			if ( removeCurrentFrame )
+			    {
+		        if ( iMccResources && item->iKeyFrame )
+		            {
+		            iMccResources->StoreKeyFrameInfoL( iEndpointId, *iConsumerBuffer );
+		            }
+		         
+			    delete item;
+    			iFrames.Remove(0);
+			    }
+
+			videoFrame = NULL;
+		
+			iConsumer->BufferFilledL( iConsumerBuffer );
+			iConsumer = NULL;
+			iConsumerBuffer = NULL;
+			iSequenceNum++;
+			__FILESOURCE_CONTROLL("CMccFileVideo::WriteBufferL, done")
+		    }
+		else
+			{
+			__FILESOURCE_CONTROLL("CMccFileVideo::WriteBufferL, drop frame")
+			delete iFrames[0];
+			iFrames.Remove(0);
+			videoFrame = NULL;
+			}
+	    }
+	else
+	    {
+	    __FILESOURCE_CONTROLL("CMccFileVideo::WriteBufferL, writing ignored")
+	    }
+    }
+
+