diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccfilesourcesink/src/mccfilesourceimpl_withtimer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccfilesourcesink/src/mccfilesourceimpl_withtimer.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,1438 @@ +/* +* 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 FILES +#include +#include +#include "MccFileSourceImpl.h" +#include "MmccCodecInformation.h" +#include "MccFileSourceLogs.h" +#include "MccTickVideoObserver.h" +#include "MccTickAudioObserver.h" + + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::NewL +// Static constructor. +// ----------------------------------------------------------------------------- +// +CMccFileSourceImpl* CMccFileSourceImpl::NewL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::NewL" ) + + CMccFileSourceImpl* self = new ( ELeave ) CMccFileSourceImpl(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::ConstructL +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::ConstructL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ConstructL" ) + } + +// ----------------------------------------------------------------------------- +// Destructor. +// ----------------------------------------------------------------------------- +// +CMccFileSourceImpl::CMccFileSourceImpl() + { + iObserver = 0; + iVideoLength = 0; + iFrameRate = 0; + iVideoType = 0; + iVideoWidth = 0; + iVideoHeight = 0; + iVideoTimeScale = 0; + iAudioLength = 0; + iAudioType = 0; + iFramesPerSample = 0; + iAudioTimeScale = 0; + iAverageBitRate = 0; + iStreamSize = 0; + iStreamAverageBitRate = 0; + iAudioPosition = 0; + iVideoPosition = 0; + iPosition = 0; + iCurrentVideoType = CCMRMediaBuffer::EVideoH263; + iCurrentAudioType = CCMRMediaBuffer::EAudioAMRNB; + iBufferSize = 0; + iAudioSize = 0; + iReturnedFrames = 0; + iNextFrameType = 0; + iKeyFrame = 0; + iVideoFrameSize = 0; + iLastPosition = 0; + iFrameSize.iWidth = 0; + iFrameSize.iHeight = 0; + iCurrentState = EConstructed; + iMP4Handle = NULL; + iIsAudioLeft = EFalse; + iIsVideoLeft = EFalse; + iIsAudio = EFalse; + iIsVideo = EFalse; + iRecursiveCalls = 0; + iIsFirstVideoFrame = EFalse; + + iAudioConsumer = 0; + iAudioConsumerBuffer = 0; + iVideoConsumer = 0; + iVideoConsumerBuffer = 0; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::~CMccFileSourceImpl. +// ----------------------------------------------------------------------------- +// +CMccFileSourceImpl::~CMccFileSourceImpl() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::~CMccFileSourceImpl" ) + /* + delete iPeriodicVideo; + delete iPeriodicVideo; + */ + if ( iMP4Handle ) + { + MP4Err error = MP4ParseClose( iMP4Handle ); + } + + iObserver = NULL; + iVideoConsumer = NULL; + iAudioConsumer = NULL; + + iAudioFrames.Reset(); + iAudioFrames.Close(); + } + + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::AddDataSink(MCMRMediaSink* aSink) +// +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::AddDataSink( MCMRMediaSink* /*aSink*/ ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::AddDataSink" ) + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::OpenFileL(TFileName aFileName) +// +// Opens a 3gp file for streaming and reads media descriptions into +// member variables +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::OpenFileL( TFileName aFileName ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::OpenFileL" ) + + __ASSERT_ALWAYS( iCurrentState == EConstructed, User::Leave( KErrNotReady ) ); + + TFileName fullFileName; + MP4Err error = MP4_OK; + + RFs fS; + User::LeaveIfError( fS.Connect() ); + CleanupClosePushL( fS ); + TParse fp; + if ( fS.Parse( aFileName, fp ) != KErrNone ) + { + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL file name parse error!")); + User::Leave( KErrGeneral ); + } + + fullFileName = fp.FullName(); + + CleanupStack::PopAndDestroy( &fS ); + + error = MP4ParseOpen( &iMP4Handle, (wchar_t *) fullFileName.PtrZ() ); + + if ( error != MP4_OK ) + { + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL parse open error!")); + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL parse open error=%d"), error); + + FileOpenErrorL( error ); + } + + ParseUpdateVideoDescriptions(); + + ParseUpdateAudioDescriptions(); + + if ( ( !iIsAudio ) && ( !iIsVideo ) ) + { + User::Leave( KErrNotSupported ); + } + + error = MP4ParseRequestStreamDescription( iMP4Handle, + ( mp4_u32* ) &iStreamSize, ( mp4_u32* ) &iStreamAverageBitRate ); + + __FILESOURCE_CONTROLL_INT1("CMccFileSourceImpl::OpenFileL, \ +MP4ParseRequestStreamDescription error=",error) + + + #ifdef TIMESTAMP + iReplayTimeStamp = 0; + iTimeDifference = 0; + iPausedTime = 0; + #endif + + iCurrentState = EReady; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::CloseFileL() +// +// Closes the 3gp file +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::CloseFileL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::CloseFileL" ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + if ( iCurrentState == EPlaying ) + { + TRAP_IGNORE( SourceStopL() ); + } + + MP4Err error; + error = MP4ParseClose( iMP4Handle ); + + if ( error != MP4_OK ) + { + User::Leave( KErrGeneral ); + } + + iCurrentState = EConstructed; + iMP4Handle = NULL; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::SetPositionL(TTimeIntervalMicroSeconds aPosition) +// +// Sets a new streaming position +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::SetPositionL( TTimeIntervalMicroSeconds aPosition ) + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::SetPositionL", Int64() ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + if ( iCurrentState == EStopped ) + { + return; + } + + MP4Err error; + + TInt64 tempPosition = aPosition.Int64(); + TUint tempPosition2 = tempPosition; + tempPosition2 = tempPosition2 / 1000; + iLastPosition = iVideoLength; + + TRAP_IGNORE( UpdatePositionL()); + + if ( iLastPosition < iAudioLength ) + { + iLastPosition = iAudioLength; + } + + if ( tempPosition2 > iLastPosition ) + { + User::Leave( KErrArgument ); + } + + error = MP4ParseSeek( iMP4Handle, ( mp4_u32 ) tempPosition2, + ( mp4_u32* ) &iAudioPosition, ( mp4_u32* ) &iVideoPosition, MP4TRUE ); + + if ( error != MP4_OK ) + { + User::Leave( KErrGeneral ); + } + + #ifdef TIMESTAMP + if ( iIsAudioLeft == EFalse && iIsVideoLeft == EFalse) + { + iPosition = 0; + } + iTimeDifference = iTimeDifference + iPosition - iVideoPosition; + iPosition = iVideoPosition; + #endif + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::VideoTypeL() +// +// Returns current video type +// ----------------------------------------------------------------------------- +// +CCMRMediaBuffer::TBufferType CMccFileSourceImpl::VideoTypeL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::VideoTypeL" ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return iCurrentVideoType; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::AudioTypeL() +// +// Returns current audio type +// ----------------------------------------------------------------------------- +// +CCMRMediaBuffer::TBufferType CMccFileSourceImpl::AudioTypeL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::AudioTypeL" ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return iCurrentAudioType; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::VideoFrameRateL() +// +// Returns current video frame rate +// ----------------------------------------------------------------------------- +// +TReal32 CMccFileSourceImpl::VideoFrameRateL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::VideoFrameRateL" ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return TReal32 ( iFrameRate ); + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::AudioBitRateL() +// +// Returns current audio bit rate +// ----------------------------------------------------------------------------- +// +TUint CMccFileSourceImpl::AudioBitRateL() + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::AudioBitRateL", iAverageBitRate ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return iAverageBitRate; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::DurationL() +// +// Returns duration of current media clip +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CMccFileSourceImpl::DurationL() + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::DurationL", + iVideoLength * 1000 ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return TTimeIntervalMicroSeconds( iVideoLength * 1000 ); + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::VideoFrameSizeL() +// +// Returns current video frame size +// ----------------------------------------------------------------------------- +// +TSize CMccFileSourceImpl::VideoFrameSizeL() + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::VideoFrameSizeL iWidth", + iFrameSize.iWidth ) + __FILESOURCE_CONTROLL_INT1("CMccFileSourceImpl::VideoFrameSizeL iHeight", + iFrameSize.iHeight ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return iFrameSize; + } +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::VideoBitRateL() +// +// Returns current video bitrate +// ----------------------------------------------------------------------------- +// +TUint CMccFileSourceImpl::VideoBitRateL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::VideoBitRateL, videoBitRate" ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + TUint videoBitRate = iStreamAverageBitRate - iAverageBitRate; + + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::VideoBitRateL, videoBitRate", + videoBitRate ) + return videoBitRate; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::PositionL() +// +// Returns current streaming position +// ----------------------------------------------------------------------------- +// +TTimeIntervalMicroSeconds CMccFileSourceImpl::PositionL() + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::PositionL", + iPosition * 1000 ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + return TTimeIntervalMicroSeconds( iPosition * 1000 ); + + } +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::UpdatePositionL() +// +// Updates the position parameter +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::UpdatePositionL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::UpdatePosition" ) + MP4Err error; + + error=MP4ParseGetNextVideoTimestamp( iMP4Handle, + ( mp4_u32* ) &iPosition, NULL ); + + if ( error != MP4_OK ) + { + User::Leave( KErrGeneral ); + } + + error = MP4ParseSeek( iMP4Handle, ( mp4_u32 ) iPosition, + ( mp4_u32* ) &iAudioPosition, ( mp4_u32* ) &iVideoPosition, MP4FALSE ); + + if ( error != MP4_OK ) + { + User::Leave( KErrGeneral ); + } + + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::ReadAudioFrameL() +// +// Reads the next audio frame from 3gp file +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::ReadAudioFrameL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL" ) + + + TBool brokenFrame = EFalse; + + if ( iAudioConsumer == NULL) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +source not available" ) + return; + } + else + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +writing buffer" ) + } + + if (!iAudioFrames.Count()) + { + MP4Err error; + + error = MP4ParseIsFrameAvailable( iMP4Handle, MP4_TYPE_AMR_NB ); + + if ( error != MP4_OK ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +no audio" ) + iIsAudioLeft = EFalse; + } + else + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ + audio OK" ) + iIsAudioLeft = ETrue; + } + + if ( iIsAudioLeft == EFalse && iIsVideoLeft == EFalse ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +no video & audio available" ) + + #ifdef TIMESTAMP + iReplayTimeStamp = iReplayTimeStamp + iPosition + 10; + #endif + + SetPositionL( TTimeIntervalMicroSeconds ( 0 ) ); + SourcePauseL(); + + if ( iObserver ) + { + iObserver->EndOfFile( KErrNone ); + } + return; + } + + // Timing correction code + TTimeIntervalMicroSeconds elapsedTime; + TTime currentTime; + currentTime.HomeTime(); + elapsedTime = currentTime.MicroSecondsFrom( iStartTime ); + TInt64 tempTime = elapsedTime.Int64(); + TInt timeNow = tempTime / 1000; + + if ( ( timeNow + 500 ) < ( ( TInt ) iAudioPosition + iTimeDifference + iReplayTimeStamp + ( iPausedTime / 1000 ) ) ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +Position check, returning" ) + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, IGNORING" ) + //return + } + + MP4ParseNextFrameSize( iMP4Handle, MP4_TYPE_AMR_NB, + ( mp4_u32* ) &iBufferSize ); + + HBufC8* iMediaBuffer = HBufC8::NewL( iBufferSize ); + TPtr8 iMediaSinkBuffer = iMediaBuffer->Des(); + + iMediaSinkBuffer.SetLength( iBufferSize ); + + if ( MP4ParseReadAudioFrames( iMP4Handle, + ( mp4_u8* ) iMediaSinkBuffer.Ptr(), + ( mp4_u32 ) iBufferSize, ( mp4_u32* ) &iAudioSize, + ( mp4_u32* ) &iPosition, ( mp4_u32* ) &iReturnedFrames, + NULL ) == MP4_OK ) + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadAudioFrameL, \ +read, time position", iPosition ) + + iAudioPosition = iPosition ; + brokenFrame = EFalse; + + TBool areFramesNormal = EFalse; + + // If brokenFrame = ETrue don't send the frame forward! + + // Calculate real frame size from sample size + TInt FrameSize = iBufferSize / iReturnedFrames; + TUint Counter = 0; + TInt AddToTimeStamp = 0; + TInt startPosition = 0; + + while (Counter < iReturnedFrames) + { + Counter++; + + if ( areFramesNormal == EFalse ) + { + FrameSize = GetFrameLength( iMediaBuffer->Mid( startPosition ) ); + if ( FrameSize == 0 ) + { + brokenFrame = ETrue; + } + else + { + brokenFrame = EFalse; + } + } + + + TTimeIntervalMicroSeconds timeStamp(0); + + // Sets a different timestamp than in file (forward/rewind functionality) + #ifdef TIMESTAMP + timeStamp = TTimeIntervalMicroSeconds( ( (iPosition + iTimeDifference + iReplayTimeStamp ) * 1000 ) + + AddToTimeStamp + #ifdef TIMESTAMPPAUSE + + iPausedTime + #endif //TIMESTAMPPAUSE + ); + #else //TIMESTAMP + timeStamp =TTimeIntervalMicroSeconds( ( iPosition * 1000 ) + AddToTimeStamp ) ; + #endif //TIMESTAMP + + TAudioFrameItem item; + item.iFrame = HBufC8::NewL( FrameSize ); + item.iFrame->Des().Copy( iMediaBuffer->Mid( startPosition , FrameSize ) ); + item.iTimeStamp = timeStamp; + User::LeaveIfError( iAudioFrames.Append(item) ); + + AddToTimeStamp += 20000; + startPosition += FrameSize; + } + delete iMediaBuffer; + iMediaBuffer = NULL; + + if ( ( timeNow - 500 ) < ( ( TInt ) iAudioPosition + iTimeDifference + iReplayTimeStamp + ( iPausedTime / 1000 ) ) ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +Position check, returning" ) + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +IGNORING" ) + //return; + } + + } + else + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +reading frames failed" ) + } + } + else + { + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadAudioFrameL, \ +existing frames, count", iAudioFrames.Count() ) + } + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +writing buffer, copying" ) + CMMFDataBuffer* buf = static_cast(iAudioConsumerBuffer); + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadAudioFrameL, \ +writing buffer, len", buf->BufferSize() ) + HBufC8* audioFrame = iAudioFrames[0].iFrame; + buf->Data().Copy( *audioFrame ); + iAudioConsumerBuffer->SetTimeToPlay(iAudioFrames[0].iTimeStamp); + iAudioConsumerBuffer->SetLastBuffer(EFalse); + iAudioFrames.Remove(0); + delete audioFrame; + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +writing buffer, complete" ) + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +writing buffer to sink" ) + iAudioConsumer->BufferFilledL( iAudioConsumerBuffer ); + iAudioConsumer = 0; + iAudioConsumerBuffer = 0; + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadAudioFrameL, \ +writing buffer to sink complete" ) + } +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::ReadVideoFrameL() +// +// Reads the next video frame from 3gp file +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::ReadVideoFrameL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL" ) + + MP4Err error; + + if ( iVideoConsumer == NULL) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, \ +source not available" ) + return; + } + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, \ +writing buffer" ) + + + error = MP4ParseIsFrameAvailable( iMP4Handle, iVideoType ); + error = MP4ParseIsFrameAvailable( iMP4Handle, MP4_TYPE_AVC_PROFILE_BASELINE ); + error = MP4ParseIsFrameAvailable( iMP4Handle, iVideoType ); + error = MP4ParseIsFrameAvailable( iMP4Handle, MP4_TYPE_AVC_PROFILE_MAIN ); + error = MP4ParseIsFrameAvailable( iMP4Handle, MP4_TYPE_AVC_PROFILE_EXTENDED ); + error = MP4ParseIsFrameAvailable( iMP4Handle, iVideoType ); + + + if ( error != MP4_OK ) + { + iIsVideoLeft = EFalse; + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, \ +no video" ) + } + else + { + iIsVideoLeft = ETrue; + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, \ +video available" ) + } + + // If no more frames available inform observer and stop playing + if ( iIsAudioLeft == EFalse && iIsVideoLeft == EFalse ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, \ +no video & audio available" ) + + #ifdef TIMESTAMP + iReplayTimeStamp = iReplayTimeStamp + iPosition + 10; + #endif + + SetPositionL( TTimeIntervalMicroSeconds ( 0 ) ); + SourcePauseL(); + + if ( iObserver ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, \ + sending EOF" ) + iObserver->EndOfFile( KErrNone ); + } + return; + } + + // Timing correction code + TTimeIntervalMicroSeconds elapsedTime; + TTime currentTime; + currentTime.HomeTime(); + elapsedTime = currentTime.MicroSecondsFrom( iStartTime ); + TInt64 tempTime = elapsedTime.Int64(); + TInt timeNow = tempTime /*.GetTInt()*/ / 1000; + + if ( ( timeNow + 500 ) < ( ( TInt ) iVideoPosition + iTimeDifference + iReplayTimeStamp + ( iPausedTime / 1000 ) ) ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, Position check, returning" ) + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadVideoFrameL", (timeNow + 500)) + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadVideoFrameL", + (( TInt ) iVideoPosition + iTimeDifference + iReplayTimeStamp + ( iPausedTime / 1000 ) ) ) + __FILESOURCE_CONTROLL_INT4( "CMccFileSourceImpl::ReadVideoFrameL, videoPosition", iVideoPosition, + "TimeDifference", iTimeDifference, + "ReplyTimeStamp", iReplayTimeStamp, + "PausedTime", iPausedTime ) + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, IGNORING" ) + //return; + } + + // Read the size of next video frame + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, reading frame" ) + MP4ParseNextFrameSize( iMP4Handle, iVideoType, + ( mp4_u32* ) &iBufferSize ); + + HBufC8* tempBuff = NULL; + if ( IsAVCVideo() && iIsFirstVideoFrame ) + { + ExtractH264ParameterSetNALUsL( &tempBuff ); + if ( NULL != tempBuff ) + { + CleanupStack::PushL( tempBuff ); + } + iIsFirstVideoFrame = EFalse; + } + // Allocate a buffer big enough for the next video frame + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadVideoFrameL, reading frame, size", iBufferSize ) + HBufC8* iMediaBuffer = HBufC8::NewL( iBufferSize ); + // Pointer descriptor to the buffer + const TUint8* iPtrMediaSinkBuffer = iMediaBuffer->Des().Ptr(); + + if ( MP4ParseReadVideoFrame( iMP4Handle, + ( mp4_u8* ) iPtrMediaSinkBuffer, ( mp4_u32 ) iBufferSize, + ( mp4_u32* ) &iVideoFrameSize, ( mp4_u32* ) &iPosition, + ( mp4_bool* ) &iKeyFrame, NULL ) == MP4_OK ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, reading frame, OK" ) + TPtr8 iMediaSinkBuffer = iMediaBuffer->Des(); + + iVideoPosition = iPosition ; + + + iMediaSinkBuffer.SetLength( iBufferSize ); // Sets buffer length + if ( IsAVCVideo() ) + { + MarkWithNALUDelimiters( iBufferSize, iMediaSinkBuffer ); + } + + TTimeIntervalMicroSeconds timeStamp( 0 ); + + #ifdef TIMESTAMP + timeStamp = TTimeIntervalMicroSeconds( ( iPosition + iTimeDifference + iReplayTimeStamp ) * 1000 + #ifdef TIMESTAMPPAUSE + + iPausedTime + #endif //TIMESTAMPPAUSE + ); + #else //TIMESTAMP + timeStamp = TTimeIntervalMicroSeconds ( iPosition * 1000 ); + #endif //TIMESTAMP + + //buffer = new ( ELeave ) CCMRMediaBuffer( + //iMediaSinkBuffer, CCMRMediaBuffer::EVideoH263, iBufferSize, + //FALSE, timeStamp ); + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, writing buffer, copying" ) + CMMFDataBuffer* buf = static_cast(iVideoConsumerBuffer); + __FILESOURCE_CONTROLL_INT1( "CMccFileSourceImpl::ReadVideoFrameL, writing buffer, len", buf->BufferSize() ) + if( NULL != tempBuff ) + { + buf->Data().Copy( *tempBuff ); + CleanupStack::PopAndDestroy( tempBuff ); + tempBuff = NULL; + } + else + { + buf->Data().Delete( 0, buf->BufferSize() ); + } + buf->Data().Append( *iMediaBuffer ); + + iVideoConsumerBuffer->SetTimeToPlay(timeStamp); + iVideoConsumerBuffer->SetLastBuffer(EFalse); + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, writing buffer, complete" ) + + TInt err = KErrNone; + if ( err == KErrNone ) + { + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, writing buffer to sink" ) + iVideoConsumer->BufferFilledL( iVideoConsumerBuffer ); + iVideoConsumer = 0; + iVideoConsumerBuffer = 0; + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, writing buffer to sink complete" ) + + if ( err != KErrNone ) + { + delete iMediaBuffer; + iMediaBuffer = NULL; + User::Leave( KErrGeneral ); + } + } + } + else + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, reading frame, NOT OK" ) + } + + delete iMediaBuffer; + iMediaBuffer = NULL; + + if ( ( timeNow - 500 ) < ( ( TInt ) iVideoPosition + iTimeDifference + iReplayTimeStamp + ( iPausedTime / 1000 ) ) ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, Time Check 2, IGNORING" ) //return; + } + + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ReadVideoFrameL, writing buffer to sink complete" ) + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::PlayL() +// +// Starts streaming from 3gp file +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::SourcePlayL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::SourcePlayL" ) + + __ASSERT_ALWAYS( iCurrentState != EConstructed, User::Leave( KErrNotReady ) ); + + if ( iCurrentState == EPlaying ) + { + return; + } + + #ifdef TIMESTAMP + if ( iCurrentState == EPaused ) + { + iPauseStopped.HomeTime(); +//#ifdef TIMESTAMPPAUSE + TTimeIntervalMicroSeconds differenceTemp1 = + iPauseStopped.MicroSecondsFrom(iPauseStarted); + TInt64 differenceTemp2 = differenceTemp1.Int64(); + iPausedTime = iPausedTime + differenceTemp2 /*.GetTInt()*/; +//#endif //TIMESTAMPPAUSE + } + else + { + iStartTime.HomeTime(); // Set start time to current time + } + #endif + /* + + // Variables for periodic timers + // temporary flagged hack for WINS to get timing right + TInt iTickIntervalVideo = 1000000; + TInt iTickIntervalAudio = 10000; + + if ( iFrameRate != 0 ) + { + // Set interval for video + iTickIntervalVideo = ( 1000000 / ( TInt ) iFrameRate ) ; + } + + + TInt ticks = 10000; + + // ROP plays faster so this code was added to help syncronisation +// iTickIntervalAudio = TInt (iTickIntervalAudio * ( ( 100.0 - KPlaybackSync ) / 100.0 )) ; + iTickIntervalVideo = TInt (iTickIntervalVideo * ( ( 100.0 - KPlaybackSync ) / 100.0 )) ; + + // Creation and starting of periodic timers + + if ( iIsAudio ) + { + if ( !iPeriodicAudio ) + { + iPeriodicAudio = CMccPeriodicRunner::NewL( *this ); + } + + iPeriodicAudio->Start( iTickIntervalAudio, + TCallBack( TickAudioL, this ) ); + } + if ( iIsVideo ) + { + if ( !iPeriodicVideo ) + { + iPeriodicVideo = CMccPeriodicRunner::NewL( *this ); + + } + iPeriodicVideo->Start( iTickIntervalVideo, + TCallBack( TickVideoL, this ) ); + } + + */ + iCurrentState = EPlaying; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::TickAudioL +// +// ----------------------------------------------------------------------------- +// +TInt CMccFileSourceImpl::TickAudioL( TAny* aObject ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::TickAudioL" ) + + if ( ( ( CMccFileSourceImpl* ) aObject )->iFramesPerSample <= 2 ) + { + //Reads five frames in one tick + for ( int x = 0 ; x < 5; x++ ) + { + ( ( CMccFileSourceImpl* ) aObject )->ReadAudioFrameL(); + } + } + + if ( ( ( CMccFileSourceImpl* ) aObject )->iFramesPerSample == 3 || + ( ( CMccFileSourceImpl* ) aObject )->iFramesPerSample == 4 ) + { + + //Reads two frames in one tick + for ( int x = 0 ; x < 2; x++ ) + { + ( ( CMccFileSourceImpl* ) aObject )->ReadAudioFrameL() ; + } + } + + if ( ( ( CMccFileSourceImpl* ) aObject )->iFramesPerSample >= 5 ) + { + ( ( CMccFileSourceImpl* ) aObject )->ReadAudioFrameL(); + } + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::TickVideoL +// +// ----------------------------------------------------------------------------- +// +TInt CMccFileSourceImpl::TickVideoL( TAny* aObject ) + { + ( ( CMccFileSourceImpl* ) aObject )->ReadVideoFrameL(); + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::PauseL() +// +// Pauses streaming by cancelling timers +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::SourcePauseL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::SourcePauseL" ) + + if ( iCurrentState != EPlaying ) + { + return; + } + /* + __ASSERT_ALWAYS( iPeriodicAudio, User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( iPeriodicAudio, User::Leave( KErrArgument ) ); + + iPeriodicAudio->Cancel(); + iPeriodicVideo->Cancel(); + */ + iCurrentState = EPaused; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::StopL() +// +// Stops streaming +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::SourceStopL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::SourceStopL" ) + + if ( iCurrentState == EConstructed ) + { + return; + } +/* + if ( iCurrentState == EPlaying ) + { + __ASSERT_ALWAYS( iPeriodicAudio, User::Leave( KErrArgument ) ); + __ASSERT_ALWAYS( iPeriodicAudio, User::Leave( KErrArgument ) ); + + iPeriodicAudio->Cancel(); + iPeriodicVideo->Cancel(); + } +*/ + SetPositionL( TTimeIntervalMicroSeconds ( 0 ) ); + + iCurrentState = EStopped; + + #ifdef TIMESTAMP + + if ( iIsAudioLeft == TRUE && iIsVideoLeft == TRUE ) + { + iTimeDifference = 0; + iPausedTime=0; + } + + iPauseStarted = 0; + iPauseStopped = 0; + + #endif + + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::GetFrameLenght() +// +// Gets audio frame lenght from given buffer +// ----------------------------------------------------------------------------- +// +TUint CMccFileSourceImpl::GetFrameLength( TPtrC8 aData ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::GetFrameLength" ) + + 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 + { + return 13; + } + case 1: //amr 5.15 + { + return 14; + } + case 2: //amr 5.9 + { + return 16; + } + case 3: //amr 6.7 + { + return 18; + } + case 4: //amr 7.4 + { + return 20; + } + case 5: //amr 7.95 + { + return 21; + } + case 6: //amr 10.2 + { + return 27; + } + case 7: //amr 12.2 + { + return 32; + } + case 8: //amr SID + { + return 6; + } + + case 15: //no data + { + return 1; + } + default: //not arm narrowband + { + return 0; + } + } +} + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::SourceDataTypeCode() +// ----------------------------------------------------------------------------- +// +TFourCC CMccFileSourceImpl::SourceDataTypeCode( TMediaId aMediaId ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::SourceDataTypeCode" ) + + if ( KUidMediaTypeVideo == aMediaId.iMediaType ) + { + return iVideoFourCC; + } + else if ( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + return iAudioFourCC; + } + else + { + return TFourCC( NULL ); + } + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::SetSourceDataTypeCode() +// ----------------------------------------------------------------------------- +// +TInt CMccFileSourceImpl::SetSourceDataTypeCode( + TFourCC aCodec, + TMediaId aMediaId ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::SetSourceDataTypeCode" ) + + if ( ( KUidMediaTypeVideo == aMediaId.iMediaType && + aCodec == iVideoFourCC ) || + ( KUidMediaTypeAudio == aMediaId.iMediaType && + aCodec == iAudioFourCC ) ) + { + return KErrNone; + } + else + { + return KErrNotSupported; + } + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::SourcePrimeL() +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::SourcePrimeL() + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::SourcePrimeL" ) + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::FillBufferL() +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::FillBufferL( CMMFBuffer* aBuffer, + MDataSink* aConsumer, + TMediaId aMediaId ) + { + __FILESOURCE_MEDIA( "CMccFileSourceImpl::FillBufferL" ) + + if (aMediaId.iMediaType == KUidMediaTypeAudio) + { + __FILESOURCE_MEDIA( "CMccFileSourceImpl::FillBufferL, audio" ) + iAudioConsumer = aConsumer; + iAudioConsumerBuffer = aBuffer; + } + else if (aMediaId.iMediaType == KUidMediaTypeVideo ) + { + __FILESOURCE_MEDIA( "CMccFileSourceImpl::FillBufferL, video" ) + iVideoConsumer = aConsumer; + iVideoConsumerBuffer = aBuffer; + } + else + { + __FILESOURCE_MEDIA( "CMccFileSourceImpl::FillBufferL, unknown media " ) + User::Leave( KErrNotSupported ); + } + + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::MarkWithNALUDelimiters() +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::MarkWithNALUDelimiters( + const TInt aAccessUnitSize, TDes8& aBuffer ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::MarkWithNALUDelimiters" ) + + TUint8* ptrByte = NULL; + TInt indx = 0; + TUint32 size; + const TUint32 size_field_len = 4; + + do + { + ptrByte = const_cast ( aBuffer.Mid( indx ).Ptr() ); // get starting point of NALU size + size = BigEndian::Get32(ptrByte); // get NALU size + aBuffer[indx+0] = 0x00; + aBuffer[indx+1] = 0x00; + aBuffer[indx+2] = 0x00; + aBuffer[indx+3] = 0x01; + indx = indx + size + size_field_len; + + }while(indx < aAccessUnitSize); + + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::ExtractH264ParameterSetNALUsL() +// ----------------------------------------------------------------------------- +// + +void CMccFileSourceImpl::ExtractH264ParameterSetNALUsL( HBufC8** aBufferOut ) + { + __FILESOURCE_CONTROLL( "CMccFileSourceImpl::ExtractH264ParameterSetNALUsL" ) + + *aBufferOut = NULL; + + MP4Err error = MP4_OK; + HBufC8* buffer = NULL; + HBufC8* bufferOut = NULL; + TUint32 decspecinfosize; + TUint8* ptrByte; + + // Query for size + error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, + ( mp4_u8* ) NULL, + 0, + ( mp4_u32* ) &decspecinfosize + ); + if( ( MP4_OK != error ) && ( MP4_BUFFER_TOO_SMALL != error ) ) + { + User::Leave(KErrGeneral); + } + + buffer = HBufC8::NewLC(decspecinfosize); + ptrByte = const_cast ( buffer->Des().Ptr() ); + + error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, + ( mp4_u8* ) ptrByte, + ( mp4_u32 ) buffer->Des().MaxSize(), + ( mp4_u32* ) &decspecinfosize + ); + if(MP4_OK != error) + { + User::Leave(KErrGeneral); + } + else + { + buffer->Des().SetLength( decspecinfosize ); + } + + bufferOut = HBufC8::NewLC( buffer->Size() * 2 ); + TPtr8 ptrBufferOut = bufferOut->Des(); + TPtr8 ptrBuffer = buffer->Des(); + + // find NALUs in decoder info and put in buffer by marking with delimiters + + TUint8 tmpByte; + TUint16 size16; + TInt indx = 5; // skip other info in the beginning + TInt numNALUs = 0; + TInt lp_indx; + + // get number of seq. parameter set NALUs + tmpByte = ptrBuffer[indx++]; + numNALUs = tmpByte & 0x1F; // get rid of reserved '111' bits + + // extract seq. parameter set NALUs + + for ( lp_indx = 0; lp_indx < numNALUs; lp_indx++ ) + { + size16 = BigEndian::Get16( ptrBuffer.Mid( indx ).Ptr() ); + indx += 2; + + // insert delimiter + tmpByte = 0x00; + ptrBufferOut.Append( &tmpByte, 1 ); + ptrBufferOut.Append( &tmpByte, 1 ); + ptrBufferOut.Append( &tmpByte, 1 ); + tmpByte = 0x01; + ptrBufferOut.Append( &tmpByte, 1 ); + + ptrBufferOut.Append( ptrBuffer.Mid( indx, size16 ) ); + + indx += size16; + } + + // get number of pic. parameter set NALUs + tmpByte = ptrBuffer[indx++]; + numNALUs = tmpByte; + + // extract pic. parameter set NALUs + + for ( lp_indx = 0; lp_indx < numNALUs; lp_indx++ ) + { + size16 = BigEndian::Get16( ptrBuffer.Mid( indx ).Ptr() ); + indx += 2; + + // insert delimiter + tmpByte = 0x00; + ptrBufferOut.Append( &tmpByte, 1 ); + ptrBufferOut.Append( &tmpByte, 1 ); + ptrBufferOut.Append( &tmpByte, 1 ); + tmpByte = 0x01; + ptrBufferOut.Append( &tmpByte, 1 ); + + ptrBufferOut.Append( ptrBuffer.Mid( indx, size16 ) ); + + indx += size16; + } + + CleanupStack::Pop( bufferOut ); + CleanupStack::PopAndDestroy( buffer ); + + *aBufferOut = bufferOut; + + } + + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::IsAVCVideo() +// ----------------------------------------------------------------------------- +// + +TBool CMccFileSourceImpl::IsAVCVideo() + { + if ( ( iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE ) || + ( iVideoType == MP4_TYPE_AVC_PROFILE_MAIN ) || + ( iVideoType == MP4_TYPE_AVC_PROFILE_EXTENDED ) + ) + { + return ETrue; + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::FileOpenErrorL +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::FileOpenErrorL( MP4Err error ) + { + iMP4Handle = NULL; + if ( error == MP4_OUT_OF_MEMORY ) + { + User::Leave( KErrNoMemory ); + } + else + { + User::Leave( KErrGeneral ); + } + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::ParseUpdateVideoDescriptions +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::ParseUpdateVideoDescriptions( ) + { + if ( MP4ParseRequestVideoDescription( iMP4Handle, + ( mp4_u32* ) &iVideoLength, &iFrameRate, ( mp4_u32* ) &iVideoType, + ( mp4_u32* ) &iVideoWidth, ( mp4_u32* ) &iVideoHeight, + ( mp4_u32* ) &iVideoTimeScale ) + == MP4_OK ) + { + iFrameSize.iWidth = iVideoWidth; + iFrameSize.iHeight = iVideoHeight; + + if ( iVideoType == MP4_TYPE_H263_PROFILE_0 ) + { + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL MP4_TYPE_H263_PROFILE_0")); + + iCurrentVideoType = CCMRMediaBuffer::EVideoH263; + iIsVideo = ETrue; + iIsVideoLeft = ETrue; + // iVideoFourCC = TFourCC( KMccFourCCIdAVC ); + iVideoFourCC = TFourCC( KMccFourCCIdH263 ); + } + if ( iVideoType == MP4_TYPE_MPEG4_VIDEO ) + { + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL MP4_TYPE_MPEG4_VIDEO!")); + + iCurrentVideoType = CCMRMediaBuffer::EVideoH263; + iIsVideo = ETrue; + iIsVideoLeft = ETrue; + iVideoFourCC = TFourCC( KMccFourCCIdAVC ); + } + if ( IsAVCVideo() ) + { + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL AVC!")); + + iCurrentVideoType = CCMRMediaBuffer::EVideoH263; + iIsVideo = ETrue; + iIsVideoLeft = ETrue; + iVideoFourCC = TFourCC( KMccFourCCIdAVC ); + iIsFirstVideoFrame = ETrue; + } + } + } + +// ----------------------------------------------------------------------------- +// CMccFileSourceImpl::ParseUpdateVideoDescriptions +// ----------------------------------------------------------------------------- +// +void CMccFileSourceImpl::ParseUpdateAudioDescriptions( ) + { + if ( MP4ParseRequestAudioDescription( iMP4Handle, + ( mp4_u32* ) &iAudioLength, ( mp4_u32* ) &iAudioType, + ( mp4_u8* ) &iFramesPerSample, ( mp4_u32* ) &iAudioTimeScale, + ( mp4_u32* ) &iAverageBitRate ) + == MP4_OK ) + { + if ( iAudioType == MP4_TYPE_AMR_NB ) + { + RDebug::Print(_L("CMccFileSourceImpl::OpenFileL MP4_TYPE_AMR_NB!")); + + iCurrentAudioType = CCMRMediaBuffer::EAudioAMRNB; + iIsAudio = ETrue; + iIsAudioLeft = ETrue; + iAudioFourCC = TFourCC( KMccFourCCIdAMRNB ); + } + } + } + +#ifndef EKA2 +// DLL interface code +EXPORT_C TInt E32Dll( TDllReason ) + { + return KErrNone; + } +#endif