videoeditorengine/audioeditorengine/src/ProcEncoder.cpp
changeset 0 951a5db380a0
--- /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;
+    }
+