diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccavcpayloadformat/src/avcpayloadformatwrite.cpp --- /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 +#include +#include +#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( 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( iCInfo.iFramerate ) ); + + iEncoder->SetMTUSize( iCInfo.iMTUSize ); + } + else + { + User::Leave( KErrArgument ); + } + + __AVCPLFORMAT_CONTROLL("CAvcPayloadFormatWrite::ConfigurePayloadFormatL, exit") + } + +// ----------------------------------------------------------------------------- +