--- /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 <MmfDatabuffer.h>
+#include <mmfcontrollerpluginresolver.h>
+#include <mmfutilities.h>
+#include <mmf/plugin/mmfCodecImplementationUIDs.hrh>
+#include <MMFCodec.h>
+
+
+
+// MACROS
+
+// Debug print macro
+#if defined _DEBUG
+#include <e32svr.h>
+#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<TDesC8&>(*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<TInt> 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<TDesC8&>(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;
+ }
+