diff -r 951a5db380a0 -r e0b5df5c0969 videoeditorengine/vedengine/videoprocessor/src/mp4parser.cpp --- a/videoeditorengine/vedengine/videoprocessor/src/mp4parser.cpp Fri Jan 29 14:08:33 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1264 +0,0 @@ -/* -* 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 FILES - -#include "movieprocessorimpl.h" -#include "mp4parser.h" -#include "vedvideosettings.h" -#include "vedaudiosettings.h" -#include "vedvolreader.h" -#include "vedavcedit.h" - -// ASSERTIONS -#define MPASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CMovieProcessorImpl"), EInternalAssertionFailure)) - -#ifdef _DEBUG -#include -#define PRINT(x) RDebug::Print x; -#else -#define PRINT(x) -#endif - -// LOCAL CONSTANTS AND MACROS -#ifdef _DEBUG -const TInt KErrorCode = CParser::EParserFailure; -#else -const TInt KErrorCode = KErrGeneral; -#endif - -//const TUint KNumFramesInOneRun = 10; -const TUint KVOLHeaderBufferSize = 256; -const TUint KAVCDCRBufferSize = 1024; -const TUint KMinBitrate = 128; - -// ================= MEMBER FUNCTIONS ======================= - -// C++ default constructor can NOT contain any code, that -// might leave. -// - -CMP4Parser::CMP4Parser() -{ - iMP4Handle = 0; - iVideoType = 0; - iAudioType = 0; - iBytesRead = 0; - iFirstRead = ETrue; // added for Mp4 - iFirstFrameInfo = ETrue; // added for Mp4 - iOutputNumberOfFrames = 0; - iStreamSource = ESourceNone; - iFrameNumber=0; - iFirstTimeClipParsing=ETrue; - iStartFrameIndex=0; -} - -// Two-phased constructor. - -CMP4Parser* CMP4Parser::NewL(CMovieProcessorImpl* aProcessor, const TDesC &aFileName) -{ - CMP4Parser *self = new (ELeave) CMP4Parser; - CleanupStack::PushL(self); - - if ( aFileName.Length() > 0 ) - self->iStreamSource = ESourceFile; - else - self->iStreamSource = ESourceUser; - - self->ConstructL(aProcessor,aFileName); - - CleanupStack::Pop(); // self - - return self; -} - -CMP4Parser* CMP4Parser::NewL(CMovieProcessorImpl* aProcessor, RFile* aFileHandle) -{ - CMP4Parser *self = new (ELeave) CMP4Parser; - CleanupStack::PushL(self); - - self->iStreamSource = ESourceFile; - - self->ConstructL(aProcessor,aFileHandle); - - CleanupStack::Pop(); // self - - return self; -} - -// Symbian OS default constructor can leave. - -void CMP4Parser::ConstructL(CMovieProcessorImpl* aProcessor, const TDesC &aFileName) -{ - MP4Err error; - iProcessor = aProcessor; - - // open MP4 library - if ( iStreamSource == ESourceFile ) - { - TBuf<258> temp(aFileName); - temp.ZeroTerminate(); - - MP4FileName name = reinterpret_cast( const_cast(temp.Ptr()) ); - - error = MP4ParseOpen(&iMP4Handle, name); - if ( error == MP4_OK ) - { - // set buffer sizes; only parser buffer size is effective for this instance - error = MP4SetCustomFileBufferSizes(iMP4Handle, K3gpMp4ComposerWriteBufferSize, K3gpMp4ComposerNrOfWriteBuffers, K3gpMp4ParserReadBufferSize ); - } - } - else - { - // buffer - error = MP4ParseOpen(&iMP4Handle, 0); - } - - if (error == MP4_OUT_OF_MEMORY) - { - User::Leave(KErrNoMemory); - } - else if ( error != MP4_OK ) - { - User::Leave(KErrorCode); - } -} - -void CMP4Parser::ConstructL(CMovieProcessorImpl* aProcessor, RFile* aFileHandle) -{ - MP4Err error; - iProcessor = aProcessor; - - // open MP4 library - error = MP4ParseOpenFileHandle(&iMP4Handle, aFileHandle); - - if ( error == MP4_OK ) - { - // set buffer sizes; only parser buffer size is effective for this instance - error = MP4SetCustomFileBufferSizes(iMP4Handle, K3gpMp4ComposerWriteBufferSize, K3gpMp4ComposerNrOfWriteBuffers, K3gpMp4ParserReadBufferSize ); - } - - if (error == MP4_OUT_OF_MEMORY) - { - User::Leave(KErrNoMemory); - } - else if ( error != MP4_OK ) - { - User::Leave(KErrorCode); - } -} - -// Destructor -CMP4Parser::~CMP4Parser() -{ - if (iMP4Handle) - MP4ParseClose(iMP4Handle); - - iMP4Handle = 0; -} - - - -// --------------------------------------------------------- -// CMP4Parser::WriteDataBlockL -// Write a block of data to parser -// (other items were commented in a header). -// --------------------------------------------------------- -// - -TInt CMP4Parser::WriteDataBlock(const TDes8& aBlock) -{ - - MPASSERT(iStreamSource != ESourceFile); - MP4Err error = MP4ParseWriteData(iMP4Handle, (mp4_u8*)(aBlock.Ptr()), mp4_u32(aBlock.Length()) ); - - if ( error == MP4_OUT_OF_MEMORY ) - return KErrNoMemory; - else if ( error == MP4_ERROR ) - return KErrorCode; - else - return KErrNone; - -} - -// --------------------------------------------------------- -// CMP4Parser::GetNextFrameInformation -// Get type (streaming-case), length and availability of next frame to be fetched -// using MP4 library API functions -// (other items were commented in a header). -// --------------------------------------------------------- -// - -TInt CMP4Parser::GetNextFrameInformation(TFrameType& aType, TUint& aLength, TBool& aIsAvailable) -{ - - // If aType == EFrameTypeNone, the type of next frame is retrieved - // (valid only in streaming case) - // Otherwise, only the length of next specified type of frame is retrieved - MPASSERT(iStreamSource != ESourceNone); - - mp4_u32 type = MP4_TYPE_NONE; - MP4Err error; - - aIsAvailable = 0; - if ( iNextFrameType == EFrameTypeNone ) - // if the mp4 library is reading a file, a frame has always been read when - // we come here - // otherwise it might be that a complete frame was not available yet - // and we come here to ask again - { - if ( aType == EFrameTypeNone ) - { - MPASSERT(iStreamSource == ESourceUser); - - // get next frame type - error = MP4ParseNextFrameType(iMP4Handle, &type); - - if ( error == MP4_NOT_AVAILABLE ) - return KErrNone; - else if ( error == MP4_NO_FRAME ) - return EParserEndOfStream; // no video or audio frames left, stream ended - else if ( error == MP4_INVALID_INPUT_STREAM ) - return KErrCorrupt; - else if ( error != MP4_OK ) - return KErrorCode; - else - { - MPASSERT(error == MP4_OK); - } - - switch ( type ) - { - case MP4_TYPE_H263_PROFILE_0: - case MP4_TYPE_MPEG4_VIDEO: - - MPASSERT( type == iVideoType ); - iNextFrameType = EFrameTypeVideo; - break; - - case MP4_TYPE_AMR_NB: - MPASSERT( type == iAudioType ); - iNextFrameType = EFrameTypeAudio; - break; - - default: - return KErrNotSupported; - } - } - else - { - // library reads the file - //MPASSERT(iStreamSource == ESourceFile); - type = ( aType == EFrameTypeVideo ) ? iVideoType : iAudioType; - iNextFrameType = aType; - } - - // get length for the frame - mp4_u32 length = 0, mp4Specific = 0; - MPASSERT( type != MP4_TYPE_NONE ); - if ( (iFirstFrameInfo) && - ((iVideoType == MP4_TYPE_MPEG4_VIDEO) || (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)) ) - { - error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific ); - iFirstFrameInfo = EFalse; - } - error = MP4ParseNextFrameSize(iMP4Handle, type, &length); - MPASSERT( error != MP4_NOT_AVAILABLE ); - - if ( length == 0 || error == MP4_NO_REQUESTED_FRAME ) - { - // file-reading case: all frames of this type have been read - // and the caller should try with the other type - MPASSERT( length == 0 ); - iNextFrameType = EFrameTypeNone; - aLength = 0; - return KErrNone; - } - else if ( error == MP4_INVALID_INPUT_STREAM ) - return KErrCorrupt; - else if ( error != MP4_OK ) - return KErrorCode; - else if ( length > iMaxVideoFrameLength ) - { - PRINT((_L("CMP4Parser::GetNextFrameInformation() too large video frame size %d, return KErrCorrupt"),length)); - return KErrCorrupt; - } - else - iNextFrameLength = TUint(length + mp4Specific); - - } - MPASSERT(iNextFrameType != EFrameTypeNone); - MPASSERT(iNextFrameLength != 0); - - // check if frame is available - if ( iStreamSource == ESourceUser ) - { - error = MP4ParseIsFrameAvailable(iMP4Handle, type); - if ( error != MP4_OK && error != MP4_NOT_AVAILABLE ) - return KErrorCode; - aIsAvailable = ( error == MP4_NOT_AVAILABLE ) ? EFalse : ETrue; - } - else - aIsAvailable = ETrue; - - aType = iNextFrameType; - aLength = iNextFrameLength; - - return KErrNone; -} - -// --------------------------------------------------------- -// CMP4Parser::ReadFrames -// Read the next frame(s) from file / stream -// (other items were commented in a header). -// --------------------------------------------------------- -// - -TInt CMP4Parser::ReadFrames(TDes8& aDstBuffer, TFrameType aType, TUint32& aNumRead, - TUint32& aTimeStamp) -{ - MP4Err error; - mp4_u32 returnedSize = 0; - mp4_bool keyFrame = 0; - - MPASSERT( iNextFrameType != EFrameTypeNone && aType == iNextFrameType ); - MPASSERT( iNextFrameLength != 0 ); - -#ifdef _DEBUG - mp4_u32 type = MP4_TYPE_NONE; // buffer support - type = ( aType == EFrameTypeVideo ) ? iVideoType : iAudioType; // buffer support - if (iStreamSource == ESourceUser) - MPASSERT( MP4ParseIsFrameAvailable(iMP4Handle, type) == MP4_OK ); -#endif - - - if (aType == EFrameTypeVideo) - { - TUint32 iTimeStampInTicks=0; - mp4_u32 mp4Specific = 0; - - if ( (iFirstRead) && - ((iVideoType == MP4_TYPE_MPEG4_VIDEO) || (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)) ) - { - error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr() + aDstBuffer.Length()), - mp4_u32( aDstBuffer.MaxLength() ), &mp4Specific ); - iFirstRead = EFalse; - } - - error = MP4ParseReadVideoFrame(iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr() + aDstBuffer.Length()+ mp4Specific), - mp4_u32( aDstBuffer.MaxLength() ), &returnedSize, (mp4_u32*)&aTimeStamp, - &keyFrame, &iTimeStampInTicks); - - returnedSize += mp4Specific; - iFrameNumber++; - aNumRead = 1; - } - else - { - error = MP4ParseReadAudioFrames(iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr()), - mp4_u32(aDstBuffer.MaxLength()), &returnedSize, (mp4_u32*)&aTimeStamp, - (mp4_u32*)&aNumRead, NULL); - - //PRINT((_L("audio TS:%d, "), aTimeStamp)); - } - - MPASSERT(error != MP4_BUFFER_TOO_SMALL); - aDstBuffer.SetLength(aDstBuffer.Length() + TInt(returnedSize)); - iBytesRead += returnedSize; - iNextFrameType = EFrameTypeNone; - iNextFrameLength = 0; - - //PRINT((_L("error=%d, numReturned=%d, returnedSize=%d, bufferSize=%d\n"), - // error, aNumRead, returnedSize, aDstBuffer.MaxLength())); - - if (error == MP4_NOT_AVAILABLE) - return EParserNotEnoughData; - else if ( error == MP4_INVALID_INPUT_STREAM ) - return KErrCorrupt; - else if ( error != MP4_OK ) - return KErrorCode; - else - return KErrNone; -} - - -// --------------------------------------------------------- -// CMP4Parser::Reset -// Resets the parser to its initial state -// (other items were commented in a header). -// --------------------------------------------------------- -// - -TInt CMP4Parser::Reset() -{ - MP4Err error; - - if ( iStreamSource == ESourceFile ) - { - mp4_u32 audioPos, videoPos; - - // seek to very beginning - error = MP4ParseSeek(iMP4Handle, 0, &audioPos, &videoPos, EFalse); - if ( error != MP4_OK ) - return KErrorCode; - - MPASSERT( videoPos == 0 && (iAudioType == 0 || audioPos == 0) ); - - } - else - { - // close & open library to make sure old data is flushed - error = MP4ParseClose(iMP4Handle); - - if ( error != MP4_OK ) - return KErrorCode; - error = MP4ParseOpen(&iMP4Handle, 0); - if ( error != MP4_OK ) - return KErrorCode; - } - - iBytesRead = 0; - iNextFrameType = EFrameTypeNone; - iNextFrameLength = 0; - - return KErrNone; -} - - -// --------------------------------------------------------- -// CMP4Parser::ParseHeaderL -// Get relevant stream parameters by calling mp4 library functions -// (other items were commented in a header). -// --------------------------------------------------------- -// - -TInt CMP4Parser::ParseHeaderL(CParser::TStreamParameters& aStreamParameters) -{ - - PRINT((_L("CMP4Parser::ParseHeaderL() begin"))); - - MP4Err error; - mp4_double frameRate = 0; - TBool hasVideo = ETrue; - - // Reset channel info - aStreamParameters.iHaveVideo = EFalse; - aStreamParameters.iHaveAudio = EFalse; - aStreamParameters.iNumDemuxChannels = 0; - aStreamParameters.iFileFormat = EFileFormatUnrecognized; - aStreamParameters.iVideoFormat = EVideoFormatNone; - aStreamParameters.iAudioFormat = EAudioFormatNone; - aStreamParameters.iVideoLength = 0; - aStreamParameters.iAudioLength = 0; - aStreamParameters.iStreamLength = 0; - aStreamParameters.iAudioFramesInSample = 0; - aStreamParameters.iVideoPicturePeriodNsec = 0; - aStreamParameters.iCanSeek = EFalse; - aStreamParameters.iFrameRate=0; - aStreamParameters.iVideoTimeScale=0; - aStreamParameters.iAudioTimeScale=0; - iAudioType = 0; - iVideoType = 0; - iNumberOfFrames=0; - - // get video description - error = MP4ParseRequestVideoDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iVideoLength, - &frameRate, &iVideoType, (mp4_u32 *)&aStreamParameters.iVideoWidth, - (mp4_u32 *)&aStreamParameters.iVideoHeight, (mp4_u32 *)&aStreamParameters.iVideoTimeScale); - - if ( error == MP4_NOT_AVAILABLE ) - User::Leave(KErrorCode); - else if ( error == MP4_INVALID_INPUT_STREAM ) - User::Leave(KErrCorrupt); - else if ( error == MP4_NO_VIDEO ) - { - hasVideo = EFalse; - aStreamParameters.iVideoWidth = aStreamParameters.iVideoHeight = 0; - } - else if ( error != MP4_OK ) - User::Leave(KErrorCode); - else - { - MPASSERT(error == MP4_OK); - } - - // get audio description. ask also for averagebitrate to get error if the track is empty; the information is needed later on - mp4_u32 averagebitrate = 0; - - error = MP4ParseRequestAudioDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iAudioLength, - &iAudioType, (mp4_u8*)&aStreamParameters.iAudioFramesInSample, (mp4_u32 *)&aStreamParameters.iAudioTimeScale, &averagebitrate ); - - if ( (error == MP4_ERROR) && ((iAudioType == MP4_TYPE_MPEG4_AUDIO) || (iAudioType == MP4_TYPE_AMR_NB) || (iAudioType == MP4_TYPE_AMR_WB))) - { - // a special case: there may be audio track but it is empty; if type was recognized, mark as no audio - PRINT((_L("CMP4Parser::ParseHeaderL() problems with getting audio description, mark no audio since audio type was recognized"))); - iAudioType = MP4_NO_AUDIO; - error = MP4_NO_AUDIO; - } - if(error == MP4_NOT_AVAILABLE) - User::Leave(EParserNotEnoughData); - else if ( error == MP4_INVALID_INPUT_STREAM ) - User::Leave(KErrCorrupt); - else if ( error != MP4_NO_AUDIO && error != MP4_OK ) - User::Leave(KErrorCode); - else - { - MPASSERT(error == MP4_OK || error == MP4_NO_AUDIO); - } - - // store the sample size for sanity checking purposes - iMaxAMRSampleSize = KVedMaxAMRFrameSize * aStreamParameters.iAudioFramesInSample; - - if (aStreamParameters.iVideoLength > 0) - aStreamParameters.iStreamLength = aStreamParameters.iVideoLength; - - if (aStreamParameters.iAudioLength > aStreamParameters.iVideoLength) - aStreamParameters.iStreamLength = aStreamParameters.iAudioLength; - - aStreamParameters.iFrameRate = frameRate; - - if(hasVideo) - { - - if ( iVideoType == MP4_TYPE_MPEG4_VIDEO ) - { - // read video resolution from VOL header - - HBufC8* tmpBuffer = (HBufC8*) HBufC8::NewLC(KVOLHeaderBufferSize); - TPtr8 tmpPtr = tmpBuffer->Des(); - mp4_u32 volSize = 0; - MP4Err volError = 0; - - volError = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, - (mp4_u8*)(tmpPtr.Ptr()), - KVOLHeaderBufferSize, - &volSize ); - - if ( volError != MP4_OK ) - { - User::Leave(KErrorCode); - } - tmpPtr.SetLength(volSize); - - CVedVolReader* tmpVolReader = CVedVolReader::NewL(); - CleanupStack::PushL(tmpVolReader); - - tmpVolReader->ParseVolHeaderL(tmpPtr); - - aStreamParameters.iVideoWidth = tmpVolReader->Width(); - aStreamParameters.iVideoHeight = tmpVolReader->Height(); - - CleanupStack::PopAndDestroy(tmpVolReader); - CleanupStack::PopAndDestroy(tmpBuffer); - - } - - else if ( iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE ) - { - // read resolution from SPS - - HBufC8* tmpBuffer = (HBufC8*) HBufC8::NewLC(KAVCDCRBufferSize); - TPtr8 ptr = tmpBuffer->Des(); - - // read decoder specific info - User::LeaveIfError( ReadAVCDecoderSpecificInfo(ptr) ); - - // create AVC editing instance - CVedAVCEdit* avcEdit = CVedAVCEdit::NewL(); - CleanupStack::PushL(avcEdit); - - TSize resolution(0,0); - User::LeaveIfError( avcEdit->GetResolution(ptr, resolution) ); - - CleanupStack::PopAndDestroy(avcEdit); - CleanupStack::PopAndDestroy(tmpBuffer); - - aStreamParameters.iVideoWidth = resolution.iWidth; - aStreamParameters.iVideoHeight = resolution.iHeight; - } - - - iNumberOfFrames = GetNumberOfVideoFrames(); - MPASSERT(iNumberOfFrames); - - if (iFirstTimeClipParsing) // update only at the first parsing of a clip - { - // update the frame numbers - - iOutputNumberOfFrames = iProcessor->GetOutputNumberOfFrames(); - - if (iOutputNumberOfFrames == 0) - { - iOutputNumberOfFrames += iNumberOfFrames; // total number of frames in all clips - } - else if (!iProcessor->IsThumbnailInProgress()) - { - iOutputNumberOfFrames += iNumberOfFrames; - } - } - - MPASSERT(frameRate > 0); - if (frameRate > 0) - aStreamParameters.iVideoPicturePeriodNsec = TInt64( TReal(1000000000) / TReal(frameRate) ); - else - aStreamParameters.iVideoPicturePeriodNsec = TInt64(33366667); - - if ( iVideoType == MP4_TYPE_H263_PROFILE_0 || iVideoType == MP4_TYPE_H263_PROFILE_3 ) - { - TVideoClipProperties prop; - prop.iH263Level = 0; - MP4ParseGetVideoClipProperties(iMP4Handle, prop); - - iMaxVideoFrameLength = KMaxCodedPictureSizeQCIF; - if (prop.iH263Level == 45) - { - aStreamParameters.iVideoFormat = EVideoFormatH263Profile0Level45; - } - else - { - aStreamParameters.iVideoFormat = EVideoFormatH263Profile0Level10; - } - } - else if ( iVideoType == MP4_TYPE_MPEG4_VIDEO ) - { - aStreamParameters.iVideoFormat = EVideoFormatMPEG4; - if ( aStreamParameters.iVideoWidth <= KVedResolutionQCIF.iWidth ) - { - iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4L0BQCIF;//distinction between L0 and L0B not possible here - } - else if (aStreamParameters.iVideoWidth <= KVedResolutionCIF.iWidth ) - { - iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4CIF; - } - else - { - // VGA - iMaxVideoFrameLength = KMaxCodedPictureSizeVGA; - } - } - - else if ( iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE ) - { - - // : Is it possible to dig up the level here ?? - aStreamParameters.iVideoFormat = EVideoFormatAVCProfileBaseline; - - if ( aStreamParameters.iVideoWidth <= KVedResolutionQCIF.iWidth ) - { - iMaxVideoFrameLength = KMaxCodedPictureSizeAVCLevel1B; //distinction between L0 and L0B not possible here ?? - } - else if (aStreamParameters.iVideoWidth <= KVedResolutionCIF.iWidth ) - { - iMaxVideoFrameLength = KMaxCodedPictureSizeAVCLevel1_2; - } - else - { - // default - iMaxVideoFrameLength = KMaxCodedPictureSizeAVCLevel1_2; - } - } - } - - if ( error == MP4_OK ) - { - // stream contains audio - if ( iAudioType == MP4_TYPE_AMR_NB ) - aStreamParameters.iAudioFormat = EAudioFormatAMR; - else - { - if ( iAudioType == MP4_TYPE_MPEG4_AUDIO ) - aStreamParameters.iAudioFormat = EAudioFormatAAC; - } - } - - TBool videoMpeg4OrAVC = ( iVideoType == MP4_TYPE_MPEG4_VIDEO || - iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE ); - - if ( (videoMpeg4OrAVC && iAudioType == MP4_TYPE_MPEG4_AUDIO) || - (videoMpeg4OrAVC && iAudioType == MP4_TYPE_NONE) || - (iVideoType == MP4_TYPE_NONE && iAudioType == MP4_TYPE_MPEG4_AUDIO) ) - aStreamParameters.iFileFormat = EFileFormatMP4; - - else if (iVideoType != MP4_TYPE_NONE || iAudioType != MP4_TYPE_NONE) - aStreamParameters.iFileFormat = EFileFormat3GP; - - if ( aStreamParameters.iStreamLength == 0 ) - aStreamParameters.iFileFormat = EFileFormatUnrecognized; - - if ( aStreamParameters.iVideoFormat != EVideoFormatNone ) - { - aStreamParameters.iHaveVideo = ETrue; - aStreamParameters.iNumDemuxChannels++; - } - - if ( aStreamParameters.iAudioFormat != EAudioFormatNone ) - { - aStreamParameters.iHaveAudio = ETrue; - aStreamParameters.iNumDemuxChannels++; - } - - aStreamParameters.iMaxPacketSize = 0; // N/A - aStreamParameters.iLogicalChannelNumberVideo = 0; // N/A - aStreamParameters.iLogicalChannelNumberAudio = 0; // N/A - - // get stream description - error = MP4ParseRequestStreamDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iStreamSize, - (mp4_u32 *)&aStreamParameters.iStreamBitrate); - if ( error != MP4_OK ) - User::Leave(KErrorCode); - - // do sanity-check for bitrate - if (aStreamParameters.iStreamBitrate < KMinBitrate) - User::Leave(KErrCorrupt); - - aStreamParameters.iReferencePicturesNeeded = 0; - aStreamParameters.iNumScalabilityLayers = 0; - - // determine if the stream contains INTRA frames so seeking is possible - // If the stream contains more than one INTRA frame, seeking is - // allowed. - - if (hasVideo) - { - mp4_u32 position = aStreamParameters.iStreamLength + 1000; - mp4_u32 audioTime, videoTime; - - // Seek past stream duration to find out the position of last INTRA frame - error = MP4ParseSeek(iMP4Handle, position, &audioTime, &videoTime, ETrue); - if ( error != MP4_OK ) - User::Leave(KErrorCode); - - if (videoTime != 0) - { - // at least two INTRAs - aStreamParameters.iCanSeek = ETrue; - } - - // rewind file back to beginning - error = MP4ParseSeek(iMP4Handle, 0, &audioTime, &videoTime, EFalse); - if ( error != MP4_OK ) - User::Leave(KErrorCode); - } - - PRINT((_L("CMP4Parser::ParseHeaderL() end"))); - - return KErrNone; -} - - -// --------------------------------------------------------- -// CMP4Parser::IsStreamable -// Finds out whether input stream is multiplexed so that -// it can be streamed, i.e. played while receiving the stream. -// (other items were commented in a header). -// --------------------------------------------------------- -// - -TInt CMP4Parser::IsStreamable() -{ - MP4Err error; - - error = MP4ParseIsStreamable(iMP4Handle); - if ( error == MP4_NOT_AVAILABLE ) - return EParserNotEnoughData; - else if ( error == MP4_INVALID_INPUT_STREAM ) - return KErrNotSupported; - else if ( error == MP4_ERROR ) - return KErrorCode; - else - return ( error == MP4_OK ) ? 1 : 0; -} - - -// --------------------------------------------------------- -// CMP4Parser::Seek -// Seeks the file to desired position in milliseconds -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::Seek(TUint32 aPositionInMs, TUint32& anAudioTimeAfter, TUint32& aVideoTimeAfter) -{ - - MP4Err error = MP4_OK; - MPASSERT(iStreamSource == ESourceFile); - error = MP4ParseSeek(iMP4Handle, aPositionInMs, &anAudioTimeAfter, &aVideoTimeAfter, ETrue); - if (error != MP4_OK) - return KErrorCode; - - return KErrNone; -} - - - -TInt CMP4Parser::GetNumberOfFrames() -{ - return iNumberOfFrames; -} - -// --------------------------------------------------------- -// CMP4Parser::SeekOptimalIntraFrame -// Seeks to INTRA frame position before given time -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::SeekOptimalIntraFrame(TTimeIntervalMicroSeconds aStartTime, TInt /*aIndex*/, TBool aFirstTime) -{ - MP4Err error = KErrNone; - TInt revisedNumberOfFrames = 0; - mp4_u32 audioTime = 0; - mp4_u32 videoTime = 0; -// mp4_u32 timeScale = 0; - - // calculate the start time of the cut operation - TInt64 startTime = aStartTime.Int64() / TInt64(1000); - mp4_u32 startPosition = (mp4_u32)( I64INT(startTime) ); // in milliseconds - - TBool intraFound = (startPosition == 0); - - if (!aFirstTime) - intraFound = 0; - - // First check if the first included frame is intra - if (!intraFound) - { - // seek to previous frame preceding start time or at start time - error = MP4ParseSeek(iMP4Handle, startPosition, &audioTime, &videoTime, EFalse); - if (error != MP4_OK) - { - return KErrorCode; - } - MPASSERT(videoTime <= startPosition); - - // get index of the frame - TInt index = iProcessor->GetVideoFrameIndex(TTimeIntervalMicroSeconds(videoTime*1000)); - - if (videoTime < startPosition) - { - // if there was no frame at start time, seek - // one frame forward to the first included frame - index++; - } - - // get frame type - mp4_bool frameType; - error = MP4ParseGetVideoFrameType(iMP4Handle, index, &frameType); - if (error != MP4_OK) - { - return KErrorCode; - } - if (frameType == 1) - { - intraFound = ETrue; - iStartFrameIndex = index; - - mp4_u32 timeInTicks; - // get timestamp of matched frame to startPosition - error = MP4ParseGetVideoFrameStartTime(iMP4Handle, index, &timeInTicks, &startPosition); - if (error != MP4_OK) - { - return KErrorCode; - } - - // Now seek to found Intra in 1 ms increments. The loop is needed - // because due to rounding error, MP4Parser may seek to previous - // frame instead of the I-frame at startPosition - TInt seekTime = startPosition; - videoTime = 0; - - while (videoTime != startPosition) - { - error = MP4ParseSeek(iMP4Handle, seekTime, &audioTime, &videoTime, EFalse); - if (error != MP4_OK) - { - return KErrorCode; - } - MPASSERT(videoTime <= startPosition); - seekTime++; // add 1 ms - } - - } - } - - if (!intraFound) - { - // seek to the I-frame preceding the start time - error = MP4ParseSeek(iMP4Handle, startPosition, &audioTime, &videoTime, ETrue); - if (error != MP4_OK) - { - return KErrorCode; - } - } - - if (videoTime != 0) - { - if (!intraFound) - { - // get index of the intra frame - TInt64 time = TInt64(TUint(videoTime)) * TInt64(1000); - iStartFrameIndex = iProcessor->GetVideoFrameIndex(TTimeIntervalMicroSeconds( time )); - } - - if (aFirstTime) - { - revisedNumberOfFrames = iNumberOfFrames - iStartFrameIndex; - // update movie and clip number of frames - iOutputNumberOfFrames -= iStartFrameIndex; - iNumberOfFrames = revisedNumberOfFrames; - } - - PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() revised = %d"),revisedNumberOfFrames)); - PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() iNumberOfFrames = %d"),iNumberOfFrames)); - PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() iStartFrameIndex = %d"),iStartFrameIndex)); - PRINT((_L("CMP4Parser::SeekOptimalIntraFrame() iOutputNumberOfFrames = %d"),iOutputNumberOfFrames)); - iFrameNumber = iStartFrameIndex; - } - return KErrNone; -} - -// --------------------------------------------------------- -// CMP4Parser::GetNumberOfVideoFrames -// Gets the number of video frames in clip -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::GetNumberOfVideoFrames() -{ - mp4_u32 numberOfFrames = 0; - MP4Err error = 0; - - error = MP4ParseGetNumberOfVideoFrames(iMP4Handle, &numberOfFrames); - - if (error != MP4_OK) - return 0; - - return numberOfFrames; - -} - -// --------------------------------------------------------- -// CMP4Parser::GetVideoFrameSize -// Gets the size of video frame at given index -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::GetVideoFrameSize(TInt aIndex) -{ - mp4_u32 frameSize = 0; - mp4_u32 mp4Specific = 0; - MP4Err error = 0; - - if ( aIndex == 0 && iVideoType == MP4_TYPE_MPEG4_VIDEO ) - { - error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific ); - - if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL ) - return KErrorCode; - } - - error = MP4ParseGetVideoFrameSize(iMP4Handle, aIndex, &frameSize); - - if (error != MP4_OK) - return KErrorCode; - - return frameSize + mp4Specific; - -} - - - -// --------------------------------------------------------- -// CMP4Parser::GetVideoFrameStartTime -// Returns frame start time in millisec - optional iTimestamp for start time in ticks -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::GetVideoFrameStartTime(TInt aIndex, TInt* aTimeStampInTicks) -{ - - MP4Err error = 0; - mp4_u32 timeStampInMs = 0; - - MPASSERT(aTimeStampInTicks); - - PRINT((_L("CMP4Parser::GetVideoFrameStartTime(), get time for index %d"), aIndex)); - error = MP4ParseGetVideoFrameStartTime(iMP4Handle, aIndex, (mp4_u32*)aTimeStampInTicks, &timeStampInMs); - - if (error != MP4_OK) - { - PRINT((_L("CMP4Parser::GetVideoFrameStartTime(), error from MP4 parser %d"), error)); - return KErrorCode; - } - - PRINT((_L("CMP4Parser::GetVideoFrameStartTime(), time in ms %d"), timeStampInMs)); - return timeStampInMs; - -} - - -// --------------------------------------------------------- -// CMP4Parser::GetVideoFrameType -// Gets the type of video frame at given index -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt8 CMP4Parser::GetVideoFrameType(TInt aIndex) -{ - - MP4Err error = 0; - mp4_bool frameType; - - error = MP4ParseGetVideoFrameType(iMP4Handle, aIndex, &frameType); - - if (error != MP4_OK) - return KErrGeneral; - - return TInt8(frameType); -} - - -// --------------------------------------------------------- -// CMP4Parser::GetVideoFrameProperties -// Gets frame properties -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::GetVideoFrameProperties(TFrameInfoParameters* aVideoFrameInfoArray, - TUint32 aStartIndex, TUint32 aSizeOfArray) -{ - MP4Err error; - error = MP4GetVideoFrameProperties(iMP4Handle,aStartIndex,aSizeOfArray,aVideoFrameInfoArray); - - if (error != MP4_OK) - return KErrorCode; - - return KErrNone; -} - - -// --------------------------------------------------------- -// CMP4Parser::ParseAudioInfo -// Gets the frame information (frame size) for audio in the current clip -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::ParseAudioInfo(TInt& aAudioFrameSize) -{ - MP4Err error; - mp4_u32 audioLength=0; - mp4_u32 audioType=0; - mp4_u32 audioFramesInSample=0; - mp4_u32 audioTimeScale=0; - mp4_u32 avgBitRate=0; - mp4_double frameLength = 0.02; // 20 ms - - error = MP4ParseRequestAudioDescription(iMP4Handle, (mp4_u32 *)&audioLength, - &audioType, (mp4_u8*)&audioFramesInSample, (mp4_u32 *)&audioTimeScale, (mp4_u32*)&avgBitRate); - aAudioFrameSize = ((mp4_u32)((mp4_double)avgBitRate*frameLength)>>3); - - return error; -} - -TInt CMP4Parser::GetMP4SpecificSize() -{ - MP4Err error = 0; - mp4_u32 mp4Specific = 0; - if ( iVideoType == MP4_TYPE_MPEG4_VIDEO ) - { - error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific ); - if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL ) - return KErrGeneral; - } - return mp4Specific; -} - -// --------------------------------------------------------- -// CMP4Parser::ReadAudioDecoderSpecificInfoL -// Gets the decoder specific info from the current file filled so that it can be composed to output file -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::ReadAudioDecoderSpecificInfoL(HBufC8*& aBytes, TInt aBufferSize) -{ - aBytes = HBufC8::NewL(aBufferSize); - CleanupStack::PushL(aBytes); - mp4_u8 *buffer = new (ELeave) mp4_u8[aBufferSize]; - mp4_u32 decspecinfosize = 0; - - MP4Err err = MP4ParseReadAudioDecoderSpecificInfo( - iMP4Handle, - buffer, - aBufferSize, - &decspecinfosize); - if (err == MP4_OK) - { - for (TInt a = 0 ; a < (TInt)decspecinfosize ; a++) - { - aBytes->Des().Append(buffer[a]); - } - } - else - { - delete[] buffer; - buffer = 0; - CleanupStack::PopAndDestroy(aBytes); - aBytes = 0; - User::Leave(KErrGeneral); - } - delete[] buffer; - buffer = 0; - CleanupStack::Pop(aBytes); - return ETrue; -} - -// --------------------------------------------------------- -// CMP4Parser::SetDefaultAudioDecoderSpecificInfoL -// Gets the default decoder specific info filled so that it can be composed to output file -// the default info is for a 16 KHz, mono LC type AAC only -// (other items were commented in a header). -// --------------------------------------------------------- -// -TInt CMP4Parser::SetDefaultAudioDecoderSpecificInfoL(HBufC8*& aBytes, TInt aBufferSize) -{ - aBytes = HBufC8::NewL(aBufferSize); - CleanupStack::PushL(aBytes); - - const TUint8 frameDecSpecInfo[] = {0x14,0x08}; //the decoder specific - const TInt frameSize = 2; //constant as maximum size of decoderspecific info is 2 - - for (TInt a = 0 ; a < frameSize ; a++) - { - aBytes->Des().Append(frameDecSpecInfo[a]); - } - CleanupStack::Pop(aBytes); - return ETrue; -} - - -TInt CMP4Parser::GetAudioBitrate(TInt& aBitrate) -{ - - mp4_u32 length; - mp4_u32 type; - mp4_u8 framesPerSample; - mp4_u32 timeScale; - mp4_u32 averageBitrate; - - MP4Err error = 0; - - error = MP4ParseRequestAudioDescription(iMP4Handle, &length, - &type, &framesPerSample, &timeScale, &averageBitrate); - - if ( error != 0 ) - return KErrGeneral; - - aBitrate = averageBitrate; - - return KErrNone; - - -} - -TInt CMP4Parser::GetVideoFrameRate(TReal& aFrameRate) -{ - - mp4_u32 length; - mp4_double frameRate; - mp4_u32 videoType; - mp4_u32 width; - mp4_u32 height; - mp4_u32 timeScale; - - MP4Err error = 0; - - // get video description - error = MP4ParseRequestVideoDescription(iMP4Handle, &length, &frameRate, - &videoType, &width, &height, &timeScale); - - if ( error != 0 ) - return KErrGeneral; - - TReal temp = frameRate * 2.0; - TInt temp2 = TInt(temp + 0.5); - - aFrameRate = temp2 / 2.0; - - return KErrNone; -} - -TInt CMP4Parser::GetDecoderSpecificInfoSize() -{ - - MPASSERT(iMP4Handle); - - mp4_u32 mp4Specific = 0; - - MP4Err error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific ); - - if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL ) - return KErrGeneral; - - return mp4Specific; -} - -TInt CMP4Parser::ReadAVCDecoderSpecificInfo(TDes8& buf) -{ - - mp4_u32 mp4Specific = 0; - - MP4Err error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, (mp4_u8*)(buf.Ptr()), - mp4_u32( buf.MaxLength() ), &mp4Specific ); - - - if (error != MP4_OK) - return KErrorCode; - - buf.SetLength(mp4Specific); - - return KErrNone; - -} - -TInt CMP4Parser::GetVideoDuration(TInt& aDurationInMs) -{ - - mp4_u32 length; - mp4_double frameRate; - mp4_u32 videoType; - mp4_u32 width; - mp4_u32 height; - mp4_u32 timeScale; - - MP4Err error = 0; - - // get video description - error = MP4ParseRequestVideoDescription(iMP4Handle, &length, &frameRate, - &videoType, &width, &height, &timeScale); - - if ( error != MP4_OK ) - return KErrGeneral; - - aDurationInMs = length; - - return KErrNone; - -} - - -// End of File