multimediacommscontroller/mmccavcpayloadformat/src/avcpayloadformatwrite.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccavcpayloadformat/src/avcpayloadformatwrite.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,585 @@
+/*
+* Copyright (c) 2005 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:    AVC Payload Format Write .. Payloadizes incoming frames into RTP packets
+*
+*/
+
+
+
+
+
+
+// INCLUDE FILES
+#include <e32base.h>
+#include <mmf/common/mmffourcc.h>
+#include <sysutil.h>
+#include "avcpayloadformatwrite.h"
+#include "mccrtpdatasink.h"
+#include "mccinternaldef.h"
+#include "mmcccodecavc.h"
+#include "avcpayloadformatlogs.h"
+
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::CAvcPayloadFormatWrite
+//
+// CAvcPayloadFormatWrite default constructor, can NOT contain any code,
+// that might leave
+// Phase #1 of 2-phase constructor
+// -----------------------------------------------------------------------------
+//
+CAvcPayloadFormatWrite::CAvcPayloadFormatWrite ( )
+    {
+    iFrameTimeInterval = 0;
+    iSourceBuffer = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::NewL
+//
+// Two-phased constructor.
+// Static function for creating and constructing an instance of the AVC formatter.
+//
+// Returns:  CAvcPayloadFormatWrite* : pointer to created instance
+// -----------------------------------------------------------------------------
+//
+CAvcPayloadFormatWrite* CAvcPayloadFormatWrite::NewL( MDataSink* aSink )
+    {
+    CAvcPayloadFormatWrite* self = new ( ELeave ) CAvcPayloadFormatWrite;
+    CleanupStack::PushL( self );
+    self->ConstructL( aSink );
+    CleanupStack::Pop();
+    return self;
+    }
+    
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::ConstructL
+//
+// Symbian 2nd phase constructor can leave.
+// Phase #2 of 2-phase constructor
+// Initializes the Encoder State Machine and Encoder
+// Parameters:
+//  aSink				:	data sink
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::ConstructL( MDataSink* aSink )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ConstructL")
+    
+    __ASSERT_ALWAYS( aSink, User::Leave ( KErrArgument ) );
+    
+	// Set data sink
+    iClip = aSink;
+      
+    iIsRtpSink = ( KMccRtpSinkUid == iClip->DataSinkType() );
+
+    // Initialize state machine
+    iStateMachine = CFormatEncodeStateMachine::NewL( this );
+    iStateMachine->ChangeState( EEncodeIdle );
+    iCurDataSink = aSink;
+    
+    iEncoder = CRFC3984Encode::NewL();
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ConstructL, exit")
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::~CAvcPayloadFormatWrite
+//
+// Destructor.
+// -----------------------------------------------------------------------------
+//
+CAvcPayloadFormatWrite::~CAvcPayloadFormatWrite ( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::~CAvcPayloadFormatWrite")
+    
+    delete iSourceBuffer;
+    delete iSinkBuffer;
+    delete iStateMachine;
+    delete iEncoder;
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::~CAvcPayloadFormatWrite, exit")
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SetPayloadType
+// Set PayloadType
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SetPayloadType( TUint8 aPayloadType )
+    {
+	iCInfo.iPayloadType = aPayloadType;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::FrameTimeInterval
+//
+// Return the frame time interval for the given media
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CAvcPayloadFormatWrite::FrameTimeInterval( TMediaId aMediaId ) const
+    {
+    if ( aMediaId.iMediaType == KUidMediaTypeVideo )
+        {
+        return iFrameTimeInterval;
+        }
+    else
+        {
+        return TTimeIntervalMicroSeconds( 0 );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::CreateSinkBufferL
+//
+// Create a source buffer for the given media and indicate in aReference if buffer
+// is created.
+// -----------------------------------------------------------------------------
+//
+CMMFBuffer* CAvcPayloadFormatWrite::CreateSinkBufferL( TMediaId aMediaId, 
+                                                       TBool &aReference )
+    {
+  
+    if ( aMediaId.iMediaType != KUidMediaTypeVideo )
+        {
+        User::Leave( KErrNotSupported );
+        }
+	
+    aReference = ETrue;
+   	return CreateSinkBufferOfSizeL( iCInfo.iFrameSize );
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::CreateSinkBufferOfSizeL
+//
+// Create a sink buffer of the given size.
+// -----------------------------------------------------------------------------
+//
+CMMFDataBuffer* CAvcPayloadFormatWrite::CreateSinkBufferOfSizeL( TUint aSize )
+    {
+	// the buffer is created once and the component retains ownership in order to delete the resource
+
+	if(NULL == iSourceBuffer)
+	    {
+		//needs to create source buffer
+		iSourceBuffer = CMMFDataBuffer::NewL( aSize );
+		iSourceBuffer->Data().FillZ( aSize );
+		iSourceBuffer->SetRequestSizeL( aSize );
+	    }
+	
+    return iSourceBuffer;
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkDataTypeCode
+//
+// Return the sink data type ( four CC code ) for the given media
+// -----------------------------------------------------------------------------
+//
+TFourCC CAvcPayloadFormatWrite::SinkDataTypeCode( TMediaId aMediaId )
+    {
+    if ( aMediaId.iMediaType == KUidMediaTypeVideo ) 
+        {
+        return iCInfo.iFourCC;
+        }
+    else 
+        {
+        return TFourCC( ); //defaults to 'NULL' fourCC
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SetSinkDataTypeCode
+//
+// Set the sink data type to the given four CC code for the given media
+// -----------------------------------------------------------------------------
+//
+TInt CAvcPayloadFormatWrite::SetSinkDataTypeCode( TFourCC aSinkFourCC, 
+                                                  TMediaId aMediaId )
+    {
+    if ( aMediaId.iMediaType != KUidMediaTypeVideo )
+        {
+        return KErrNotSupported;
+        }
+    else 
+        {
+        iCInfo.iFourCC = aSinkFourCC;
+        }
+
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkThreadLogon
+//
+// Passes the logon command to the sink clip
+// -----------------------------------------------------------------------------
+//
+TInt CAvcPayloadFormatWrite::SinkThreadLogon( MAsyncEventHandler& aEventHandler )
+    {
+    iCurDataSink->SinkThreadLogon( aEventHandler );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkThreadLogoff
+//
+// Log out of the sink thread.
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SinkThreadLogoff ( )
+    {
+    iCurDataSink->SinkThreadLogoff( );
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::ProcessFramesL
+//
+// Packetize the AVC frames received from AVC codec and deliver the packets.
+// The AVC frames are stored in "iSourceBuffer".
+// return value - Current talk spurt finished, ETrue. Otherwise, EFalse
+// -----------------------------------------------------------------------------
+//
+TBool CAvcPayloadFormatWrite::ProcessFramesL( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ProcessFramesL")
+    
+    __ASSERT_ALWAYS( iSourceBuffer, User::Leave( KErrNotReady ) );
+    
+	TInt nalCount = 0;
+    TUint32 markerBit = 0;
+    TDes8& srcDes = iSourceBuffer->Data();
+    HBufC8* bufPtr = NULL;
+    TInt count = 0;
+    TBool retVal = EFalse;
+    
+    if ( !iSinkBuffer )
+        {
+        __AVCPLFORMAT_CONTROLL(
+            "CAvcPayloadFormatWrite::ProcessFramesL, sink not ready, exit")
+        return retVal;
+        }	
+    
+    // Get timestamp to RTP header. conversion to 90kHz clock
+	iRtpSendHeader.iTimestamp = iSourceBuffer->TimeToPlay().Int64() / 100 * 9; 
+    
+    iEncoder->PayloadizeFrameL( srcDes, iRtpSendHeader.iTimestamp, markerBit, nalCount );
+        
+   	for ( count = 0; count < nalCount; count++ )
+   	    {
+   	    __AVCPLFORMAT_CONTROLL("looping")
+   	    
+   		// getting data
+   		bufPtr = iEncoder->GetNalUnitsInOrder( count );
+   		User::LeaveIfNull( bufPtr );
+   		TPtr8 ptr = bufPtr->Des();
+   		
+   		// copying data to sink
+   		TDes8& dataDes = iSinkBuffer->Data();
+   		
+   		dataDes.Copy( ptr.Ptr(), ptr.Length() );
+   		
+		// filling RTP Header structure
+		
+		iSinkBuffer->SetFrameNumber( iSourceBuffer->FrameNumber() + iSeqNumIncrementer );
+
+		// Setting marker bit only for last packet if more than one NAL unit
+		// for same ts, marker bit is never set for sps or pps
+		if ( nalCount > 1 && ( count != nalCount-1 ) )
+		    {
+		    iRtpSendHeader.iMarker = 0;
+		    
+		    // If frame is divided in several packets, sequence numbers of following
+	        // packets have to be modified
+		    iSeqNumIncrementer++;
+		    }
+		else if ( TMccCodecInfo::IsAvcPpsOrSpsData( ptr, ETrue ) )
+		    {
+		    iRtpSendHeader.iMarker = 0;
+		    }
+	    else
+	        {
+	        iRtpSendHeader.iMarker = 1;
+	        }
+	        
+		iRtpSendHeader.iPayloadType = iCInfo.iPayloadType; // as per configured
+   		
+   		if ( iIsRtpSink )
+    	    {
+        	CMccRtpDataSink* rtpSink = static_cast<CMccRtpDataSink*>( iCurDataSink );
+    	    rtpSink->EmptyBufferL( iSinkBuffer, this, iMediaId, iRtpSendHeader );
+    	    }
+    	else
+    	    {
+    	    iSinkBuffer->SetTimeToPlay( iRtpSendHeader.iTimestamp );
+		    iSinkBuffer->SetLastBuffer( iRtpSendHeader.iMarker );
+    	    iCurDataSink->EmptyBufferL( iSinkBuffer, this, iMediaId );
+    	    }
+	    }
+   	
+   	// this clears the buffers in the encoder filled with data, necessary to do this
+   	iEncoder->ClearNalBuffers();	
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ProcessFramesL, exit")
+    // probably it always returns false because in TRUE case, S/M goes IDLE,
+    // which is not desired in video
+    return retVal;
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::EmptyBufferL
+//
+// Empty the given source buffer by formatting the AVC frames into RTP payload.
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::EmptyBufferL( CMMFBuffer* aBuffer, 
+                                           MDataSource* aSupplier, 
+                                           TMediaId aMediaId )
+    {
+ 
+    if ( aMediaId.iMediaType != KUidMediaTypeVideo )
+        {
+        User::Leave( KErrNotSupported );
+        }
+    
+    // MMF buffer must never be NULL
+    __ASSERT_ALWAYS (aBuffer, User::Leave(KErrArgument));
+    
+    // Make sure that the very buffer is passed on, which we created once...
+    // This is necessary to avoid double-deletion problems etc.
+    __ASSERT_ALWAYS (aBuffer == iSourceBuffer, User::Leave(KErrArgument));
+    
+    // if same buffer is passed then no need to save the pointer; we already have it
+
+    // Save source buffer parameters and change the state.
+    iDataPath = aSupplier;
+    iMediaId = aMediaId;
+    
+    // we request S/M to call our EmptySourceBufferL() function
+    iStateMachine->ChangeState( EEmptySourceBuffer );
+
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::EmptySourceBufferL
+//
+// Empty the given source buffer by formatting the AMR frames into RTP payload.
+// Source buffer is given in "iSourceBuffer".
+// Called by the state machine.
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::EmptySourceBufferL( )
+    {
+  
+    if ( this->ProcessFramesL( ) )
+        {
+        // Current talk spurt is finished. Either last buffer
+        iStateMachine->ChangeState( EEncodeIdle );
+        }
+    else
+        {
+        // Just one step in a talk spurt
+        iStateMachine->ChangeState( ESourceBufferEmptied );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SourceBufferEmptiedL
+//
+// Hanlde the event that source buffer has been emptied.
+// Source buffer is given in "iSourceBuffer".
+// Called by the state machine.
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SourceBufferEmptiedL( )
+    {
+    __ASSERT_ALWAYS( iDataPath, User::Leave( KErrNotReady ) );
+    iDataPath->BufferEmptiedL( iSourceBuffer );
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::BufferEmptiedL
+//
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::BufferEmptiedL( CMMFBuffer* /*aBuffer*/ )
+    {
+    // We're using synchronous EmptyBufferL( aBuffer ) function call to RTP Sink.
+    // The aBuffer is ready to be used again when the EmptyBufferL returns back.
+    // So BufferEmptiedL( aBuffer ) is not really used.
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::Duration
+//
+// Return the clip duration for the given media. Returns a big value, 
+// which is not usable since this function is not being used for video.
+// The return value should be ignored.
+// -----------------------------------------------------------------------------
+//
+TTimeIntervalMicroSeconds CAvcPayloadFormatWrite::Duration( TMediaId /*aMediaType*/ ) const
+    {
+    return TTimeIntervalMicroSeconds( 1000000000 );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::CancelUlRequest
+// Cancel UL Request
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::CancelUlRequest( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::CancelUlRequest")
+     
+    iStateMachine->Cancel( );
+    iStateMachine->ChangeState( EEncodeIdle );
+
+     // Reset the payload buffer
+    if ( iSinkBuffer )
+        {
+        TDes8& dataDes = iSinkBuffer->Data();
+        dataDes.SetLength( 0 );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkPrimeL( )
+// Primes sink
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SinkPrimeL( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkPrimeL")
+    
+    iCurDataSink->SinkPrimeL();
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkPrimeL, exit")
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkPlayL( )
+// Plays sink
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SinkPlayL( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkPlayL")
+    
+    // Allocate buffer for data transfer between 
+    // FormatWrite - MDataSink AND FormatWrite - redundancy payload encoder
+	
+    delete iSinkBuffer;
+    iSinkBuffer = NULL;
+    iSinkBuffer = CMMFDataBuffer::NewL( iCInfo.iFrameSize );
+
+    // Initialize payload encoder
+    TDes8& dataDes = iSinkBuffer->Data();
+    dataDes.SetLength( 0 );   // for first packet length
+    
+    iSinkBuffer->SetLastBuffer( EFalse );
+    
+    iCurDataSink->SinkPlayL();
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkPlayL, exit")
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkPauseL( )
+// Pauses sink
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SinkPauseL( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkPauseL")
+    
+    iCurDataSink->SinkPauseL( );
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkPauseL, exit")
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::SinkStopL( )
+// Stops sink
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::SinkStopL( )
+    {
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkStopL")
+     
+    if ( EEmptySourceBuffer == iStateMachine->CurrentState( ) )
+        {
+        return;
+        }
+
+    // Stop state machine
+    CancelUlRequest( );
+
+    iCurDataSink->SinkStopL( );
+    
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::SinkStopL, exit")
+    }
+
+// -----------------------------------------------------------------------------
+// CAvcPayloadFormatWrite::ConfigurePayloadFormatL
+// Configure payload encoding parameters.
+// -----------------------------------------------------------------------------
+//
+void CAvcPayloadFormatWrite::ConfigurePayloadFormatL(
+    const TDesC8& aConfigParams,
+    CMccRtpMediaClock& /*aClock*/ )
+    {
+	__AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ConfigurePayloadFormatL")
+	
+	if ( aConfigParams.Size() == sizeof( TMccCodecInfo ) )
+        {
+        TMccCodecInfoBuffer infoBuffer;
+        infoBuffer.Copy( aConfigParams );
+        iCInfo = infoBuffer();
+        
+        // use values passed in to set parameter variables
+        __AVCPLFORMAT_CONTROLL_INT1( "packetization mode:", iCInfo.iCodecMode )
+        __ASSERT_ALWAYS( iCInfo.iCodecMode == KAvcFormatModeSingleNal || 
+                         iCInfo.iCodecMode == KAvcFormatModeNonInterleaved,
+                         User::Leave( KErrNotSupported ) );
+        
+        __ASSERT_ALWAYS( iCInfo.iPayloadType < KMccPayloadTypeMax, 
+                         User::Leave( KErrArgument ) );
+        
+        __ASSERT_ALWAYS( iCInfo.iFrameSize > 0, User::Leave( KErrArgument ) );
+        __ASSERT_ALWAYS( iCInfo.iMTUSize > 0, User::Leave( KErrArgument ) );
+        
+        iEncoder->SetPacketizationMode( iCInfo.iCodecMode );
+
+        iEncoder->SetFrameRate( static_cast<TInt>( iCInfo.iFramerate ) );
+
+        iEncoder->SetMTUSize( iCInfo.iMTUSize );
+        }
+    else
+        {
+        User::Leave( KErrArgument );
+    	}
+    	
+    __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ConfigurePayloadFormatL, exit")
+    }
+
+// -----------------------------------------------------------------------------
+