diff -r 000000000000 -r 951a5db380a0 videoeditorengine/audioeditorengine/src/ProcEncoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videoeditorengine/audioeditorengine/src/ProcEncoder.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,702 @@ +/* +* Copyright (c) 2010 Ixonos Plc. +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the "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: +* Ixonos Plc +* +* Description: +* +*/ + + + +#include "ProcEncoder.h" +#include "audconstants.h" +#include +#include +#include +#include +#include + + + +// MACROS + +// Debug print macro +#if defined _DEBUG +#include +#define PRINT(x) RDebug::Print x; +#else +#define PRINT(x) +#endif + +// ----------------------------------------------------------------------------- +// TCMRAMREncParams +// Encoding parameters structure for SW AMR codec +// ----------------------------------------------------------------------------- +// +class TVedACAMREncParams + { +public: + // encoding mode (for AMR-NB: 0=MR475,1=MR515,...,7=MR122, default 7) + TInt iMode; + // DTX flag (TRUE or default FALSE) + TInt iDTX; + }; + +CProcEncoder* CProcEncoder::NewL() + + { + CProcEncoder* self = NewLC(); + CleanupStack::Pop(self); + return self; + + } + + +CProcEncoder* CProcEncoder::NewLC() + + { + + CProcEncoder* self = new (ELeave) CProcEncoder(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + + } + +CProcEncoder::~CProcEncoder() + { + + + delete iSourceInputBuffer; + + delete iDestInputBuffer; + + delete iDestCodec; + + + } + + + + +TBool CProcEncoder::InitL(TAudType aAudioType, TInt aTargetSamplingRate, TChannelMode aChannelMode, + TInt aBitrate) + { + PRINT((_L("CProcEncoder::InitL() in"))); + + if (aAudioType == EAudAMR) + { + iOutputFrameDurationMilli = 20; + } + else if (aAudioType == EAudAAC_MPEG4) + { + iOutputFrameDurationMilli = (1024*1000)/(aTargetSamplingRate); + } + else + { + // only AMR & AAC encoding supported + PRINT((_L("CProcEncoder::InitL() out, unsupported audio type"))); + User::Leave(KErrNotSupported); + } + + iToBitRate = aBitrate; + + iAudioType = aAudioType; + + iNumberOfFramesInOutputBuffer = 0; + + iToSampleRate = aTargetSamplingRate; + + iToChannels = 1; + + if (aChannelMode == EAudStereo) + { + iToChannels = 2; + } + + + TInt destInputBufferSize = 0; + TInt sourceInputBufferSize = 0; + + // input buffer size: + // we never get longer than 64 milliseconds input + // as it is limited by the input formats + // for 16kHz AAC the frame duration is 64 ms + // + const TInt KMaxInputDurationMilli = 64; + + // multiplied by 2 as we have a bitdepth of 16 + sourceInputBufferSize = (2*aTargetSamplingRate*KMaxInputDurationMilli)/1000; + + if (aChannelMode == EAudStereo) + { + sourceInputBufferSize *= 2; + } + + if ( aAudioType == EAudAMR ) + { + + // from 64 ms input we can have maximum 4 AMR frames + destInputBufferSize = KAedMaxAMRFrameLength*4; + + + } + else if (aAudioType == EAudAAC_MPEG4) + { + + if ( aChannelMode == EAudSingleChannel ) + { + destInputBufferSize = KAedMaxAACFrameLengthPerChannel; + } + else + { + destInputBufferSize = 2 * KAedMaxAACFrameLengthPerChannel; + + } + } + + if ( iSourceInputBuffer ) + { + delete iSourceInputBuffer; + iSourceInputBuffer = NULL; + } + + iSourceInputBuffer = CMMFDataBuffer::NewL(sourceInputBufferSize*5); + + + if ( iDestInputBuffer ) + { + delete iDestInputBuffer; + iDestInputBuffer = NULL; + } + + TInt errC = KErrNone; + + if (aAudioType == EAudAMR) + { + + // shouldn't get more than 6 AMR frames at a time -> 120 ms + iDestInputBuffer = CMMFDataBuffer::NewL( destInputBufferSize); + + } + else + { + + iDestInputBuffer = CMMFDataBuffer::NewL( destInputBufferSize); + + } + + TRAP (errC,SetDestCodecL()); + + if (errC != KErrNone) + { + // initialization failed for some reason + User::Leave(KErrNotSupported); + + } + + TInt err = KErrNone; + + if ( iAudioType == EAudAAC_MPEG4 ) + { + TRAP( err, ConfigureAACEncoderL()); + + } + else if (iAudioType == EAudAMR) + { + TRAP( err, ConfigureAMREncoderL()); + } + + + if (err != KErrNone || errC != KErrNone) + { + + // initialization failed for some reason + User::Leave(KErrNotSupported); + } + + iReady = ETrue; + PRINT((_L("CProcEncoder::InitL() out"))); + + return ETrue; + } + +TBool CProcEncoder::FillEncBufferL(const TDesC8& aRawFrame, HBufC8* aEncBuffer, TInt& aOutputDurationMilli) + { + PRINT((_L("CProcEncoder::FillEncBufferL() in"))); + + aOutputDurationMilli = 0; + + + if (!iReady) + { + User::Leave(KErrNotReady); + } + + iEncBuffer = aEncBuffer; + + if (iEncBuffer->Length() == 0) + { + iNumberOfFramesInOutputBuffer = 0; + } + + if ( !aRawFrame.Length() ) + { + return EFalse; + } + + if ( (TInt)(aRawFrame.Length() + iSourceInputBuffer->Position() ) > iSourceInputBuffer->Data().MaxLength() ) + { + ReAllocBufferL( iSourceInputBuffer, aRawFrame.Length() + iSourceInputBuffer->Position() ); + + } + + + // copy the input data to MMF buffer + iSourceInputBuffer->Data().SetLength( 0 ); + iSourceInputBuffer->SetPosition( 0 ); + + iSourceInputBuffer->Data().Append( aRawFrame ); + iSourceInputBuffer->Data().SetLength( iSourceInputBuffer->Data().Length() ); + iSourceInputBuffer->SetStatus(EFull); + + iDestInputBuffer->Data().SetLength(0); + iDestInputBuffer->SetPosition(0); + + FeedCodecL( iDestCodec, iSourceInputBuffer, iDestInputBuffer); + + + + iDestInputBuffer->Data().SetLength(0); + iDestInputBuffer->SetPosition(0); + + if (iEncBuffer->Size() > 0) + { + + aOutputDurationMilli = iOutputFrameDurationMilli * iNumberOfFramesInOutputBuffer; + PRINT((_L("CProcEncoder::FillEncBufferL() out with ETrue (complete)"))); + return ETrue; + } + + PRINT((_L("CProcEncoder::FillEncBufferL() out with EFalse (incomplete)"))); + return EFalse; + } + +TAudType CProcEncoder::DestAudType() + { + return iAudioType; + } + +void CProcEncoder::ConstructL() + { + + } + +CProcEncoder::CProcEncoder() + { + + } + + +void CProcEncoder::ConfigureAMREncoderL() + { + PRINT((_L("CProcEncoder::ConfigureAMREncoderL() in"))); + + if ( (iToBitRate < KAedMinAMRBitRate) || (iToBitRate > KAedMaxAMRBitRate) ) + { + User::Leave( KErrArgument ); + } + + TVedACAMREncParams* configData = new (ELeave) TVedACAMREncParams; + CleanupStack::PushL( configData ); + + // the bitrates in the switch & if below are not magic numbers but AMR bitrates in bits per seconds and mode indices from TAmrEncParams + + switch ( iToBitRate ) + { + case 4750: + configData->iMode = 0; + configData->iDTX = EFalse; + break; + case 5150: + configData->iMode = 1; + configData->iDTX = EFalse; + break; + case 5900: + configData->iMode = 2; + configData->iDTX = EFalse; + break; + case 6700: + configData->iMode = 3; + configData->iDTX = EFalse; + break; + case 7400: + configData->iMode = 4; + configData->iDTX = EFalse; + break; + case 7950: + configData->iMode = 5; + configData->iDTX = EFalse; + break; + case 10200: + configData->iMode = 6; + configData->iDTX = EFalse; + break; + case 12200: + configData->iMode = 7; + configData->iDTX = EFalse; + break; + default : + // Interprets now the bitrate proprietarily: bitrates that are not exactly AMR bitrates + // mean that voice activity detection is used and the AMR bitrates is the given bitrate rounded upwards to the next AMR bitrate + if ( iToBitRate < 4750 ) + { + configData->iMode = 0; + configData->iDTX = ETrue; + } + else if ( iToBitRate < 5150 ) + { + configData->iMode = 1; + configData->iDTX = ETrue; + } + else if ( iToBitRate < 5900 ) + { + configData->iMode = 2; + configData->iDTX = ETrue; + } + else if ( iToBitRate < 6700 ) + { + configData->iMode = 3; + configData->iDTX = ETrue; + } + else if ( iToBitRate < 7400 ) + { + configData->iMode = 4; + configData->iDTX = ETrue; + } + else if ( iToBitRate < 7950 ) + { + configData->iMode = 5; + configData->iDTX = ETrue; + } + else if ( iToBitRate < 10200 ) + { + configData->iMode = 6; + configData->iDTX = ETrue; + } + else // must be: ( iToBitRate < 12200 ) since checked earlier + { + configData->iMode = 7; + configData->iDTX = ETrue; + } + } + + TUid uid ={KUidMmfCodecAudioSettings}; // Use Uid reserved for codec configurations + iDestCodec->ConfigureL( uid, reinterpret_cast(*configData)); + CleanupStack::PopAndDestroy( configData ); + PRINT((_L("CProcEncoder::ConfigureAMREncoderL() out"))); + } + +// ----------------------------------------------------------------------------- +// CProcEncoder::ConfigureAACEncoderL +// +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CProcEncoder::ConfigureAACEncoderL() + { + PRINT((_L("CProcEncoder::ConfigureAACEncoderL() in"))); + + TInt i = 0; + TBool iSet = EFalse; + for ( i = 0; i < KAedNumSupportedAACSampleRates; i++ ) + { + if ( iToSampleRate == KAedSupportedAACSampleRates[i] ) + { + iSet = ETrue; + } + } + if ( !iSet ) + { + // given samplerate is not supported + User::Leave( KErrNotSupported ); + } + + // AAC codec interprets the input as array of TInts, not as a class + RArray config; + config.Append (iToBitRate); //BitRate + config.Append (iToSampleRate); //SamplingRate + config.Append (0); //iToolFlags + config.Append (iToChannels); //iNumChan + + // NOTE Ali: for 48kHz stereo we might need to use ADTS as output format + // as we can get more than one frame in synchronous call! + config.Append (0); //iuseFormat 0=RAW; 1=ADTS; 2=ADIF + config.Append (0); // 0 = 1 Frame only; 1 = Full Buffer + + TUid uid ={KUidMmfCodecAudioSettings}; // Use Uid reserved for codec configurations + iDestCodec->ConfigureL( uid, reinterpret_cast(config)); + config.Close(); + PRINT((_L("CProcEncoder::ConfigureAACEncoderL() out"))); + } + + +void CProcEncoder::ReAllocBufferL( CMMFDataBuffer* aBuffer, TInt aNewMaxSize ) + { + if ( aBuffer->Data().Length() ) + { + TInt position = aBuffer->Position(); + TInt length = aBuffer->Data().Length(); + HBufC8* oldData = aBuffer->Data().AllocL(); + CleanupStack::PushL( oldData ); + ((CMMFDescriptorBuffer*)aBuffer)->ReAllocBufferL( aNewMaxSize ); + aBuffer->Data().Copy( *oldData ); + CleanupStack::PopAndDestroy( oldData ); + aBuffer->Data().SetLength( length ); + aBuffer->SetPosition( position ); + } + else + { + ((CMMFDescriptorBuffer*)aBuffer)->ReAllocBufferL( aNewMaxSize ); + } + } + +void CProcEncoder::FeedCodecL( CMMFCodec* aCodec, CMMFDataBuffer* aSourceBuffer, CMMFDataBuffer* aDestBuffer ) + { + PRINT((_L("CProcEncoder::FeedCodecL() in"))); + TBool completed = EFalse; + TCodecProcessResult result; + TInt aSrcUsed = 0; + + while ( !completed ) + { + + // encode and check the result + result = EncodeL(aCodec, aSourceBuffer, aDestBuffer); + + switch ( result.iStatus ) + { + case TCodecProcessResult::EProcessIncomplete: + // Not all data from input was consumed (EncodeL updated buffer members), but output was generated + + iEncBuffer->Des().Append(aDestBuffer->Data()); + iNumberOfFramesInOutputBuffer++; + + aDestBuffer->Data().SetLength( 0 ); + aDestBuffer->SetPosition( 0 ); + + break; + + case TCodecProcessResult::EProcessComplete: + // all data from input was used and output was generated + + iEncBuffer->Des().Append(aDestBuffer->Data()); + + iNumberOfFramesInOutputBuffer++; + + aDestBuffer->Data().SetLength( 0 ); + aDestBuffer->SetPosition( 0 ); + + //completed = ETrue; + + break; + + case TCodecProcessResult::EDstNotFilled: + // need more input data, can't fill the output yet; put it back to the empty queue + //completed = ETrue; + + break; + + default: + // EEndOfData, EProcessError, EProcessIncompleteRepositionRequest, EProcessCompleteRepositionRequest + User::Leave( KErrUnknown ); + } + + aSrcUsed += result.iSrcBytesProcessed; + if (aSrcUsed >= (STATIC_CAST(CMMFDataBuffer*, aSourceBuffer)->Data().Length())) + { + PRINT((_L("CProcEncoder::FeedCodecL() ProcessL is completed aSrcUsed[%d]"), aSrcUsed)); + completed = ETrue; + } + + + } + + PRINT((_L("CProcEncoder::FeedCodecL() out"))); + } + + +TBool CProcEncoder::GetIsSupportedDestCodec() + { + TFourCC fourCC; + TUid euid; + + if (iAudioType == EAudAMR) + { + fourCC = TFourCC(KMMFFourCCCodeAMR); + euid = KAedAMRNBEncSWCodecUid; + } + else if (iAudioType == EAudAAC_MPEG4 ) + { + fourCC = TFourCC(KMMFFourCCCodeAAC); + euid = KAedAACEncSWCodecUid; + } + + _LIT8(emptyFourCCString, " , "); + TBufC8<9> fourCCString(emptyFourCCString); + TPtr8 fourCCPtr = fourCCString.Des(); + TPtr8 fourCCPtr1(&fourCCPtr[0], 4); + TPtr8 fourCCPtr2(&fourCCPtr[5], 4 ); + + TFourCC srcFourCC(' ','P','1','6'); + srcFourCC.FourCC(&fourCCPtr1); + fourCC.FourCC(&fourCCPtr2); + + TBool found = EFalse; + TRAPD( err, found = CheckIfCodecAvailableL( fourCCPtr, euid )); + + if (err == KErrNone) + { + return found; + } + else + { + return EFalse; + } + + } + + +void CProcEncoder::SetDestCodecL() + { + PRINT((_L("CProcEncoder::SetDestCodecL() in"))); + + if ( !GetIsSupportedDestCodec() ) + { + PRINT((_L("CProcEncoder::SetDestCodecL() error, unsupported codec"))); + User::Leave( KErrNotSupported ); + } + + if ( iDestCodec ) + { + delete iDestCodec; + iDestCodec = NULL; + } + + TUid euid = TUid::Null(); + + if (iAudioType == EAudAMR) + { + euid = KAedAMRNBEncSWCodecUid; + } + else if (iAudioType == EAudAAC_MPEG4 ) + { + euid = KAedAACEncSWCodecUid; + } + + + iDestCodec = CMMFCodec::NewL (euid); + iReady = EFalse; + + PRINT((_L("CProcEncoder::SetDestCodecL() out"))); + } + + +TBool CProcEncoder::CheckIfCodecAvailableL( + const TDesC8& aCodecFourCCString, const TUid& aCodecUId ) + { + PRINT((_L("CProcEncoder::CheckIfCodecAvailableL() in"))); + TBool found = EFalse; + + // Create a TEcomResolverParams structure. + TEComResolverParams resolverParams ; + resolverParams.SetDataType( aCodecFourCCString ) ; + resolverParams.SetWildcardMatch( EFalse ) ; + + RImplInfoPtrArray plugInArray ; // Array to return matching decoders in (place on cleanupstack _after_ ListImplementationsL() ) + + TUid UidMmfPluginInterfaceCodec = {KMmfUidPluginInterfaceCodec}; + + // ListImplementationsL leaves if it cannot find anything so trap the error and ignore it. + TRAPD( err, REComSession::ListImplementationsL(UidMmfPluginInterfaceCodec, resolverParams, plugInArray ) ) ; + CleanupResetAndDestroyPushL(plugInArray); + + if (err == KErrNone) + { + found = EFalse; + for ( TInt i = 0; i < plugInArray.Count(); i++) + { + // there is a match, but 1st we need to ensure it is the one we have tested with, and that have compatible implementation of ConfigureL + PRINT((_L("CProcEncoder::CheckIfCodecAvailable() plugin found with Uid 0x%x"), plugInArray[i]->ImplementationUid().iUid )); + if ( plugInArray[i]->ImplementationUid() == aCodecUId ) + { + //match accepted + PRINT((_L("CProcEncoder::CheckIfCodecAvailable() plugin accepted"))); + found = ETrue; + } + } + } + else + { + PRINT((_L("CProcEncoder::CheckIfCodecAvailable() Error in ListImp.: %d"), err)); + //no match + found = EFalse; + } + + + CleanupStack::PopAndDestroy(); //plugInArray + PRINT((_L("CProcEncoder::CheckIfCodecAvailableL() out"))); + return found; + } + +TCodecProcessResult CProcEncoder::EncodeL( CMMFCodec* aCodec, CMMFDataBuffer* aInBuffer, CMMFDataBuffer* aOutBuffer) + { + PRINT((_L("CProcEncoder::EncodeL() in, input pos: %d, length: %d"), aInBuffer->Position(), aInBuffer->Data().Length() )); + TCodecProcessResult result; + + result = aCodec->ProcessL (*aInBuffer, *aOutBuffer); + + switch (result.iStatus) + { + case TCodecProcessResult::EProcessComplete: + // finished processing source data, all data in sink buffer + PRINT((_L("CProcEncoder::FeedCodecL() EProcessComplete"))); + aInBuffer->SetPosition( 0 ); + aInBuffer->Data().SetLength(0); + break; + + case TCodecProcessResult::EDstNotFilled: + // the destination is not full, we need more data. Handled in caller + PRINT((_L("CProcEncoder::FeedCodecL() EDstNotFilled"))); + aInBuffer->SetPosition( 0 ); + aInBuffer->Data().SetLength(0); + break; + + case TCodecProcessResult::EProcessIncomplete: + // the sink was filled before all the source was processed + PRINT((_L("CProcEncoder::FeedCodecL() EProcessIncomplete"))); + aOutBuffer->SetPosition( 0 ); + aInBuffer->SetPosition( aInBuffer->Position() + result.iSrcBytesProcessed ); + break; + + default: + break; + } + + + + PRINT((_L("CProcEncoder::EncodeL() out, %d -> %d"),result.iSrcBytesProcessed, result.iDstBytesAdded)); + PRINT((_L("CProcEncoder::EncodeL() out, input pos: %d, length: %d"), aInBuffer->Position(), aInBuffer->Data().Length() )); + return result; + } +