diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccavcpayloadformat/src/rfc3984encode.cpp --- /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 + +// ============================ 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( size ) ); + TUint8* ptrByte = reinterpret_cast( &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; + 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( &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 +