diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccfilesourcesink/src/mccfileaudio.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccfilesourcesink/src/mccfileaudio.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,506 @@ +/* +* 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 "mccfileaudio.h" +#include "mmcccodecinformation.h" +#include "mccperiodicrunner.h" +#include "mccfilesourcelogs.h" +#include "mccinternaldef.h" + + +// ----------------------------------------------------------------------------- +// CMccFileAudio::NewL +// ----------------------------------------------------------------------------- +// +CMccFileAudio* CMccFileAudio::NewL( CMccFileSourceImpl& aSource ) + { + CMccFileAudio* self = new (ELeave) CMccFileAudio ( aSource ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::ConstructL +// ----------------------------------------------------------------------------- +// +void CMccFileAudio::ConstructL() + { + CMccFileSourceTypeBase::ConstructL(); + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::CMccFileAudio +// ----------------------------------------------------------------------------- +// +CMccFileAudio::CMccFileAudio( CMccFileSourceImpl& aSource ) + : CMccFileSourceTypeBase ( aSource, KUidMediaTypeAudio ), + iBufferType ( CCMRMediaBuffer::EAudioAMRNB ) + { + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::~CMccFileAudio +// ----------------------------------------------------------------------------- +// +CMccFileAudio::~CMccFileAudio( ) + { + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::FillBufferL +// ----------------------------------------------------------------------------- +// +void CMccFileAudio::FillBufferL( + CMMFBuffer* aBuffer, + MDataSink* aConsumer ) + { + CMccFileSourceTypeBase::FillBufferL( aBuffer, aConsumer ); + + // There might be pending audio frames, read the oldest one immediately + WriteBufferL(); + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::ParseUpdateAudioDescriptions +// ----------------------------------------------------------------------------- +// +TBool CMccFileAudio::ParseUpdateAudioDescriptions( MP4Handle aMP4Handle ) + { + TBool isAudio = EFalse; + + mp4_u32 timeScale = 0; + if ( MP4ParseRequestAudioDescription( aMP4Handle, + ( mp4_u32* ) &iLength, ( mp4_u32* ) &iType, + ( mp4_u8* ) &iFramesPerSample, ( mp4_u32* ) &timeScale, + ( mp4_u32* ) &iAverageBitRate ) + == MP4_OK ) + { + if ( iType == MP4_TYPE_AMR_NB ) + { + __FILESOURCE_CONTROLL( "CMccFileAudio:ParseUpdateAudioDescriptions \ +MP4_TYPE_AMR_NB!" ) + + iBufferType = CCMRMediaBuffer::EAudioAMRNB; + isAudio = ETrue; + iFourCC = TFourCC( KMccFourCCIdAMRNB ); + } + else if ( iType != MP4_TYPE_NONE ) + { + __FILESOURCE_CONTROLL( "CMccFileAudio:ParseUpdateAudioDescriptions \ +contains unsupported audio" ) + + iFourCC = TFourCC( KMccFourCCUnsupported ); + } + else + { + // NOP + } + } + return isAudio; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::DoSetPositionL +// ----------------------------------------------------------------------------- +// +void CMccFileAudio::DoSetPositionL( TUint32 aPosition ) + { + __FILESOURCE_CONTROLL( "CMccFileAudio::DoSetPositionL" ) + + __ASSERT_ALWAYS( aPosition <= iLength, User::Leave( KErrArgument ) ); + + mp4_u32 videoPos = 0; + if ( MP4ParseSeek( iMP4Handle, ( mp4_u32 ) aPosition, + ( mp4_u32* ) &iPosition, ( mp4_u32* ) &videoPos, MP4TRUE ) + != MP4_OK ) + { + User::Leave( KErrGeneral ); + } + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::Type +// ----------------------------------------------------------------------------- +// +CCMRMediaBuffer::TBufferType CMccFileAudio::Type() + { + return iBufferType; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::GetFourCC +// ----------------------------------------------------------------------------- +// +TFourCC CMccFileAudio::GetFourCC() + { + return iFourCC; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::TickCallBack +// ----------------------------------------------------------------------------- +// +TCallBack CMccFileAudio::TickCallBack() + { + return TCallBack( TickAudioL, this ); + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::PositionL +// ----------------------------------------------------------------------------- +// +TUint32 CMccFileAudio::Position() + { + return iPosition; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::DurationL +// ----------------------------------------------------------------------------- +// +TUint32 CMccFileAudio::Duration() + { + return iLength; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::AudioBitRateL +// ----------------------------------------------------------------------------- +// +TUint32 CMccFileAudio::AudioBitRate() + { + return iAverageBitRate; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::VideoFrameSizeL +// ----------------------------------------------------------------------------- +// +TSize CMccFileAudio::VideoFrameSize() + { + TSize size; + return size; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::VideoFrameRateL +// ----------------------------------------------------------------------------- +// +TReal CMccFileAudio::VideoFrameRateL() + { + return 0; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::StartTimerL +// ----------------------------------------------------------------------------- +// +void CMccFileAudio::StartTimerL() + { + __FILESOURCE_CONTROLL( "CMccFileAudio::StartTimerL" ) + + if ( IsPaused() ) + { + SetPaused( EFalse ); + + SetPositionL( iPosition, ETrue ); + } + else + { + SetStartTime(); + } + + const TInt KMccFileIntervalMinInterval = 60000; + const TInt KMccFileAudioPTime = 20000; + TInt tickIntervalAudio = 0; + iReadsPerInterval = 0; + + __ASSERT_ALWAYS( iFramesPerSample > 0, User::Leave( KErrArgument ) ); + + while ( tickIntervalAudio < KMccFileIntervalMinInterval ) + { + tickIntervalAudio += KMccFileAudioPTime * iFramesPerSample; + iReadsPerInterval++; + } + + __FILESOURCE_CONTROLL_INT1( "CMccFileAudio::StartTimer (timer):", + tickIntervalAudio ) + + iTimerInterval = tickIntervalAudio; + iCorrectionInterval = iTimerInterval; + + iPeriodicRunner->Start( tickIntervalAudio, TCallBack( TickAudioL, this ) ); + + __FILESOURCE_CONTROLL( "CMccFileAudio::StartTimerL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::TickAudioL +// ----------------------------------------------------------------------------- +// +TInt CMccFileAudio::TickAudioL( TAny* aObject ) + { + __FILESOURCE_CONTROLL( "CMccFileAudio::TickAudioL" ) + + CMccFileAudio* self = static_cast( aObject ); + + TBool read( ETrue ); + TInt readsPerInterval( self->iReadsPerInterval ); + for ( TInt i = 0; i < readsPerInterval && read; i++ ) + { + // Do timing correction only after everything within this cycle has + // been read + TBool doTimingCorrection( ( i + 1 ) == readsPerInterval ); + read = self->ReadFrameL( doTimingCorrection ); + } + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::ReadFrameL +// ----------------------------------------------------------------------------- +// +TBool CMccFileAudio::ReadFrameL( TBool aDoTimingCorrection ) + { + __FILESOURCE_CONTROLL( "CMccFileAudio::ReadFrameL" ) + + + if ( MP4ParseIsFrameAvailable( iMP4Handle, MP4_TYPE_AMR_NB ) != MP4_OK ) + { + __FILESOURCE_CONTROLL( "CMccFileAudio::ReadFrameL, no audio" ) + + SetPaused( ETrue ); + TRAPD( positionErr, SetPositionL( 0 ) ); + iSource.PauseAudioL( positionErr ); + return EFalse; + } + + MP4ParseNextFrameSize( iMP4Handle, MP4_TYPE_AMR_NB, + ( mp4_u32* ) &iBufferSize ); + + HBufC8* mediaBuffer = HBufC8::NewLC( iBufferSize ); + TPtr8 mediaSinkBuffer = mediaBuffer->Des(); + mediaSinkBuffer.SetLength( iBufferSize ); + TUint8* bufPtr = CONST_CAST(TUint8*, mediaSinkBuffer.Ptr()); + + TUint32 oldPosition = iPosition; + if ( MP4ParseReadAudioFrames( iMP4Handle, + ( mp4_u8* ) bufPtr, + ( mp4_u32 ) iBufferSize, ( mp4_u32* ) &iAudioSize, + ( mp4_u32* ) &iPosition, ( mp4_u32* ) &iReturnedFrames, + NULL ) == MP4_OK ) + { + __FILESOURCE_CONTROLL_INT1( ":ReadFrameL:ReadAudioFrameL, \ +read, time position", iPosition ) + __FILESOURCE_CONTROLL_INT1( ":ReadFrameL:ReadAudioFrameL, \ +read, returned frames", iReturnedFrames ) + + if ( aDoTimingCorrection ) + { + DoTimingCorrection( iPosition ); + } + + // Update read interval (how much position changes on each frame read) + iReadInterval = iPosition - oldPosition; + + // Calculate real frame size from sample size + TInt frameSize = iBufferSize / iReturnedFrames; + TUint counter = 0; + TInt addToTimeStamp = 0; + TInt startPosition = 0; + TInt mediaBufferLen = mediaBuffer->Length(); + + while ( ( counter < iReturnedFrames ) && + ( startPosition < mediaBufferLen ) ) + { + counter++; + + frameSize = GetFrameLength( mediaBuffer->Mid( startPosition ) ); + if ( frameSize != 0 && ( startPosition + frameSize <= mediaBufferLen ) ) + { + TTimeIntervalMicroSeconds timeStamp = + GetTimeStamp( addToTimeStamp ); + + CMccFrameItem* item = new (ELeave) CMccFrameItem(); + CleanupStack::PushL( item ); + item->iFrame = HBufC8::NewL( frameSize ); + item->iFrame->Des().Copy( + mediaBuffer->Mid( startPosition, frameSize ) ); + item->iTimeStamp = timeStamp; + User::LeaveIfError( iFrames.Append( item ) ); + CleanupStack::Pop( item ); + } + addToTimeStamp += 20000; + startPosition += frameSize; + } + } + else + { + __FILESOURCE_CONTROLL( ":ReadFrameL:ReadAudioFrameL, \ +reading frames failed" ) + } + CleanupStack::PopAndDestroy(mediaBuffer); + mediaBuffer = NULL; + + __FILESOURCE_CONTROLL( ":ReadFrameL:ReadAudioFrameL, \ +writing buffer, copying" ) + + WriteBufferL(); + + return ETrue; + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::WriteBufferL +// ----------------------------------------------------------------------------- +// +void CMccFileAudio::WriteBufferL() + { + __FILESOURCE_CONTROLL("CMccFileAudio::WriteBufferL") + + if ( iFrames.Count() && iConsumer && iConsumerBuffer ) + { + CMMFDataBuffer* buf = static_cast(iConsumerBuffer); + + HBufC8* audioFrame = (iFrames[0])->iFrame; + // to be sure the source buffer length is greater or equal + if ( buf->Data().MaxLength() >= audioFrame->Des().Length() ) + { + buf->Data().Copy( *audioFrame ); + iConsumerBuffer->SetTimeToPlay((iFrames[0])->iTimeStamp); + iConsumerBuffer->SetLastBuffer(EFalse); + iConsumerBuffer->SetFrameNumber( iSequenceNum ); + delete iFrames[0]; + iFrames.Remove(0); + audioFrame = NULL; + iConsumer->BufferFilledL( iConsumerBuffer ); + iConsumer = NULL; + iConsumerBuffer = NULL; + iSequenceNum++; + __FILESOURCE_CONTROLL("CMccFileAudio::WriteBufferL, done") + } + else + { + __FILESOURCE_CONTROLL("CMccFileAudio::WriteBufferL, frame dropped") + + delete iFrames[0]; + iFrames.Remove(0); + audioFrame = NULL; + } + } + else + { + __FILESOURCE_CONTROLL("CMccFileAudio::WriteBufferL, writing ignored") + } + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::GetFrameLength +// ----------------------------------------------------------------------------- +// +TUint32 CMccFileAudio::GetFrameLength( TPtrC8 aData ) + { + const TUint8 *ptrData=aData.Ptr(); + //read FT from data + TUint8 fT = (TUint8) ( *ptrData & 0x78 ); + fT = TUint8 ( fT >> 3 ); + //return frame length + switch ( fT ) + { + case 0: //amr 4.75 + { + const TUint32 number13 = 13; + return number13; + } + case 1: //amr 5.15 + { + const TUint32 number14 = 14; + return number14; + } + case 2: //amr 5.9 + { + const TUint32 number16 = 16; + + return number16; + } + case 3: //amr 6.7 + { + const TUint32 number18 = 18; + return number18; + } + case 4: //amr 7.4 + { + const TUint32 number20 = 20; + return number20; + } + case 5: //amr 7.95 + { + const TUint32 number21 = 21; + return number21; + } + case 6: //amr 10.2 + { + const TUint32 number27 = 27; + return number27; + } + case 7: //amr 12.2 + { + const TUint32 number32 = 32; + return number32; + } + case 8: //amr SID + { + const TUint32 number6 = 6; + return number6; + } + case 15: //no data + { + const TUint32 number1 = 1; + return number1; + } + default: //not arm narrowband + { + const TUint32 number0 = 0; + return number0; + } + } + } + +// ----------------------------------------------------------------------------- +// CMccFileAudio::GetTimeStamp +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CMccFileAudio::GetTimeStamp( TUint32 aAddToTimeStamp ) + { + TInt64 position = iPosition + iPositionModifier; + TUint32 position2 = ( position < 0 ) ? 0 : (TUint32)position; + TTimeIntervalMicroSeconds timeStamp = + TTimeIntervalMicroSeconds( ( (TInt64) position2 * KMccMicroToMilliConst ) + aAddToTimeStamp ); + + __FILESOURCE_CONTROLL_INT1( "CMccFileAudio::GetTimeStamp timestamp (without clock frequency):", + timeStamp.Int64() ) + + return timeStamp; + } +