multimediacommscontroller/mmccavcpayloadformat/src/rfc3984encode.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/multimediacommscontroller/mmccavcpayloadformat/src/rfc3984encode.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,595 @@
+/*
+* 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 Payloadization class
+*
+*/
+
+
+
+
+// ============================ INCLUDES =======================================
+
+#include"rfc3984encode.h"
+#include "mccinternalcodecs.h"
+#include <es_sock.h>
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::CRFC3984Encode()
+// Default Constructor
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CRFC3984Encode::CRFC3984Encode()
+    {
+	iBufferIndex = 0;
+	iToPayloadizeCount = 0;
+	iNalCount = 0;
+    }
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::~CRFC3984Encode()
+// Default Destructor
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+CRFC3984Encode::~CRFC3984Encode()
+    {
+	ClearNalBuffers();
+	iToPayloadizeBuffer.Reset( );
+	iToPayloadizeSizeBuffer.Reset( );	
+    }
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::NewL()
+// First stage constructor
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+
+CRFC3984Encode * CRFC3984Encode::NewL()
+    {
+	CRFC3984Encode * self = new(ELeave) CRFC3984Encode;
+	CleanupStack::PushL( self );
+    CleanupStack::Pop();
+    return self;		
+    }
+
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::SetMTUSize()
+// Purpose     : 
+// Parameters  : 
+// Return Value: 
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::SetMTUSize( TUint32 aMtuSize )
+    {
+	iMaxPacketSize = aMtuSize;	
+    }
+
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::SetFrameRate()
+// Purpose     : 
+// Parameters  : 
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::SetFrameRate( TInt aFrameRate )
+    {
+	iFrameRate = aFrameRate;	
+    }
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::PayloadizeFrameL()
+// Purpose     : This function receives the encoded frame and payloadizes it based 
+//               on the packetization_mode value
+// Parameters  : aBuffer - Buffer containing the encoded frame
+//				 aTimeStamp - Timestamp to go into RTP
+// 				 aMarkerBit - Marker Bit indication (this function sets it for key frames)
+// 				 aNalCount - Reference to return the number of NAL units payloadized
+// Return Value: none, leaves if an error occured
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::PayloadizeFrameL(
+    TDes8 & aBuffer, 
+    TUint32 aTimeStamp, 
+    TUint32 & aMarkerBit, 
+    TInt &aNalCount )
+    {
+	TInt error = KErrNone;
+	
+	if ( iPacketizationMode == AVC_MODE_SNALU )
+	    {
+		TRAP( error, 
+		PayloadizeFrameSingleNALModeL( aBuffer, aTimeStamp, aMarkerBit, aNalCount ) );
+	    }
+	else if ( iPacketizationMode == AVC_MODE_NONINTERLEAVED )
+	    {
+		TRAP( error, 
+		PayloadizeFrameNonInterleavedModeL( aBuffer, aTimeStamp, aMarkerBit, aNalCount ) );
+    	}
+	else if ( iPacketizationMode == AVC_MODE_INTERLEAVED )
+	    {
+		User::Leave( KErrNotSupported );
+	    }
+	
+	if ( KErrNone != error )
+	    {
+		ClearNalBuffers();
+		iToPayloadizeBuffer.Reset();
+    	iToPayloadizeSizeBuffer.Reset();
+    	iToPayloadizeCount = 0;
+    	User::Leave( error );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::PayloadizeFrameSingleNALModeL()
+// Purpose     : This function receives the encoded frame and payloadizes it
+//               according to the SNALU mode
+// Parameters  : aBuffer - Buffer containing the encoded frame
+//				 aTimeStamp - Timestamp to go into RTP
+// 				 aMarkerBit - Marker Bit indication (this function sets it for key frames)
+//				 aNalCount - This function returns the number of packetized NAL
+//               units through this variable.
+// Return Value: none, leaves if an error occured
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::PayloadizeFrameSingleNALModeL(
+    TDes8& aBuffer, 
+    TUint32 /*aTimeStamp*/, 
+    TUint32& /*aMarkerBit*/, 
+    TInt& aNalCount )
+    {
+	// This implementation assumes the NAL units for one frame are seperated
+	// by 0x001 or 0x0001 start codes 
+    
+    // Resetting iBufferIndex for this new frame, always do this for new frame
+    // because this is used to find start codes within one frame
+    iBufferIndex = 0; 	
+    
+    TInt startIndex = 0;	// holds first byte-index of NALU
+    TInt endIndex = 0;		// hold byte-index of next to last byte of NALU
+    TInt size = 0;
+    HBufC8 * pBuffer = 0;
+    
+    // loop to find and packetize all NAL Units in the frame
+	while ( ETrue )
+	    {
+		startIndex = TMccCodecInfo::FindAvcNaluStart( iBufferIndex, aBuffer );
+		if ( KErrNotFound == startIndex )
+		    {
+			break;
+		    }
+		
+		endIndex = TMccCodecInfo::FindAvcNaluEnd( iBufferIndex, aBuffer );
+		if ( KErrNotFound == endIndex )
+		    {
+			break;
+		    }
+		
+		if ( startIndex == endIndex )
+		    {
+			break;
+		    }
+				
+		// finding size of the NAL unit
+		size = endIndex - startIndex;
+		
+		__ASSERT_ALWAYS( size > 0, User::Leave( KErrGeneral ) ); // some flaw in logic
+		
+		pBuffer = HBufC8::NewLC( size );
+		
+		TPtr8 aPtr = pBuffer->Des();
+		// Now the size and start Index is known, copying the data
+		
+		aPtr.Copy( aBuffer.Mid( startIndex, size ) );
+		
+		// Now inserting pointer
+		iPayloadizedBuffers.InsertL( pBuffer, iNalCount );
+		CleanupStack::Pop( pBuffer );
+		pBuffer = NULL;	// ownership transferred
+		iNalCount++;
+	    }
+    
+    aNalCount = iNalCount;
+    }
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::PayloadizeFrameNonInterleavedModeL()
+// Purpose     : This function receives the encoded frame and payloadizes it
+//               according to the Non-Interleaved Mode
+// Parameters  : aBuffer - Buffer containing the encoded frame
+//				 aTimeStamp - Timestamp to go into RTP
+// 				 aMarkerBit - Marker Bit indication (this function sets it for key frames)
+//				 aNalCount - This function returns the number of packetized
+//               NAL units through this variable.
+// Return Value: none, leaves if an error occured
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::PayloadizeFrameNonInterleavedModeL(
+    TDes8& aBuffer, 
+    TUint32 aTimeStamp, 
+    TUint32& aMarkerBit, 
+    TInt& aNalCount )
+    {
+	iNalCount = 0;
+	aNalCount = 0; // resetting value coming from above
+	iBufferIndex = 0;
+	
+	TInt startIndex = 0;
+	TInt endIndex = 0;
+	TInt size = 0;
+	TInt count = 0; // variable to keep track of the size of aggregated packet.
+	
+	aNalCount = 0;
+	
+	// loop to find and packetize all NAL Units in the frame
+	while( ETrue )
+	    {
+		startIndex = TMccCodecInfo::FindAvcNaluStart( iBufferIndex, aBuffer );
+		if ( startIndex == KErrNotFound )
+		    {
+			break;
+		    }
+		
+		endIndex = TMccCodecInfo::FindAvcNaluEnd( iBufferIndex, aBuffer );
+		if ( endIndex == KErrNotFound )
+		    {
+			break;
+		    }
+		
+		if ( startIndex == endIndex )
+		    {
+			break;
+		    }
+		    
+		// finding size of the NAL unit
+		size = endIndex - startIndex;
+		
+		__ASSERT_ALWAYS( size > 0, User::Leave( KErrGeneral ) ); // some flaw in logic
+		
+		// Now startIndex and size of this NAL Unit are known
+		// decide if SNALU packetization or STAP or FU-A is required
+		if ( size > iMaxPacketSize )
+		    {
+		    // if any NALU there for aggregation or SNALU, payloadize it first
+			if ( iToPayloadizeCount > 0 )  
+			    {
+				PayloadizeNaluL( aBuffer, aTimeStamp, aMarkerBit, aNalCount );
+				
+				count = 0; // resetting count of bytes for aggregation packets
+				iToPayloadizeCount = 0;	
+			    }
+			
+			FragmentNaluL( aBuffer, aTimeStamp, aMarkerBit, aNalCount, startIndex, size, 0 );
+		    }
+		else if ( size <= iMaxPacketSize )
+		    {
+			if( size + count > iMaxPacketSize )
+			    {
+				// make STAP-A or SNALU based on number of elements in the buffer
+				PayloadizeNaluL( aBuffer, aTimeStamp, aMarkerBit, aNalCount );
+				
+				count = 0;   // resetting count of bytes for aggregation packets
+				iToPayloadizeCount = 0;
+			    }	
+			// Insert current NALU into the Buffer.
+			iToPayloadizeBuffer.InsertL( startIndex, iToPayloadizeCount );
+			iToPayloadizeSizeBuffer.InsertL( size, iToPayloadizeCount );
+			iToPayloadizeCount++;
+			count += size;
+		    }
+	    } // end while()
+	
+	// packetizing any last NALUs left in the buffer
+	if ( iToPayloadizeCount > 0 )
+	    {
+	 	PayloadizeNaluL( aBuffer, aTimeStamp, aMarkerBit, aNalCount );
+	 	count = 0;
+	 	iToPayloadizeCount = 0;
+	    }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::PayloadizeNaluL()
+// Purpose     : This function makes a SNALU packet or STAP-A packet based on the
+//               number of NALUs in the array iToPayloadizeBuffer.
+// Parameters  : aBuffer - Buffer containing the encoded frame
+//				 aTimeStamp - Timestamp to go into RTP
+// 				 aMarkerBit - Marker Bit indication (this function sets it for key frames)
+//				 aNalCount - This function returns the number of packetized
+//               NAL units through this variable.
+//				 aStartIndex - Index to the starting of the NALU
+// Return Value: none, leaves if an error occured
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::PayloadizeNaluL(
+    TDes8 & aBuffer, 
+    TUint32 /*aTimeStamp*/, 
+    TUint32& /*aMarkerBit*/, 
+    TInt & aNalCount )
+    {
+	TInt startIndex = 0;
+	TInt size = 0;
+	
+	__ASSERT_ALWAYS( iToPayloadizeCount > 0, User::Leave( KErrArgument ) );
+	
+	__ASSERT_ALWAYS( iToPayloadizeBuffer.Count() == iToPayloadizeSizeBuffer.Count(), 
+	                 User::Leave( KErrArgument ) );
+		
+	if ( iToPayloadizeCount == 1 ) // SNALU packet
+	    {
+		startIndex = iToPayloadizeBuffer[0];
+		size = iToPayloadizeSizeBuffer[0];	
+		TPtr8 start = aBuffer.MidTPtr( startIndex );
+		AddSnaluPacketL( start, size );
+    	}
+	else // payloadize STAP-A packet
+	    {
+		TInt count = 0;
+		TInt totalSize = 0;
+		TUint8 headerByte = 0;
+		
+		for ( count = 0; count < iToPayloadizeCount; count++ )
+		    {
+		    // finding total size of all the NALU's to aggregate
+			totalSize += iToPayloadizeSizeBuffer[count]; 
+		    }
+		
+		// addding the total size fields and STAP-A header size	
+		totalSize += ( iToPayloadizeCount*2 + 1 ); 
+		
+		count = 0;
+		
+		// allocating memory for the total buffer size		
+		HBufC8* pBuffer = HBufC8::NewLC( totalSize );
+		
+		TUint16 value = 0;
+		TPtr8 pDes1 = pBuffer->Des();
+		
+		headerByte = PACKET_STAP_A | ( aBuffer[iToPayloadizeBuffer[count]] & ( 0x7 << 5 ) ); 
+		pDes1.Append( &headerByte, 1 );
+		
+		 // Pps and sps are handled as SNALUs, 
+		 // if there's nothing else to packetize, stap-a packet is not created
+		TBool stapPacketCreated( EFalse );
+		for( count = 0; count < iToPayloadizeCount; count++ )
+		    {
+			startIndex = iToPayloadizeBuffer[count];
+			size = iToPayloadizeSizeBuffer[count];
+			TPtr8 pStart = aBuffer.MidTPtr( startIndex ); // getting start index
+			
+			if ( TMccCodecInfo::IsAvcPpsOrSpsData( pStart, ETrue ) )
+			    {
+			    AddSnaluPacketL( pStart, size );
+			    }
+			else
+			    {
+    			// convert to network byte order
+    			value = ByteOrder::Swap16( static_cast<TUint16>( size ) ); 
+    			TUint8* ptrByte = reinterpret_cast<TUint8*>( &value );
+    			pDes1.Append( ptrByte, 2 );
+    			pDes1.Append( pStart.Ptr(), size );
+    			stapPacketCreated = ETrue;
+			    }
+		    }
+		
+		if ( stapPacketCreated )
+		    {
+    		// inserting stap-a packet into the payloadized NAL unit buffer for retrieval
+        	iPayloadizedBuffers.InsertL( pBuffer, iNalCount );
+        	iNalCount++;
+        	CleanupStack::Pop(pBuffer);
+		    }
+		else
+		    {
+		    // stap-a packet not created
+		    CleanupStack::PopAndDestroy(pBuffer);
+		    }
+	    }
+	
+    //Now cleaning up the buffer
+    iToPayloadizeBuffer.Reset();
+    iToPayloadizeSizeBuffer.Reset();
+    iToPayloadizeCount = 0;
+    	
+	aNalCount = iNalCount;
+    }
+
+// -----------------------------------------------------------------------------
+// CRFC3984Encode::FragmentNaluL()
+// Purpose     : This function receives the starting index of a NALU in a buffer and
+//               fragments the NAL unit
+// Parameters  : aBuffer - Buffer containing the encoded frame
+//				 aTimeStamp - Timestamp to go into RTP
+// 				 aMarkerBit - Marker Bit indication (this function sets it for key frames)
+//				 aNalCount - This function returns the number of packetized NAL units
+//               through this variable.
+//				 aStartIndex - Index to the starting of the NALU
+// 				 aSize - Size of the NALU
+//				 aDon - valeu of Decoding order number , 16 bit value
+// Return Value: none, leaves if an error occured
+// -----------------------------------------------------------------------------
+//
+
+void CRFC3984Encode::FragmentNaluL(
+    TDes8 & aBuffer, 
+    TUint32 /*aTimeStamp*/, 
+    TUint32 & aMarkerBit, 
+    TInt & aNalCount, 
+    TInt aStartIndex, 
+    TInt aSize, 
+    TUint16 aDON )
+    {
+	TInt index = 0;
+	TInt fragsPacketized = 0;
+	TUint8 headerByte = 0; // FU-A packet header byte (contains F, NRI, Type Fields) 
+	TUint8 fragHeaderByte = 0;
+	TInt length = 0;
+	// maximum size of fragment, 4 is to cater for DON field in FU-B
+	TInt fragMaxSize = iMaxPacketSize - 4; 
+	TInt fragSize = 0; // size of fragment
+	HBufC8 * pBuffer = NULL;
+	
+	// index keeps track of indexes in the buffer
+	index = aStartIndex; 
+	// length of data packetized, the code decrements this after each fragment is made
+	length = aSize;	
+	
+	while ( length > 0 )
+	    {
+	     // Actually should be based on (PacketizationMode == INTERLEAVED && fragsPacketized == 0)
+		TBool fuB = EFalse;
+		
+		headerByte = aBuffer[aStartIndex]  & ( 0x07 << 5 ); // Extracting F and NRI bits
+		
+		// taking lower 5 type bits and putting into fragHeader
+		fragHeaderByte = aBuffer[aStartIndex] & 0x1f; 
+			
+		if ( fragsPacketized == 0 )
+		    {
+		    fragHeaderByte |= (0x1 << 7); // setting start bit
+		    }
+		    
+		if ( length <= fragMaxSize )
+		    {
+			fragHeaderByte |= ( 0x1 << 6 );	// setting end byte
+			aMarkerBit = 1;	
+		    }
+		else
+		    {
+			aMarkerBit = 0;
+		    }
+		
+		if ( fragsPacketized == 0 )	// skipping payload header byte for FU packets 
+		    {	
+		    index += 1;
+			length -= 1;	
+		    }
+	    
+	    fragSize = ( length > fragMaxSize ) ? fragMaxSize+2 : length+2; // 2 bytes for headers
+		
+		if( !fuB )
+		    {
+			headerByte |= PACKET_FU_A;	
+		    }
+		else
+		    {
+			fragSize += 2; // for additional DON field
+			headerByte |= PACKET_FU_B;
+		    }
+		
+		// allocating memory for fragmented NAL unit
+	    pBuffer = HBufC8::NewLC(fragSize);
+	     	
+ 		TPtr8 pDes = pBuffer->Des(); //new (ELeave) TBuf8<size>;
+		pDes.Append( &headerByte, 1 ); // appending FU-A packet header byte
+		pDes.Append( &fragHeaderByte, 1 ); // appending Fragment header
+		
+		if ( fuB )
+		    {  
+		    // writing DON in network byte order
+			TUint16 val = ByteOrder::Swap16( aDON );
+			TUint8* ptrByte = reinterpret_cast<TUint8*>( &val );
+			pDes.Append( ptrByte, 2 );
+		    }
+		
+		TPtr8 pStart = aBuffer.MidTPtr( index ); // pStart contains the data pointer    		
+    	
+    	if ( !fuB )
+    	    {
+    		pDes.Append( pStart.Ptr(), fragSize-2 ); // copying data	
+    		index += Min( length, fragMaxSize );    	
+    		length -= ( fragSize-2 );
+        	}
+    	else
+    	    {
+    	    // copying data, subtracting DON and header size from total size to copy
+    		pDes.Append( pStart.Ptr( ), fragSize-4 );
+			index += Min( length, fragMaxSize );
+			length -= ( fragSize-4 );    		
+    	    }
+    
+    	
+    	// inserting into the payloadized NAL unit buffer for retreival
+    	iPayloadizedBuffers.InsertL( pBuffer, iNalCount );
+    	iNalCount++;
+    	CleanupStack::Pop( pBuffer );
+    	pBuffer = NULL; // ownership transferred
+    	
+    	fragsPacketized++; // to count the number of fragments
+	
+	    } // end while()
+	
+	aNalCount = iNalCount;
+    }
+
+
+HBufC8 * CRFC3984Encode::GetNalUnitsInOrder( TInt & aIndex )
+    {
+	HBufC8 *pBuffer;
+	if ( aIndex < iNalCount )
+	    {
+		pBuffer = iPayloadizedBuffers[aIndex];
+		return (pBuffer);
+	    }
+	else
+	    {
+		return NULL;
+	    }
+	
+    }
+
+void CRFC3984Encode::ClearNalBuffers()
+    {
+	TInt count = 0;
+	HBufC8 * pBuffer = NULL;
+	
+	for ( count = 0; count < iPayloadizedBuffers.Count(); count++ )
+	    {
+		pBuffer = iPayloadizedBuffers[count];
+		delete pBuffer;
+		pBuffer = NULL;
+		iPayloadizedBuffers[count] = NULL;
+	    }
+	
+	iPayloadizedBuffers.Reset();
+	iNalCount = 0; 
+    }
+
+void CRFC3984Encode::AddSnaluPacketL( TPtr8 aStart, TInt aSize )
+    {
+    HBufC8* pBuffer = HBufC8::NewLC( aSize );
+	
+	TPtr8 pPtr = pBuffer->Des();
+	pPtr.Copy( aStart.Ptr(), aSize );
+	
+	// inserting into the payloadized NAL unit buffer for retreival
+	iPayloadizedBuffers.InsertL( pBuffer, iNalCount );
+	iNalCount++;
+	CleanupStack::Pop( pBuffer );
+    }
+    	
+// End of file
+