diff -r 000000000000 -r 1bce908db942 multimediacommsengine/mmceshared/src/mcecomavccodec.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommsengine/mmceshared/src/mcecomavccodec.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,708 @@ +/* +* 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 "mcecomavccodec.h" + +#ifdef MCE_COMMON_SERVER_SIDE + +#include +#include + +#include "mcecommediastream.h" + +#endif + + +// CONSTANTS +_LIT8( KMceAvcProfileLevelIdFmtp, "profile-level-id=" ); +_LIT8( KMceAvcProfileLevel1, "42800A" ); +const TInt KMceAvcProfileLevelIdValLen = 6; + +_LIT8( KMceAvcPacketizationModeFmtp, "packetization-mode=" ); +_LIT8( KMceAvcPacketizationModeSingleNal, "0" ); +const TInt KMceAvcPacketizationModeValLen = 1; + +#ifdef MCE_COMMON_SERVER_SIDE + +_LIT8( KMceAvcProfileLevelOnly1, "0A" ); +const TInt KMceAvcProfileLevelValLen = 2; +const TInt KMceAvcProfileLevelValOffset = 4; + +_LIT8( KMceAvcProfileIopDefault, "80" ); +const TInt KMceAvcProfileIopValLen = 2; +const TInt KMceAvcProfileIopValOffset = 2; + +_LIT8( KMceAvcSpropParameterSetsFmtp, "sprop-parameter-sets="); +const TChar KMceAvcFmtpParameterSeparator = ';'; +const TChar KMceAvcFtmpParameterSpace = ' '; + +#endif + +// ============================ MEMBER FUNCTIONS =============================== + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::NewL +// ----------------------------------------------------------------------------- +// +CMceComAvcCodec* CMceComAvcCodec::NewL( TBuf8 aSdpName ) + { + CMceComAvcCodec* self = NewLC( aSdpName ); + CleanupStack::Pop( self ); + return self; + + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::NewLC +// ----------------------------------------------------------------------------- +// +CMceComAvcCodec* CMceComAvcCodec::NewLC( TBuf8 aSdpName ) + { + CMceComAvcCodec* self = new (ELeave) CMceComAvcCodec(); + CleanupStack::PushL( self ); + self->ConstructL( aSdpName ); + return self; + } + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::~CMceComAvcCodec +// ----------------------------------------------------------------------------- +// +CMceComAvcCodec::~CMceComAvcCodec() + { + } + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::CMceComAvcCodec +// ----------------------------------------------------------------------------- +// +CMceComAvcCodec::CMceComAvcCodec() + :CMceComVideoCodec() + { + iCodecMode = KMceAvcModeSingleNal; + iClockRate = KMceAvcDefaultFrameRate; + iFrameRate = KMceAvcDefaultFrameRate; + iResolutionWidth = KMceAvcDefaultFrameWidth; + iResolutionHeight = KMceAvcDefaultFrameHeight; + iBitrate = KMceAvcLevel1BitrateBps; + iMaxBitRate = KMceAvcLevel1BitrateBps; + iAllowedBitrates = KMceAvcDefaultAllowedBitrate; + iFrameSize = KMceAvcDefaultFrameSize; + // Defaults should be defined in MCE API + const TUint8 KMceDefaultAvcPayloadType = 98; + iPayloadType = KMceDefaultAvcPayloadType; + + iReceiveFrameRate = KMceAvcDefaultFrameRate; + } + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ConstructL +// ----------------------------------------------------------------------------- +// +CMceComVideoCodec* CMceComAvcCodec::CloneL() + { + CMceComAvcCodec* copy = new (ELeave) CMceComAvcCodec(); + CleanupStack::PushL( copy ); + copy->ConstructL( *this ); + CleanupStack::Pop( copy ); + return copy; + + } + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ConstructL +// ----------------------------------------------------------------------------- +// +void CMceComAvcCodec::ConstructL( TBuf8 aSdpName ) + { + CMceComVideoCodec::ConstructL( aSdpName ); + + } + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ConstructL +// ----------------------------------------------------------------------------- +// +void CMceComAvcCodec::ConstructL( CMceComAvcCodec& aCodec ) + { + CMceComVideoCodec::ConstructL( aCodec ); + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::SetBitrate +// ----------------------------------------------------------------------------- +// +TInt CMceComAvcCodec::SetBitrate( TUint aBitrate ) + { + return CMceComCodec::SetBitrate( aBitrate ); + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::SetAllowedBitrates +// ----------------------------------------------------------------------------- +// +TInt CMceComAvcCodec::SetAllowedBitrates( TUint aBitrates ) + { + TInt error = KErrNone; + + //Confirm that the bitrate mask is valid + //I.e. after all the valid bitrates are set to zero the value should be zero + if ( !aBitrates || + ( aBitrates >> 16 ) > 0 ) + { + error = KErrArgument; + } + else + { + const TUint KMceOtherInfoMask = 0xFF00; + + if ( aBitrates == KMceAllowedAvcBitrateAll ) + { + // Start using recommended high bitrate + aBitrates = KMceAvcAllowedBitrateRecommendedHigh; + } + + CMceComCodec::SetAllowedBitrates( KMceAllowedAvcBitrateAll ); + iAllowedBitrates &= aBitrates; + TUint maxBitrate = GetMaxBitRate(); + CMceComVideoCodec::SetMaxBitrate( maxBitrate ); + if ( iBitrate > maxBitrate ) + { + error = CMceComCodec::SetBitrate( maxBitrate ); + } + + // Update also other avc codec information stored inside + // allowed bitrates mask + iAllowedBitrates |= ( aBitrates & KMceOtherInfoMask ); + } + + return error; + } + + + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::GetMaxBitRate +// ----------------------------------------------------------------------------- +// +TUint CMceComAvcCodec::GetMaxBitRate() + { + TUint maxBitrate( 0 ); + if( iAllowedBitrates & KMceAvcBitrateLevel1 ) + { + maxBitrate = KMceAvcLevel1BitrateBps; + } + else if( iAllowedBitrates & KMceAvcBitrateLevel1b ) + { + maxBitrate = KMceAvcLevel1bBitrateBps; + } + else if( iAllowedBitrates & KMceAvcBitrateLevel1_1 ) + { + maxBitrate = KMceAvcLevel11BitrateBps; + } + else if( iAllowedBitrates & KMceAvcBitrateLevel1_2 ) + { + maxBitrate = KMceAvcLevel12BitrateBps; + } + else if( iAllowedBitrates & KMceAvcBitrateLevel1_3 ) + { + maxBitrate = KMceAvcLevel13BitrateBps; + } + else if( iAllowedBitrates & KMceAvcBitrateLevel2 ) + { + maxBitrate = KMceAvcLevel2BitrateBps; + } + else + { + // NOP + } + + return maxBitrate; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::SetMaxBitrate +// ----------------------------------------------------------------------------- +// +TInt CMceComAvcCodec::SetMaxBitrate( TUint aMaxBitrate ) + { + TInt status = KErrNone; + switch( aMaxBitrate ) + { + case KMceAvcLevel1BitrateBps: + { + status = SetAllowedBitrates( KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1 ); + break; + } + case KMceAvcLevel1bBitrateBps: + { + status = SetAllowedBitrates( KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1b ); + break; + } + case KMceAvcLevel11BitrateBps: + { + status = SetAllowedBitrates( KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1_1 ); + break; + } + case KMceAvcLevel12BitrateBps: + { + status = SetAllowedBitrates( KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1_2 ); + break; + } + case KMceAvcLevel13BitrateBps: + { + status = SetAllowedBitrates( KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1_3 ); + break; + } + case KMceAvcLevel2BitrateBps: + { + status = SetAllowedBitrates( KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel2 ); + break; + } + default: + { + status = KErrNotSupported; + break; + } + } + + return status; + + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ResolveAllowedBitrates +// ----------------------------------------------------------------------------- +// +TInt CMceComAvcCodec::ResolveAllowedBitrates( + TUint aBitrate, TUint& aAllowedBitrates ) + { + TInt retVal( KErrNone ); + + if ( aBitrate <= KMceAvcLevel1BitrateBps ) + { + aAllowedBitrates = KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1; + } + else if ( aBitrate <= KMceAvcLevel1bBitrateBps ) + { + aAllowedBitrates = KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1b; + } + else if ( aBitrate <= KMceAvcLevel11BitrateBps ) + { + aAllowedBitrates = KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1_1; + } + else if ( aBitrate <= KMceAvcLevel12BitrateBps ) + { + aAllowedBitrates = KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1_2; + } + else if ( aBitrate <= KMceAvcLevel13BitrateBps ) + { + aAllowedBitrates = KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel1_3; + } + else if ( aBitrate <= KMceAvcLevel2BitrateBps ) + { + aAllowedBitrates = KMceAvcCodecProfileIdBaseline | + KMceAvcCodecProfileIopConstraintSet | + KMceAvcBitrateLevel2; + } + else + { + retVal = KErrNotSupported; + } + + return retVal; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::Decodes +// For AVC, fmtp value contains profile level and packetization mode +// information which need to be taken in count (same codec cannot be +// used for different levels or packetization modes). If less strict matching +// is used, profile level is ignored but packetization mode is still checked +// ----------------------------------------------------------------------------- +// +TBool CMceComAvcCodec::Decodes( + const TDesC8& aRtpmapValue, + const TDesC8& aFmtpValue, + TBool aIsStrictMatch ) + { + TBool decodes = CMceComCodec::Decodes( aRtpmapValue, aFmtpValue, aIsStrictMatch ); + if ( decodes ) + { + TPtrC8 existingFmtpVal = FmtpAttr(); + + TPtrC8 packetizationMode = ParsePacketizationMode( aFmtpValue ); + TPtrC8 existingPacketizationMode = ParsePacketizationMode( existingFmtpVal ); + decodes = ( packetizationMode.CompareF( existingPacketizationMode ) == 0 ); + + if ( decodes && aIsStrictMatch ) + { + TPtrC8 profileLevelId = ParseProfileLevelId( aFmtpValue ); + + TPtrC8 existingProfileLevelId = ParseProfileLevelId( existingFmtpVal ); + decodes = ( profileLevelId.CompareF( existingProfileLevelId ) == 0 ); + } + } + return decodes; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ParseProfileLevelId +// ----------------------------------------------------------------------------- +// +TPtrC8 CMceComAvcCodec::ParseProfileLevelId( const TDesC8& aFmtpValue ) + { + // Non-existing profile-level-id means level 1 + TPtrC8 profileLevelIdVal = + GetFmtpAttributeValuePart( aFmtpValue, + KMceAvcProfileLevelIdFmtp(), + KMceAvcProfileLevelIdValLen, + KMceAvcProfileLevel1 ); + + return profileLevelIdVal; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ParseProfileLevelIdValPart +// ----------------------------------------------------------------------------- +// +TPtrC8 CMceComAvcCodec::ParseProfileLevelIdValPart( + const TDesC8& aFmtpValue, + TInt aValPartOffset, + TInt aValPartLen, + const TDesC8& aDefaultVal ) + { + TPtrC8 profileLevelVal( aDefaultVal ); + + TPtrC8 profileLevelIdVal = ParseProfileLevelId( aFmtpValue ); + if ( profileLevelIdVal.Length() >= aValPartOffset + aValPartLen ) + { + // Take just value part + profileLevelVal.Set( profileLevelIdVal.Mid( aValPartOffset, aValPartLen ) ); + } + + return profileLevelVal; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ReplaceProfileLevelIdValuePart +// ----------------------------------------------------------------------------- +// +TInt CMceComAvcCodec::ReplaceProfileLevelIdValuePart( + TDes8& aModifiedFmtp, + const TDesC8& aReplacement, + TInt aValPartOffset ) + { + TInt err( KErrArgument ); + + TInt startIndex = aModifiedFmtp.FindF( KMceAvcProfileLevelIdFmtp() ); + startIndex = ( startIndex != KErrNotFound ) ? + ( startIndex + KMceAvcProfileLevelIdFmtp().Length() ) : startIndex; + if ( startIndex != KErrNotFound && + ( startIndex + aValPartOffset + aReplacement.Length() ) <= aModifiedFmtp.Length() ) + { + aModifiedFmtp.Replace( + startIndex + aValPartOffset, + aReplacement.Length(), + aReplacement ); + err = KErrNone; + } + return err; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::ParsePacketizationMode +// ----------------------------------------------------------------------------- +// +TPtrC8 CMceComAvcCodec::ParsePacketizationMode( const TDesC8& aFmtpValue ) + { + // Non-existing packetization mode means single nal mode + TPtrC8 packetizationModeVal = + GetFmtpAttributeValuePart( aFmtpValue, + KMceAvcPacketizationModeFmtp(), + KMceAvcPacketizationModeValLen, + KMceAvcPacketizationModeSingleNal ); + + return packetizationModeVal; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::GetFmtpAttributeValuePart +// ----------------------------------------------------------------------------- +// +TPtrC8 CMceComAvcCodec::GetFmtpAttributeValuePart( + const TDesC8& aFmtpValue, + const TDesC8& aFmtpAttributeName, + TInt aValLen, + const TDesC8& aDefaultVal ) + { + TPtrC8 outputValuePart( aDefaultVal ); + + TInt valPos = aFmtpValue.FindF( aFmtpAttributeName ); + valPos = ( valPos != KErrNotFound ) ? + ( valPos + aFmtpAttributeName.Length() ) : valPos; + if ( valPos != KErrNotFound && + ( valPos + aValLen ) <= aFmtpValue.Length() ) + { + outputValuePart.Set( aFmtpValue.Mid( valPos, aValLen ) ); + } + return outputValuePart; + } + +#ifdef MCE_COMMON_SERVER_SIDE + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::SetFmtpProposalL +// ----------------------------------------------------------------------------- +// +TBool CMceComAvcCodec::SetFmtpProposalL( const TDesC8& aFmtpProposal ) + { + HBufC8* proposal = aFmtpProposal.AllocL(); + delete iFmtpProposal; + iFmtpProposal = proposal; + + CMccCodecInformationFactory* factory = CMccCodecInformationFactory::NewL(); + CleanupStack::PushL( factory ); + CMccCodecInformation* codec = + factory->CreateCodecInformationL( iSdpName ); + CleanupStack::PushL( codec ); + + TRAPD( err, codec->SetFmtpAttrL( *iFmtpProposal ) ); + if ( err == KErrNoMemory ) + { + User::Leave( err ); + } + + CleanupStack::PopAndDestroy( codec ); + CleanupStack::PopAndDestroy( factory ); + + return ( err == KErrNone ); + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::SetFmtpFromIncomingSdpL +// ----------------------------------------------------------------------------- +// +void CMceComAvcCodec::SetFmtpFromIncomingSdpL( + const TDesC8& aFmtpAttribute, + TBool aRoleAnswerer, + TBool aReset ) + { + HBufC8* fmtp = aFmtpAttribute.AllocLC(); + TPtr8 ptrFmtp( fmtp->Des() ); + + if ( !aRoleAnswerer ) + { + // If no strict match, we are accepting fmtp even it is against specs. + // In that case, replace level value with existing level + TBool decodes = Decodes( iSdpName, aFmtpAttribute ); + if ( !decodes ) + { + TPtrC8 existingLevel = + ParseProfileLevelIdValPart( FmtpAttr(), + KMceAvcProfileLevelValOffset, + KMceAvcProfileLevelValLen, + KMceAvcProfileLevelOnly1 ); + ReplaceProfileLevelIdValuePart( + ptrFmtp, existingLevel, KMceAvcProfileLevelValOffset ); + } + + // In offerer side, tolerate also incorrect iop part usage + // by using existing iop val + TPtrC8 existingIop = + ParseProfileLevelIdValPart( FmtpAttr(), + KMceAvcProfileIopValOffset, + KMceAvcProfileIopValLen, + KMceAvcProfileIopDefault ); + ReplaceProfileLevelIdValuePart( + ptrFmtp, existingIop, KMceAvcProfileIopValOffset ); + } + + if ( iStream && iStream->BoundStream() ) + { + // In case of two-way video streams, sprop-parameter-set (configkey) + // from incoming sdp is put to receive stream and it will not override + // existing key in sendstream + if ( IS_SENDSTREAM( iStream ) && IS_RECEIVESTREAM( &iStream->BoundStreamL() ) ) + { + CMceComVideoCodec* boundCodec = + static_cast( + iStream->BoundStreamL().FindCodecL( *this ) ); + + HBufC8* spropParameterSetsVal = + StripFmtpParameterL( ptrFmtp, KMceAvcSpropParameterSetsFmtp() ); + CleanupStack::PushL( spropParameterSetsVal ); + if ( boundCodec && + CMceComVideoCodec::IsConfigKeyValid( spropParameterSetsVal ) ) + { + boundCodec->SetConfigKeyL( spropParameterSetsVal ); + } + CleanupStack::PopAndDestroy( spropParameterSetsVal ); + } + } + + SetFmtpAttributeL( ptrFmtp, aReset ); + + CleanupStack::PopAndDestroy( fmtp ); + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::FtmpForOutgoingSdpLC +// ----------------------------------------------------------------------------- +// +HBufC8* CMceComAvcCodec::FtmpForOutgoingSdpLC() + { + HBufC8* fmtp = CMceComCodec::FtmpForOutgoingSdpLC(); + if ( iStream && iStream->BoundStream() ) + { + // In case of two-way video streams, sprop-parameter-set (configkey) + // for outgoing sdp is taken from send stream + if ( IS_RECEIVESTREAM( iStream ) && IS_SENDSTREAM( &iStream->BoundStreamL() ) ) + { + TPtr8 ptrFmtp( fmtp->Des() ); + + CMceComVideoCodec* boundCodec = + static_cast( + iStream->BoundStreamL().FindCodecL( *this ) ); + if ( boundCodec && boundCodec->IsConfigKeyValid() ) + { + HBufC8* spropParameterSetsVal = + StripFmtpParameterL( ptrFmtp, KMceAvcSpropParameterSetsFmtp() ); + delete spropParameterSetsVal; + + HBufC8* newFmtp = AddFmtpParameterL( ptrFmtp, + KMceAvcSpropParameterSetsFmtp(), + *boundCodec->iConfigKey ); + CleanupStack::PopAndDestroy( fmtp ); + fmtp = newFmtp; + CleanupStack::PushL( fmtp ); + } + + } + } + return fmtp; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::StripFmtpParameterL +// ----------------------------------------------------------------------------- +// +HBufC8* CMceComAvcCodec::StripFmtpParameterL( + TPtr8& aInputFmtp, + const TDesC8& aStrippedParameter ) + { + HBufC8* strippedParameter = NULL; + TInt startIndex = aInputFmtp.FindF( aStrippedParameter ); + if ( startIndex != KErrNotFound ) + { + TPtrC8 parameterVal = aInputFmtp.Mid( startIndex + aStrippedParameter.Length() ); + TInt endIndex = parameterVal.Locate( KMceAvcFmtpParameterSeparator ); + if ( endIndex == KErrNotFound ) + { + endIndex = parameterVal.Length(); + } + + if ( endIndex > 0 ) + { + strippedParameter = parameterVal.Mid( 0, endIndex ).AllocLC(); + + // Remove stripped part from input fmtp + TInt deleteLen( endIndex + aStrippedParameter.Length() + 1 ); + + aInputFmtp.Delete( startIndex, deleteLen ); + aInputFmtp.Trim(); + + CleanupStack::Pop( strippedParameter ); + } + } + return strippedParameter; + } + +// ----------------------------------------------------------------------------- +// CMceComAvcCodec::AddFmtpParameterL +// ----------------------------------------------------------------------------- +// +HBufC8* CMceComAvcCodec::AddFmtpParameterL( + const TDesC8& aInputFmtp, + const TDesC8& aAddedParameter, + const TDesC8& aAddedParameterVal ) + { + const TInt KMceAvcAdditionalLen = 2; + HBufC8* outputFmtp = HBufC8::NewL( aInputFmtp.Length() + + aAddedParameter.Length() + + aAddedParameterVal.Length() + + KMceAvcAdditionalLen ); + TPtr8 ptrOutputFmtp( outputFmtp->Des() ); + + // Add original param + ptrOutputFmtp.Append( aInputFmtp ); + + // Add separators if needed + TInt lastSeparatorIndex = aInputFmtp.LocateReverse( KMceAvcFmtpParameterSeparator ); + if ( aInputFmtp.Length() > 0 && lastSeparatorIndex < ( aInputFmtp.Length() - 2 ) ) + { + ptrOutputFmtp.Append( KMceAvcFmtpParameterSeparator ); + } + TInt lastSpaceIndex = aInputFmtp.LocateReverse( KMceAvcFtmpParameterSpace ); + if ( aInputFmtp.Length() > 0 && lastSpaceIndex < ( aInputFmtp.Length() - 1 ) ) + { + ptrOutputFmtp.Append( KMceAvcFtmpParameterSpace ); + } + + // Add new parameter + ptrOutputFmtp.Append( aAddedParameter ); + ptrOutputFmtp.Append( aAddedParameterVal ); + + return outputFmtp; + } + +#endif + +// End of File + +