camcordermmfplugin/filecomposer/Src/CamC3GPDataSinkImp.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 02 Feb 2010 00:20:52 +0200
changeset 2 c7e61a0077eb
parent 1 2d3e1993fb02
child 6 bcdc0181a9f1
permissions -rw-r--r--
Revision: 201003 Kit: 201005

/*
* Copyright (c) 2002-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:  3GP file composer
*
*/

// INCLUDE FILES
#include <f32file.h>
#include <mmf/server/mmffile.h>
#include <sysutildomaincrkeys.h>	// for critical disk level CentralRepository keys
#include <3gplibrary/mp4lib.h>
#include "CamC3GPDataSink.h"
#include "CamC3GPDataSinkImp.h"
#include "CCMRMediaSink.h"
#include "CCMRSupportedCodecs.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>

// MACROS
// Debug print macro
#ifdef _DEBUG
#include <e32svr.h>
#define PRINT(x) RDebug::Print x
#else
#define PRINT(x)
#endif

// CONSTANTS
const TUint   KVideoAverageBitRate   = 48000;     // Default average bitrate for video
const TUint   KVideoMaxBitRate       = 64000;     // Default maximum bitrate for video
const TUint   KVideoXResolution      = 176;       // Default width of video
const TUint   KVideoYResolution      = 144;       // Default height of video
const TUint   KVideoBufferSize       = 8192;      // Maximum video frame size
const TUint   KAudioMaxFrameSize     = 32;        // Maximum AMR audio frame size
const TUint   KAudioBufferNumber     = 10;        // Number of audio frames to be buffered
const TUint   KVideoTimeScale        = 30000;     // Video timescale in the output file; use 30000 since it corresponds roughly to ~30 fps.
                                                  // 29970 would be exact for H.263, but it may not be exactly camera's baseframerate. And it may be harder for some players than 30000
                                                  // The most important is now that this value is in the same scale as used in MediaRecorder for Camera API framerate.
                                                  // If that is 15, then this should be 30000. But some other, e.g. 14.985 fps is used there, then it is better to change this one too.
const TUint   KAudioTimeScale        = 8000;      // Audio timescale in the output file, safer to use the same value as sampling rate although makes the times more difficult to understand
const TUint   KAudioFrameDuration    = 8*20;      // AMR frame is 20 ms, but timescale is 8000 => duration is 160 / 8000 s
const TUint8  KAMRAudioFramesPerSample  = 10;     // Number of AMR audio frames per sample in the output file
const TUint8  KAACAudioFramesPerSample  = 1;      // Number of AAC audio frames per sample in the output file
const TUint   KAACDefaultSampleRate  = 16000;     // Default samplerate for AAC that is used as audio track timescale in case we get no audiobuffers, but audio codec is selected.
const TUint16 KAudioModeSet          = 0x81ff;    // AMR modeset: all modes possible
const TUint   KDiskSafetyLimit       = 400000;    // Amount of free disk space to leave unused
const TReal   KMetaDataCoeff         = 1.03;      // Coefficient to estimate metadata amount
const TInt    KFreeDiskSpaceCounter  = 10;        // Interval when to find out real free disk space
const TUint   KFTYPSize              = 24;        // Size of FTYP box in bytes in 3GP files
const TUint   KCamCMaxClipDurationInSecs = 5400;  // Maximun video clip duration in seconds
const TInt    KLimitForLargeFileBuffers = 100000; // Bitrate limit to toggle to larger output file buffers in composer.
const TInt    KDelayUseBitrates      = 3000000;   // Delay used in GetRemainingTime until function uses real file sizes instead of avarage bitrates.
const TInt    KCamC3GPDeleteFileQueueGranularity  = 10; // Optimal value is the number of temporary files
const TUint32 KCamC3GPMaximumFileSize = 4294967295UL; // max size for RFile

_LIT(KTmpFileName, "\\system\\Temp\\CamcorderTMP");               // Temporary output file name

// ============================ MEMBER FUNCTIONS ===============================


// -----------------------------------------------------------------------------
// CCamC3GPDataSink::NewL
//
// Sink constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CCamC3GPDataSink* CCamC3GPDataSink::NewL(M3GPDataSinkObserver *aObserver)
    {
	CCamC3GPDataSinkImp* self = new (ELeave) CCamC3GPDataSinkImp();
	CleanupStack::PushL(self);
	self->ConstructL(aObserver);
	CleanupStack::Pop();
	return self;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp
//
// Sink destructor.
// -----------------------------------------------------------------------------
//
CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp(void)
    {
    PRINT(_L("CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp enter"));

    if ( iFileName != KNullDesC )
        {
        // we need to try to stop sink
        TInt error = KErrNone;
        TRAP(error, SinkStopL());
        iFileName = KNullDesC;
        }

    if (iMP4Handle)
        {
        MP4ComposeClose(iMP4Handle);
        iMP4Handle = NULL;
        }

    if (iFS)
        {
        iFS->Delete(iTmpFileName);
        iFS->Close();
        delete iFS;
        iFS = NULL;
        }

    delete [] iVideoBuffer;
    delete [] iAudioBuffer;
    iObserver = NULL;
    iMMFFile = NULL; // not owned
    iFile = NULL; // not owned

    // Delete the CIdle async file remover object
    delete iIdleDelete;
    iIdleDelete = 0;

    // Do async temp file deletion for rest of files
    if ( iDeleteFileQueue )
        {
        // Reset and destroy the file name pointers from queue (if any left).
        iDeleteFileQueue->ResetAndDestroy();
        }
    delete iDeleteFileQueue;
    iDeleteFileQueue = 0;
    PRINT(_L("CCamC3GPDataSinkImp::~CCamC3GPDataSinkImp exit"));
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::ConstructL
//
// Symbian 2nd phase constructor.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::ConstructL(M3GPDataSinkObserver *aObserver)
	{
    PRINT(_L("CCamC3GPDataSinkImp::ConstructL enter"));
    iObserver = aObserver;

    iVideoBuffer = new (ELeave) TUint8[KVideoBufferSize];
    iVideoBufferSize = KVideoBufferSize;

    iAudioBuffer = new (ELeave) TUint8[KAudioMaxFrameSize * KAudioBufferNumber];
    iAudioBufferSize = KAudioMaxFrameSize * KAudioBufferNumber;

    iMP4Handle = NULL;
    iMMFFile = NULL;

    iFileName = KNullDesC;

    iBytesReceived = 0;
    iBytesOfMetadata = 0;

    iVideoXResolution = 0;
    iVideoYResolution = 0;
    iVideoAverageBitRate = -1;
    iVideoMaxBitRate = -1;
    iAudioAverageBitRate = -1;

    iBufferSize = 0;
    iFileCodecType = MP4_TYPE_NONE;
    iVideoTimestamp = 0;
    iVideoBufferTimestamp = -1;
    iFirstVideoFrameTimestamp = 0;
    iVideoRandomAccessPoint = EFalse;
    iVideoBufferRandomAccessPoint = EFalse;
    iVideoFrameDuration = 0;
    iVideoBufferFrameSize = 0;
    iVideoFrameNumber = 0;
    iVideoIntraFrameNumber = 0;
    iVideoDecSpecInfoSize = 0;
    iAudioDecSpecInfoSize = 0;
    iAudioBufferFrameSize = 0;
    iAudioFrameNumber = 0;
    iAudioFramesInBuffer = 0;
    iFreeDiskSpace = 0;
    iFreeDiskSpaceCounter = 0;
    iAvailableSpaceAtStart = 0;
    iAvarageEndTime = -1;
    iAudioAACFrameDuration = 0;
    iAudioAACSamplerate = 0;
    iAVCOutputLevel = 10;
    iCriticalDiskVal = 0;

    iSizeLimit = KCamC3GPMaximumFileSize; // max size for RFile
    iFileSizeLimitReached = EFalse;
    iDiskFull = EFalse;
    iFS = NULL;

    iDeleteFileQueue = new( ELeave ) RPointerArray<MP4FileName>( KCamC3GPDeleteFileQueueGranularity );

    // Idle priority Active object for async video temp file deletion
    iIdleDelete = CIdle::NewL( CActive::EPriorityIdle );

    PRINT(_L("CCamC3GPDataSinkImp::ConstructL exit"));
	}

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::OpenFileL
//
// Opens a 3GP file for writing.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::OpenFileL(CMMFFile* aMMFFile, TFourCC aAudioCodecType, const TDesC8& aVideoCodecType, TCamCSinkFileFormat aFileFormat )
    {
    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL CMMFFile enter")));

    TFileName aFileName;
    iMMFFile = aMMFFile;
    aFileName = iMMFFile->FullName();

    OpenFileL(aFileName, aAudioCodecType, aVideoCodecType, aFileFormat);
    }

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::OpenFileL
//
// Opens a 3GP file for writing.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::OpenFileL(TFileName aFileName, TFourCC aAudioCodecType, const TDesC8& aVideoCodecType, TCamCSinkFileFormat aFileFormat)
    {
    MP4Err    error;

    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL TFileName enter")));

    if (iMP4Handle)
        {
        User::Leave(KErrGeneral);
        }

    iVideoBufferTimestamp = -1;     // reset duration information for new file
    iFirstVideoFrameTimestamp = 0;
    iAvailableSpaceAtStart = 0;
    iAvarageEndTime = -1;
    iVideoFrameNumber = 0;
    iVideoIntraFrameNumber = 0;
    iBytesReceived = 0;
    iAudioAACFrameDuration = 0;
    iAudioAACSamplerate = 0;
    iFileHandleExists = EFalse;

    iDiskFull = EFalse;
    iTmpFileName = KTmpFileName;
    iFileName = aFileName;
    TInt errorcode;

    if (!iFS) // Don't allocate new file server, if there is one already
        {
        iFS = new (ELeave) RFs;

        errorcode = iFS->Connect();
        if ( errorcode != KErrNone)
            {
            delete(iFS);
            iFS = NULL;
            User::Leave( errorcode );
            }
        }

    TParse fp;
    User::LeaveIfError(iFS->Parse(iFileName, fp));
    TPtrC driveletter = fp.Drive();
    TChar drl = driveletter[0];
    User::LeaveIfError(iFS->CharToDrive(drl, iDriveNumber));

    // Get critical level for this drive type
    TDriveInfo driveInfo;
    iFS->Drive(driveInfo, iDriveNumber);

    iCriticalDiskVal = 0;
	if ( driveInfo.iType == EMediaRam ) // RAM drives have different critical levent than others
		{
		PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Asking disk critical level, memtype: EMediaRam")));
		CRepository* repository = CRepository::NewLC( KCRUidDiskLevel );
		User::LeaveIfError( repository->Get( KRamDiskCriticalLevel, iCriticalDiskVal ) );
		PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Got disk critical level: %d"),iCriticalDiskVal ));
		CleanupStack::PopAndDestroy( repository );
		}
	else // Some other media type
		{
		PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Asking disk critical level, memtype: other")));
		CRepository* repository = CRepository::NewLC( KCRUidDiskLevel );
		User::LeaveIfError( repository->Get( KDiskCriticalThreshold, iCriticalDiskVal ) );
		PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Got disk critical level: %d"),iCriticalDiskVal ));
		CleanupStack::PopAndDestroy( repository );
		}

    errorcode = iFS->MkDirAll(fp.DriveAndPath());
    if ( (errorcode != KErrAlreadyExists ) && ( errorcode != KErrNone ) )
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Error creating output path: '%s', error: %d"), fp.DriveAndPath().Ptr(), errorcode ));
        User::Leave(errorcode);
        }

    errorcode = iFS->SetAtt( iFileName, KEntryAttNormal, KEntryAttReadOnly );
    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Deleting File: '%s'"), iFileName.Ptr()));
    errorcode = iFS->Delete(iFileName);
    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Deleting File Error: %d"), errorcode));

    if ( errorcode == KErrInUse && iMMFFile )
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL using rfiles")));
        iMMFFile->SinkPrimeL();
        iFile = &(iMMFFile->FileL());
        iFileHandleExists = ETrue;
        }
    else if ( ( errorcode != KErrNone ) && ( errorcode != KErrNotFound ) && ( errorcode != KErrPathNotFound ) )
        {
        User::Leave(errorcode);
        }

    iTmpFileName.Insert(0, fp.Drive());
    errorcode = iFS->SetAtt( iTmpFileName, KEntryAttNormal, KEntryAttReadOnly );
    errorcode = iFS->Delete(iTmpFileName);
    if ( ( errorcode != KErrNone ) && ( errorcode != KErrNotFound ) && ( errorcode != KErrPathNotFound ) )
    	{
        if ( errorcode == KErrInUse )
        	{
        	// use actual output filename incase other instance still running with temporary file.
            PRINT((_L("CCamC3GPDataSinkImp::OpenFileL temporary output file in use (-14). Using actual output filename instead.")));
        	iTmpFileName = aFileName;
            errorcode = iFS->SetAtt( iTmpFileName, KEntryAttNormal, KEntryAttReadOnly );
            errorcode = iFS->Delete(iTmpFileName);
            if ( ( errorcode != KErrNone ) && ( errorcode != KErrNotFound ) && ( errorcode != KErrPathNotFound ) )
            	{
            	User::Leave(errorcode);
            	}
        	}
        else
        	{
        	User::Leave(errorcode);
        	}
        }

    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Temp files cleared")));

    // Find used audio codec
    if ( ( aAudioCodecType == TFourCC(KCMRFourCCIdAMRNB) ) ) // AMR-NB
        {
        iFileCodecType |= MP4_TYPE_AMR_NB;
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Audio codec: AMR-NB")));
        }
    else if ( aAudioCodecType == TFourCC(KCMRFourCCIdMPEG4AAC) ) // AAC
        {
        iFileCodecType |= MP4_TYPE_MPEG4_AUDIO;
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Audio codec: AAC")));
        }
    else
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Audio codec: none")));
        // if audio codec is null we don't generate audiotrack to composed file.
        }

    // Find used video codec
    mp4_u8 videoLevel = 10;

    if ( aVideoCodecType == KNullDesC8 ) // No video codec set.
        {
        // filecomposer will always create videotrack, whether we get video frames or not.
        iFileCodecType |= MP4_TYPE_H263_PROFILE_0;
        }
    else
        {
        TBuf8<256> matchstring;
        matchstring = KCMRMimeTypeH263;
        matchstring += _L8( "*" );

        if ( ( aVideoCodecType.MatchF( matchstring ) != KErrNotFound ) ) // H.263
            {
            matchstring = KCMRMimeTypeH263Profile3;
            matchstring += _L8( "*" );

            if ( aVideoCodecType.MatchF( matchstring ) != KErrNotFound )
                {
                iFileCodecType |= MP4_TYPE_H263_PROFILE_3;   // H.263 profile 3
                PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 profile 3")));
                }
            else
                {
                iFileCodecType |= MP4_TYPE_H263_PROFILE_0;   // H.263 profile 0
                PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 profile 0")));
                }
            // check if level is indicated too
            matchstring = _L8("*level=*");
            if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound )
                {
                // yes, there is, check what it is
                if ( aVideoCodecType.MatchF( _L8("*level=10*") ) != KErrNotFound )
                    {
                    videoLevel = 10;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 10")));
                    }
                else if ( aVideoCodecType.MatchF( _L8("*level=20*") ) != KErrNotFound )
                    {
                    videoLevel = 20;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 20")));
                    }
                else if ( aVideoCodecType.MatchF( _L8("*level=30*") ) != KErrNotFound )
                    {
                    videoLevel = 30;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 30")));
                    }
                else if ( aVideoCodecType.MatchF( _L8("*level=40*") ) != KErrNotFound )
                    {
                    videoLevel = 40;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 40")));
                    }
                else if ( aVideoCodecType.MatchF( _L8("*level=45*") ) != KErrNotFound )
                    {
                    videoLevel = 45;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 45")));
                    }
                else if ( aVideoCodecType.MatchF( _L8("*level=50*") ) != KErrNotFound )
                    {
                    videoLevel = 50;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 50")));
                    }
                else
                    {
                    // assume 10
                    videoLevel = 10;
                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Video codec: H.263 level 10")));
                    }
                }
            }
        else // MPEG-4
            {
            matchstring = KCMRMimeTypeMPEG4V;
            matchstring += _L8( "*" );

            if ( aVideoCodecType.MatchF(matchstring) != KErrNotFound )
                {
                iFileCodecType |= MP4_TYPE_MPEG4_VIDEO;     // MPEG-4
                }
            else // H.264 AVC
	            {
	            matchstring = KCMRMimeTypeH264AVC;
	            matchstring += _L8( "*" );

	            if ( aVideoCodecType.MatchF(matchstring) != KErrNotFound )
	                {
                    iAVCOutputLevel = 10;
		            // check if profile & level is indicated too
		            matchstring = _L8("*profile-level-id=*");
		            if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound )
		                {
		                // yes, there is, check what it is
	                    // Determine if other AVC profile is used:
                        matchstring = _L8( "*profile-level-id=42*" ); // Main Profile 
                        if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound)
                            {
                            iFileCodecType |= MP4_TYPE_AVC_PROFILE_BASELINE;     // H.264 AVC Baseline profile found 
                            }
	                    matchstring = _L8( "*profile-level-id=4D*" ); // Main Profile 
	                    if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound)
	                        {
	                        iFileCodecType |= MP4_TYPE_AVC_PROFILE_MAIN;     // H.264 AVC Main profile found 
	                        }
	                    matchstring = _L8( "*profile-level-id=64*" ); // High Profile 
	                    if (aVideoCodecType.MatchF( matchstring ) != KErrNotFound)
	                        {
	                        iFileCodecType |= MP4_TYPE_AVC_PROFILE_HIGH;     // H.264 AVC Baseline profile found 
	                        }
		                
	                    // Determine if other AVC level is used:
		                if ( aVideoCodecType.MatchF( _L8("*00A*") ) != KErrNotFound )
		                    {
		                    iAVCOutputLevel = 10; 	// Level 1
		                    }
		                else if ( (aVideoCodecType.MatchF( _L8("*profile-level-id=42900B*") ) != KErrNotFound) ||
                                  (aVideoCodecType.MatchF( _L8("*profile-level-id=4D500B*") ) != KErrNotFound) || 
                                  (aVideoCodecType.MatchF( _L8("*profile-level-id=644009*") ) != KErrNotFound) )
		                    {
		                    iAVCOutputLevel = 101; 	// Level 1b
		                    }
                        else if ( (aVideoCodecType.MatchF( _L8("*profile-level-id=42800B*") ) != KErrNotFound) ||
                                  (aVideoCodecType.MatchF( _L8("*profile-level-id=4D400B*") ) != KErrNotFound) || 
                                  (aVideoCodecType.MatchF( _L8("*profile-level-id=64400B*") ) != KErrNotFound) )
		                    {
		                    iAVCOutputLevel = 11;	// Level 1.1
		                    }
		                else if ( aVideoCodecType.MatchF( _L8("*00C*") ) != KErrNotFound )
		                    {
		                    iAVCOutputLevel = 12;	// Level 1.2
		                    }
		                else if ( aVideoCodecType.MatchF( _L8("*00D*") ) != KErrNotFound )
		                    {
		                    iAVCOutputLevel = 13;	// Level 1.3
		                    }
		                else if ( aVideoCodecType.MatchF( _L8("*014*") ) != KErrNotFound )
		                    {
		                    iAVCOutputLevel = 20;	// Level 2
		                    }
                        else if ( aVideoCodecType.MatchF( _L8("*015*") ) != KErrNotFound )
                            {
                            iAVCOutputLevel = 21;   // Level 2.1
                            }
                        else if ( aVideoCodecType.MatchF( _L8("*016*") ) != KErrNotFound )
                            {
                            iAVCOutputLevel = 22;   // Level 2.2
                            }
                        else if ( aVideoCodecType.MatchF( _L8("*01E*") ) != KErrNotFound )
                            {
                            iAVCOutputLevel = 30;   // Level 3
                            }
                        else if ( aVideoCodecType.MatchF( _L8("*01F*") ) != KErrNotFound )
                            {
                            iAVCOutputLevel = 31;   // Level 3.1
                            }
                        else if ( aVideoCodecType.MatchF( _L8("*020*") ) != KErrNotFound )
                            {
                            iAVCOutputLevel = 32;   // Level 3.2
                            }
                        else if ( aVideoCodecType.MatchF( _L8("*028*") ) != KErrNotFound )
                            {
                            iAVCOutputLevel = 4;   // Level 4
                            }
		                else
		                    {
		                    // assume level 1
		                    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Warning unknown video codec type - defaulting level 1.0")));
		                    iAVCOutputLevel = 10;
		                    }
		                }
	                }
	            else
		            {
    				PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Unsupported video codec type")));
		            User::Leave(KErrArgument);
		            }
	            }
            }
        }

    if ( iFileHandleExists )
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL using rfile to open mp4handle")));
        error = MP4ComposeOpenFileHandle(&iMP4Handle, iFile, (TDriveNumber)iDriveNumber, iFileCodecType);
        }
    else
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL using descriptors to open mp4handle")));
        error = MP4ComposeOpen(&iMP4Handle, (MP4FileName)iTmpFileName.Ptr(), iFileCodecType);
        }

    if ( error == MP4_OUT_OF_MEMORY )
    	{
    	PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeOpen, error=%d"), error));
    	User::Leave(KErrNoMemory);
    	}
    else if (error != MP4_OK)
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeOpen, error=%d"), error));
        TInt64 currentdiskspace = DriveFreeSpaceL();
        iFileName = KNullDesC;

        if ( currentdiskspace < ((TInt64)KDiskSafetyLimit+iCriticalDiskVal+CurrentMetadataSize()) )
            {
            PRINT((_L("CCamC3GPDataSinkImp::OpenFileL disk full, available: %d"), I64INT(currentdiskspace)));
            iDiskFull = ETrue;
            User::Leave(KErrDiskFull);
            }
        else
            {
            PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Compose and Open failed, error=%d"), error));
            iFileName = KNullDesC;
            User::Leave(KErrGeneral);
            }
        }
    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Compose and Open done")));

    mp4_u32 composeFlags = 0;
    if ( aFileFormat == E3GPP2 )
        {
        composeFlags |= ( MP4_FLAG_METADATALAST | MP4_FLAG_LONGCLIP | MP4_FLAG_GENERATE_3G2);
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Fileformat: 3G2")));
        }
    else if ( aFileFormat == EMPEG4 )
        {
        composeFlags |= ( MP4_FLAG_METADATALAST | MP4_FLAG_LONGCLIP | MP4_FLAG_GENERATE_MP4);
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Fileformat: MP4")));
        }
    else // E3GPP
        {
        composeFlags |= ( MP4_FLAG_METADATALAST | MP4_FLAG_LONGCLIP );
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Fileformat: 3GP")));
        }

    if ( ( iVideoMaxBitRate + iAudioAverageBitRate ) >= KLimitForLargeFileBuffers )
        {
        composeFlags |= MP4_FLAG_LARGEFILEBUFFER;
        }

    error = MP4ComposeSetFlags(iMP4Handle, composeFlags );
    if ( error == MP4_OUT_OF_MEMORY )
    	{
    	PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeSetFlags, error=%d"), error));
    	User::Leave(KErrNoMemory);
    	}
    else if (error != MP4_OK)
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeSetFlags, error=%d"), error));
        TInt64 currentdiskspace2 = DriveFreeSpaceL();

        if ( currentdiskspace2 < ((TInt64)KDiskSafetyLimit+iCriticalDiskVal+CurrentMetadataSize()) )
            {
            PRINT((_L("CCamC3GPDataSinkImp::OpenFileL disk full, available: %d"), I64INT(currentdiskspace2)));
            iDiskFull = ETrue;
            User::Leave(KErrDiskFull);
            }
        else
            {
            User::Leave(KErrGeneral);
            }
        }
    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Compose flags set")));

    if ((iFileCodecType & MP4_TYPE_H263_PROFILE_0) ||
        (iFileCodecType & MP4_TYPE_H263_PROFILE_3) ||
        (iFileCodecType & MP4_TYPE_MPEG4_VIDEO)    ||
        (iFileCodecType & MP4_TYPE_AVC_PROFILE_BASELINE) ||
        (iFileCodecType & MP4_TYPE_AVC_PROFILE_MAIN) ||
        (iFileCodecType & MP4_TYPE_AVC_PROFILE_HIGH))
        {
        // Set default values for video parameters if they are not set
        if (iVideoAverageBitRate < 0)
            {
            iVideoAverageBitRate = KVideoAverageBitRate;
            }
        if (iVideoMaxBitRate < 0)
            {
            iVideoMaxBitRate = KVideoMaxBitRate;
            }
        if (iVideoXResolution == 0)
            {
            iVideoXResolution = KVideoXResolution;
            }
        if (iVideoYResolution == 0)
            {
            iVideoYResolution = KVideoYResolution;
            }

        error = MP4ComposeAddVideoDescription(iMP4Handle,
                                              (mp4_u32)KVideoTimeScale,
                                              (mp4_u16)iVideoXResolution,
                                              (mp4_u16)iVideoYResolution,
                                              (mp4_u32)iVideoMaxBitRate,
                                              (mp4_u32)iVideoAverageBitRate);

        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeAddVideoDescription, error=%d"), error));
        if (error != MP4_OK)
            {
            User::Leave(KErrGeneral);
            }
        if ( (iFileCodecType & (MP4_TYPE_H263_PROFILE_0 | MP4_TYPE_H263_PROFILE_3))
            && ( videoLevel != 10) )
            {
            // H.263 level should be given to 3gp library like this
            error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle,
                                                            (mp4_u8*)&videoLevel,
                                                            (mp4_u32)1);
            if ( error != MP4_OK )
                {
                PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error));
                User::Leave(KErrGeneral);
                }
            }
        }

    if (iFileCodecType & MP4_TYPE_AMR_NB)
        {
        error = MP4ComposeAddAudioDescription(iMP4Handle,
                                              (mp4_u32)KAudioTimeScale,
                                              (mp4_u8)KAMRAudioFramesPerSample,
                                              (mp4_u16)KAudioModeSet);
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeAddAudioDescription, AMR-NB error=%d"), error));
        if (error != MP4_OK)
            {
            User::Leave(KErrGeneral);
            }
        }

    if ( iFileCodecType & MP4_TYPE_MPEG4_AUDIO)
        {
        // To make sure we always write proper timescale to output file (even in case when we get no audio
        // buffers) the default samplerate is passed to 3GP library here.
        // When we get audio decoder specific information in WriteBuffer() the MP4ComposeAddAudioDescription()
        // will be called again with correct samplerate.
        error = MP4ComposeAddAudioDescription(iMP4Handle,
                                              (mp4_u32)KAACDefaultSampleRate,
                                              (mp4_u8)KAACAudioFramesPerSample,
                                              (mp4_u16)KAudioModeSet);
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL MP4ComposeAddAudioDescription, AAC error=%d"), error));
        if (error != MP4_OK)
            {
            User::Leave(KErrGeneral);
            }
        }

    if ( iAvailableSpaceAtStart == 0 )
        {
        TVolumeInfo volumeinfo;
        User::LeaveIfError(iFS->Volume(volumeinfo, iDriveNumber));
        iAvailableSpaceAtStart = volumeinfo.iFree - (TInt64)(KDiskSafetyLimit+iCriticalDiskVal);
        }

    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Setting async file remover handler")));
    error = MP4ComposeSetTempFileRemoverObserver(&iMP4Handle, this);
    if (error != MP4_OK)
        {
        PRINT((_L("CCamC3GPDataSinkImp::OpenFileL Setting async file remover handler FAILED")));
        }

    PRINT((_L("CCamC3GPDataSinkImp::OpenFileL exit")));
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::SetSizeLimit
//
// Set size limit of the 3GP file to be recorded in bytes. The limit must be
// set before the recording starts.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::SetSizeLimit(TUint aSize)
    {
    PRINT((_L("CCamC3GPDataSinkImp::SetSizeLimit enter, requested limit: %u"), aSize));
    if (iBytesReceived)
        {
        PRINT(_L("CCamC3GPDataSinkImp::SetSizeLimit NOT set, recording"));
        return;
        }

    TInt64 rfileMaxSize = KCamC3GPMaximumFileSize; 
    if ( aSize == 0 || aSize > rfileMaxSize )
        {
        PRINT((_L("CCamC3GPDataSinkImp::SetSizeLimit 0 or over RFile max size, using internal max instead.")));
        iSizeLimit = rfileMaxSize; //max size for RFile
        }
    else
        {
        iSizeLimit = aSize;
        }
    PRINT((_L("CCamC3GPDataSinkImp::SetSizeLimit set to: high:%u low:%u"), I64HIGH(iSizeLimit), I64LOW(iSizeLimit)));
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::GetElapsedTime
//
// Return the amount of time recording has been on in microseconds.
// -----------------------------------------------------------------------------
//
TTimeIntervalMicroSeconds CCamC3GPDataSinkImp::GetElapsedTime()
    {
    PRINT(_L("CCamC3GPDataSinkImp::GetElapsedTime in"));
    TTimeIntervalMicroSeconds elapsed;
    if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0))
        {
        elapsed = 0;
        }
    else
        {
        elapsed = iVideoBufferTimestamp.Int64() - iFirstVideoFrameTimestamp.Int64();
        }
    PRINT((_L("CCamC3GPDataSinkImp::GetElapsedTime out, elapsed=%d"), I64INT(elapsed.Int64()) ));
    return elapsed;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::GetRemainingTime
//
// Return the estimated remaining time for the recording in microseconds.
// This method takes into account the file size and disk full restrictions.
// -----------------------------------------------------------------------------
//
TTimeIntervalMicroSeconds CCamC3GPDataSinkImp::GetRemainingTimeL()
    {
    TTimeIntervalMicroSeconds  elapsed;
    TTimeIntervalMicroSeconds  remaining;
    TTimeIntervalMicroSeconds  endtime;
    TInt64 availableSpace;
    TInt64 usedSpace;
    TInt64 metaDataSize;
    TBool remainingFromSizeLimit = EFalse;

    PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL in")));

    if ( iAvailableSpaceAtStart == 0 )
        {
        TVolumeInfo volumeinfo;
        User::LeaveIfError(iFS->Volume(volumeinfo, iDriveNumber));
        iAvailableSpaceAtStart = volumeinfo.iFree - (TInt64)(KDiskSafetyLimit+iCriticalDiskVal);
        }

    if (iSizeLimit && ( iSizeLimit < iAvailableSpaceAtStart ) )
        {
        // use sizelimit as available space.
        PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL Limiting remainingtime by sizelimit: %d."), I64INT(iSizeLimit)));
        remainingFromSizeLimit = ETrue;
        }
    else
        {
        PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL Limiting remainingtime by available space at start: %d "), I64INT(iAvailableSpaceAtStart) ));
        }

    if ( iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0) )
        {
        elapsed = 0;
        }
    else
        {
        elapsed = iVideoBufferTimestamp.Int64() - iFirstVideoFrameTimestamp.Int64();
        PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL elapsed with first=%d current=%d elapsed=%d"), I64INT(iFirstVideoFrameTimestamp.Int64()), I64INT(iVideoBufferTimestamp.Int64()), I64INT(elapsed.Int64()) ));
        }

    if (elapsed < (TTimeIntervalMicroSeconds)((TInt64)KDelayUseBitrates) )
        {
        // Use average audio/video bitrates to estimate remaining time
        TUint  averageBitRate;
        TUint  averageByteRate;

        PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: BitRates Video: %d , Audio: %d"), iVideoAverageBitRate, iAudioAverageBitRate ));

        averageBitRate = (TUint)((iVideoAverageBitRate + iAudioAverageBitRate) * KMetaDataCoeff);
        averageByteRate = averageBitRate / 8;

        PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: avaragebitrate: %d , avaragebyterate: %d"), averageBitRate, averageByteRate ));

        usedSpace = elapsed.Int64() * averageByteRate / 1000000; // 1000000 is for conversion between microseconds and seconds

        PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: elapsed: %d, usedspace: %d"), I64INT(elapsed.Int64()), usedSpace ));

        metaDataSize = 2*CurrentMetadataSize();
        if (remainingFromSizeLimit)
            {
            availableSpace = iSizeLimit - usedSpace - metaDataSize;
            }
        else
            {
            availableSpace = iAvailableSpaceAtStart - usedSpace - metaDataSize;
            }

        if (availableSpace <= 0 || averageByteRate == 0)
            {
            remaining = 0;
            }
        else
            {
            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: availablespace: %d, atStart: %d "), I64INT(elapsed.Int64()), I64INT(iAvailableSpaceAtStart) ));

            remaining = availableSpace * 1000000 / averageByteRate; // 1000000 is for conversion between microseconds and seconds

            if ( (remaining.Int64() + elapsed.Int64()) > (TInt64(KCamCMaxClipDurationInSecs)*1000000) )
                {
                remaining = (TInt64(KCamCMaxClipDurationInSecs)*1000000) - elapsed.Int64();
                }

            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL: remaining: %d "), I64INT(remaining.Int64()) ));
            }

        // update also iAvarageEndTime to smooth jump at KDelayUseBitrates sec point.
        iAvarageEndTime = elapsed.Int64()+ remaining.Int64();
        }
    else // use real filesize estimates.
        {
        // used space is mediadata + 2x metadata (metadata in temp-files written and additionaö reserved space for stop copying it to output file.
        usedSpace = CurrentFileSize()+ 2*CurrentMetadataSize();
        if (remainingFromSizeLimit)
            {
            availableSpace = iSizeLimit - usedSpace;
            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL availableSpace from sizelimit: %d "), I64INT(iAvailableSpaceAtStart) ));
            }
        else
            {
            availableSpace = iAvailableSpaceAtStart - usedSpace;
            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL availableSpace from availablespaceAtStart: %d "), I64INT(iAvailableSpaceAtStart) ));
            }

        if (availableSpace <= 0)
            {
            remaining = 0;
            }
        else
            {
            // preserve integer precision by scaling the first dividend up in calculation
            if (remainingFromSizeLimit)
                {
                // divide the greater of iSizeLimit and elapsed with usedSpace first to prevent overflow
                if ( iSizeLimit  > elapsed.Int64() )
                    {
                    PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iSizeLimit > elapsed: %d vs. %d"), I64INT(iSizeLimit), I64INT(elapsed.Int64()) ));
                    endtime = (((iSizeLimit * 1000) / usedSpace ) * elapsed.Int64() ) / 1000;
                    }
                else
                    {
                    PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iSizeLimit < elapsed: %d vs. %d"), I64INT(iSizeLimit), I64INT(elapsed.Int64()) ));
                    endtime = ( iSizeLimit  * ( (elapsed.Int64() * 1000) / usedSpace )) / 1000;
                    }
                }
            else
                {
                // divide the greater of iAvailableSpaceAtStart and elapsed with usedSpace first to prevent overflow
                if (iAvailableSpaceAtStart > elapsed.Int64() )
                    {
                    PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iAvailableSpaceAtStart > elapsed: %d vs. %d"), I64INT(iAvailableSpaceAtStart), I64INT(elapsed.Int64()) ));
                    endtime = (( (iAvailableSpaceAtStart * 1000) / usedSpace ) * elapsed.Int64() ) / 1000;
                    }
                else
                    {
                    PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL iAvailableSpaceAtStart < elapsed: %d vs. %d"), I64INT(iAvailableSpaceAtStart), I64INT(elapsed.Int64()) ));
                    endtime = ( iAvailableSpaceAtStart * ( (elapsed.Int64() * 1000) / usedSpace )) / 1000;
                    }
                }

            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL Endtime: %d"), I64INT(endtime.Int64()) ));
            if ( iAvarageEndTime.Int64() == -1 )
                {
                iAvarageEndTime = endtime;
                }
            else
                {
                iAvarageEndTime = (( iAvarageEndTime.Int64() * 7 ) + endtime.Int64() ) / 8;
                }

            if ( iAvarageEndTime.Int64() > (TInt64(KCamCMaxClipDurationInSecs)*1000000) )
                {
                iAvarageEndTime = (TInt64(KCamCMaxClipDurationInSecs)*1000000);
                }

            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL elapsed: %d , usedspace: %d"), I64INT(elapsed.Int64()), I64INT(usedSpace) ));
            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL available: %d, atStart: %d"), I64INT(availableSpace), iAvailableSpaceAtStart));
            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL AvgEndtime: %d"), I64INT(iAvarageEndTime.Int64()) ));
            remaining = iAvarageEndTime.Int64() - elapsed.Int64();
            PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL remaining: %d"), I64INT(remaining.Int64()) ));
            }
        }

    // Check if remaining time has reached 0 and we need to stop right away
    if ( remaining <= TInt64(0) )
        {
        if ( elapsed >= TInt64(0) ) // we are recording.
            {
            if ( remainingFromSizeLimit || (elapsed >= (TInt64(KCamCMaxClipDurationInSecs)*1000000)) )
                {
                // Size limit has been set and we reach wanted size -> remaining time is 0
                iFileSizeLimitReached = ETrue;
                iObserver->MfcoSizeLimitReachedL();
                }
            else
                {
                // Diskfull
                iDiskFull = ETrue;
                iObserver->MfcoDiskFullL();
                }
            }
        remaining = 0;
        }
    PRINT((_L("CCamC3GPDataSinkImp::GetRemainingTimeL out")));
    return remaining;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::SinkStopL
//
// Order the sink to finalize and close the current 3GP file.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::SinkStopL()
    {
    MP4Err  error;

    PRINT((_L("CCamC3GPDataSinkImp::SinkStopL enter")));

    if (!iMP4Handle)
        {
        return;
        }

    if (iVideoFrameDuration) // Write remaining video frame to disk
        {
        error = MP4ComposeWriteVideoFrame(iMP4Handle,
                                          (mp4_u8 *)iVideoBuffer,
                                          (mp4_u32)iVideoBufferFrameSize,
                                          (mp4_u32)iVideoFrameDuration,
                                          (mp4_bool)iVideoBufferRandomAccessPoint);
        if (error != MP4_OK)
            {
            PRINT((_L("CCamC3GPDataSinkImp::SinkStopL MP4ComposeWriteVideoFrame, error=%d"), error));
            User::Leave(KErrGeneral);
            }
        }


    PRINT((_L("CCamC3GPDataSinkImp::SinkStopL video frames written")));


    if (iAudioFramesInBuffer) // Write remaining audio frames to disk
        {
        error = MP4ComposeWriteAudioFrames(iMP4Handle,
                                           (mp4_u8 *)iAudioBuffer,
                                           (mp4_u32)iAudioBufferFrameSize,
                                           (mp4_u32)iAudioFramesInBuffer,
                                           (mp4_u32)iAudioFramesInBuffer * KAudioFrameDuration);
        if (error != MP4_OK)
            {
            PRINT((_L("CCamC3GPDataSinkImp::SinkStopL MP4ComposeWriteAudioFrames, error=%d"), error));
            User::Leave(KErrGeneral);
            }
        }

    PRINT((_L("CCamC3GPDataSinkImp::SinkStopL audio frames written")));


    error = MP4ComposeClose(iMP4Handle);
    iMP4Handle = NULL;
    if (error != MP4_OK)
        {
        PRINT((_L("CCamC3GPDataSinkImp::SinkStopL MP4ComposeClose, error=%d"), error));
        TInt64 currentdiskspace = DriveFreeSpaceL();

        if ( currentdiskspace < ((TInt64)KDiskSafetyLimit+iCriticalDiskVal+CurrentMetadataSize()) )
            {
            PRINT((_L("CCamC3GPDataSinkImp::SinkStopL disk full, available: %d"), I64INT(currentdiskspace)));
            iDiskFull = ETrue;
            User::Leave(KErrDiskFull);
            }
        else
            {
            User::Leave(KErrGeneral);
            }
        }

    PRINT((_L("CCamC3GPDataSinkImp::SinkStopL file composed and closed")));

    if ( iFileHandleExists )
        {
        iMMFFile->SinkStopL();
        iMMFFile = NULL; // not owned
        }
    else
        {
        if (!iBytesReceived)
            {
            PRINT((_L("CCamC3GPDataSinkImp::SinkStopL No data written, iTmpFileName left: '%s'"), iTmpFileName.Ptr()));
            }
        else
            {
            iFS->SetEntry(iTmpFileName, TTime(0), NULL, KEntryAttHidden);
            PRINT((_L("CCamC3GPDataSinkImp::SinkStopL Renaming temp file to: '%s'"), iFileName.Ptr()));
            User::LeaveIfError(iFS->Rename(iTmpFileName, iFileName));
            }
        }

    iFileName = KNullDesC;

    iBytesOfMetadata = 0;
    iBufferSize = 0;
    iFileCodecType = MP4_TYPE_NONE;
    iVideoTimestamp = 0;
    iVideoBufferTimestamp = -1;
    iVideoRandomAccessPoint = EFalse;
    iVideoBufferRandomAccessPoint = EFalse;
    iVideoFrameDuration = 0;
    iVideoBufferFrameSize = 0;
    iVideoDecSpecInfoSize = 0;
    iAudioDecSpecInfoSize = 0;
    iAudioBufferFrameSize = 0;
    iAudioFrameNumber = 0;
    iAudioFramesInBuffer = 0;
    iFileSizeLimitReached = EFalse;
    iDiskFull = EFalse;
    iFreeDiskSpace = 0;
    iFreeDiskSpaceCounter = 0;
    iAudioAACFrameDuration = 0;
    iAudioAACSamplerate = 0;

    PRINT((_L("CCamC3GPDataSinkImp::SinkStopL() updating available diskspace - in")));
    TVolumeInfo volumeinfo;
    if ( iFS && iFS->Volume(volumeinfo, iDriveNumber) == KErrNone )
        {
        iAvailableSpaceAtStart = volumeinfo.iFree - (TInt64)(KDiskSafetyLimit+iCriticalDiskVal);
        PRINT((_L("CCamC3GPDataSinkImp::SinkStopL() updating available diskspace - done")));
        }

    PRINT((_L("CCamC3GPDataSinkImp::SinkStopL exit")));
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::WriteBuffer
//
// Write an audio/video buffer to the sink. The sink copies the given buffer
// and writes it to the file.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::WriteBufferL(CCMRMediaBuffer* aBuffer)
    {
    PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL enter")));
    TInt64  videoduration = 0;
    TUint8* tmpaudiobuffer = 0;
    TInt64 currentfilesize;
    MP4Err  error = MP4_OK;


    if (!iMP4Handle)
        {
        PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL No MP4Handle, returning.")));
        return;
        }

    if (iFileSizeLimitReached || iDiskFull)
        {
        PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL sizelimit reached or disk full returning")));
        return;
        }

    iBufferType = aBuffer->Type();
    iBufferSize = aBuffer->BufferSize();

    TTimeIntervalMicroSeconds elapsed;
    if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0))
        {
        elapsed = 0;
        }
    else
        {
        elapsed = iVideoBufferTimestamp.Int64() - iFirstVideoFrameTimestamp.Int64();
        }

    currentfilesize = CurrentFileSize() + CurrentMetadataSize();
    if ( ( iSizeLimit && ((currentfilesize + (TUint)iBufferSize) > iSizeLimit) ) ||
         (elapsed.Int64() >= (TInt64(KCamCMaxClipDurationInSecs)*1000000)) )
        {
        PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL sizelimit reached, filesize: %d"), I64INT(currentfilesize)));
        PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL sizelimit is set to: high:%u low:%u"), I64HIGH(iSizeLimit), I64LOW(iSizeLimit)));
        PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL elapsed time: high:%u low:%u"), I64HIGH(elapsed.Int64()), I64LOW(elapsed.Int64())));        
        iFileSizeLimitReached = ETrue;
        iObserver->MfcoSizeLimitReachedL();
        return;
        }

    PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL, filesize: %d, bufsize: %d")
            , I64INT(currentfilesize), iBufferSize));

    currentfilesize += CurrentMetadataSize(); // extra reserve for stop (copy metadata from temp files to end of output file.
    if ( currentfilesize >= iAvailableSpaceAtStart )
        {
        PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL disk full, calc size: %d"), I64INT(currentfilesize)));
        iDiskFull = ETrue;
        iObserver->MfcoDiskFullL();
        return;
        }

    PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL, available: %d")
            , I64INT(iAvailableSpaceAtStart-currentfilesize)));

    iBytesReceived += (TUint)iBufferSize;
    switch (iBufferType)
        {
        case CCMRMediaBuffer::EAudioAMRNB:
            {
            iAudioFrameNumber++;

            if ( ( (TUint)iBufferSize + iAudioBufferFrameSize ) > iAudioBufferSize) // Incoming buffer doesn't fit into allocated buffer
                {
                tmpaudiobuffer = new (ELeave) TUint8[(TUint)iBufferSize + iAudioBufferFrameSize];
                Mem::Copy(tmpaudiobuffer, iAudioBuffer, (TInt)iAudioBufferFrameSize);
                delete [] iAudioBuffer;
                iAudioBuffer = tmpaudiobuffer;
                iAudioBufferSize = (TUint)iBufferSize + iAudioBufferFrameSize;
                }

            Mem::Copy(iAudioBuffer + iAudioBufferFrameSize, aBuffer->Data().Ptr(), iBufferSize);
            iAudioBufferFrameSize += (TUint)iBufferSize;
            iAudioFramesInBuffer++;

            if (iAudioFramesInBuffer == KAMRAudioFramesPerSample) // Buffer several audio frames before writing to disk
                {
                error = MP4ComposeWriteAudioFrames(iMP4Handle,
                                                   (mp4_u8 *)iAudioBuffer,
                                                   (mp4_u32)iAudioBufferFrameSize,
                                                   (mp4_u32)iAudioFramesInBuffer,
                                                   (mp4_u32)iAudioFramesInBuffer * KAudioFrameDuration);
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL AMR-NB MP4ComposeWriteAudioFrames, error=%d"), error));
                if (error != MP4_OK)
                    {
                    User::Leave(KErrGeneral);
                    }

                iAudioFramesInBuffer = 0;
                iAudioBufferFrameSize = 0;
                }

            break;
            }
        case CCMRMediaBuffer::EAudioMPEG4AAC:
            {
            if ( !iAudioAACFrameDuration )
                {
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL AAC Audio frameduration not set! Error= -18"), error));
                User::Leave ( KErrNotReady );
                }

            iAudioFrameNumber++;
            error = MP4ComposeWriteAudioFrames(iMP4Handle,
                                               (mp4_u8 *)aBuffer->Data().Ptr(),
                                               (mp4_u32)aBuffer->BufferSize(),
                                               (mp4_u32)KAACAudioFramesPerSample,
                                               (mp4_u32)KAACAudioFramesPerSample * iAudioAACFrameDuration);
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL AAC MP4ComposeWriteAudioFrames, error=%d"), error));
            if (error != MP4_OK)
                {
                User::Leave(KErrGeneral);
                }
            break;
            }
        case CCMRMediaBuffer::EAudioAMRWB:
            {
            break;
            }
        case CCMRMediaBuffer::EVideoH263:
        case CCMRMediaBuffer::EVideoMPEG4:
            {
            iVideoTimestamp = aBuffer->TimeStamp();
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH263/EVideoMPEG4 Timestamp of the buffer is %d"), I64INT(iVideoTimestamp.Int64())));
            iVideoRandomAccessPoint = aBuffer->RandomAccessPoint();
            iVideoFrameNumber++;
            if (iVideoRandomAccessPoint)
                {
                iVideoIntraFrameNumber++;
                }

            if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) // First frame
                {
                iFirstVideoFrameTimestamp = iVideoTimestamp;
                iVideoBufferTimestamp = iVideoTimestamp;
                iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint;

                if ((TUint)iBufferSize > iVideoBufferSize)
                    {
                    delete [] iVideoBuffer;
                    iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize];
                    iVideoBufferSize = (TUint)iBufferSize;
                    }

                Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize);
                iVideoBufferFrameSize = (TUint)iBufferSize;

                break;
                }

            videoduration = iVideoTimestamp.Int64() - iVideoBufferTimestamp.Int64(); // Duration in microseconds
            videoduration = TInt64((videoduration * KVideoTimeScale) / 1E6 + 0.5); // Duration scaled to KVideoTimeScale
            iVideoFrameDuration = (TUint)I64INT(videoduration);

            error = MP4ComposeWriteVideoFrame(iMP4Handle,
                                              (mp4_u8 *)iVideoBuffer,
                                              (mp4_u32)iVideoBufferFrameSize,
                                              (mp4_u32)iVideoFrameDuration,
                                              (mp4_bool)iVideoBufferRandomAccessPoint);
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoFrame, error=%d"), error));
            if (error != MP4_OK)
                {
                User::Leave(KErrGeneral);
                }

            if ((TUint)iBufferSize > iVideoBufferSize)
                {
                delete [] iVideoBuffer;
                iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize];
                iVideoBufferSize = (TUint)iBufferSize;
                }

            Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize);
            iVideoBufferFrameSize = (TUint)iBufferSize;
            iVideoBufferTimestamp = iVideoTimestamp;
            iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint;

            break;
            }
        case CCMRMediaBuffer::EVideoMPEG4DecSpecInfo:
            {
            iVideoDecSpecInfoSize = iBufferSize;

            error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle,
                                                            (mp4_u8 *)aBuffer->Data().Ptr(),
                                                            (mp4_u32)iBufferSize);
            if (error != MP4_OK)
                {
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error));
                User::Leave(KErrGeneral);
                }

            break;
            }
        case CCMRMediaBuffer::EVideoH264NAL:
            {
            iVideoTimestamp = aBuffer->TimeStamp();
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264NAL Timestamp of the buffer is %d"), I64INT(iVideoTimestamp.Int64())));
            iVideoRandomAccessPoint = aBuffer->RandomAccessPoint();
            iVideoFrameNumber++;
            if (iVideoRandomAccessPoint)
                {
                iVideoIntraFrameNumber++;
                }

            if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) // First frame
                {
                iFirstVideoFrameTimestamp = iVideoTimestamp;
                iVideoBufferTimestamp = iVideoTimestamp;
                iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint;

                if ((TUint)(iBufferSize) > iVideoBufferSize)
                    {
                    delete [] iVideoBuffer;
                    iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize];
                    iVideoBufferSize = (TUint)iBufferSize;
                    }

                ConvertNALEncapsulationToNALSizes( aBuffer );
                break;
                }

            videoduration = iVideoTimestamp.Int64() - iVideoBufferTimestamp.Int64(); // Duration in microseconds
            videoduration = TInt64((videoduration * KVideoTimeScale) / 1E6 + 0.5); // Duration scaled to KVideoTimeScale
            iVideoFrameDuration = (TUint)I64INT(videoduration);

            error = MP4ComposeWriteVideoFrame(iMP4Handle,
                                              (mp4_u8 *)iVideoBuffer,
                                              (mp4_u32)iVideoBufferFrameSize,
                                              (mp4_u32)iVideoFrameDuration,
                                              (mp4_bool)iVideoBufferRandomAccessPoint);
            if (error != MP4_OK)
                {
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoFrame, error=%d"), error));
                User::Leave(KErrGeneral);
                }

            if ((TUint)(iBufferSize) > iVideoBufferSize)
                {
                delete [] iVideoBuffer;
                iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize];
                iVideoBufferSize = (TUint)iBufferSize;
                }

            ConvertNALEncapsulationToNALSizes( aBuffer );

            iVideoBufferTimestamp = iVideoTimestamp;
            iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint;
            break;
            }
        case CCMRMediaBuffer::EVideoH264Bytestream:
            {
            // need to add NAL header to end on bytestream buffer
            iVideoTimestamp = aBuffer->TimeStamp();
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264Bytestream Timestamp of the buffer is %d"), I64INT(iVideoTimestamp.Int64())));
            iVideoRandomAccessPoint = aBuffer->RandomAccessPoint();
            iVideoFrameNumber++;
            if (iVideoRandomAccessPoint)
                {
                iVideoIntraFrameNumber++;
                }

            if (iVideoBufferTimestamp < TTimeIntervalMicroSeconds(0)) // First frame
                {
                iFirstVideoFrameTimestamp = iVideoTimestamp;
                iVideoBufferTimestamp = iVideoTimestamp;
                iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint;

                if ((TUint)(iBufferSize) > iVideoBufferSize)
                    {
                    delete [] iVideoBuffer;
                    iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize];
                    iVideoBufferSize = (TUint)iBufferSize;
                    }

                ConvertBytestreamHeadersToNALSizes(aBuffer);
                Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize);
                iVideoBufferFrameSize = iBufferSize;
                break;
                }

            videoduration = iVideoTimestamp.Int64() - iVideoBufferTimestamp.Int64(); // Duration in microseconds
            videoduration = TInt64((videoduration * KVideoTimeScale) / 1E6 + 0.5); // Duration scaled to KVideoTimeScale
            iVideoFrameDuration = (TUint)I64INT(videoduration);

            error = MP4ComposeWriteVideoFrame(iMP4Handle,
                                              (mp4_u8 *)iVideoBuffer,
                                              (mp4_u32)iVideoBufferFrameSize,
                                              (mp4_u32)iVideoFrameDuration,
                                              (mp4_bool)iVideoBufferRandomAccessPoint);
            if (error != MP4_OK)
                {
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoFrame, error=%d"), error));
                User::Leave(KErrGeneral);
                }

            if ((TUint)(iBufferSize) > iVideoBufferSize)
                {
                delete [] iVideoBuffer;
                iVideoBuffer = new (ELeave) TUint8[(TUint)iBufferSize];
                iVideoBufferSize = (TUint)iBufferSize;
                }

            ConvertBytestreamHeadersToNALSizes(aBuffer);
            Mem::Copy(iVideoBuffer, aBuffer->Data().Ptr(), iBufferSize);

            iVideoBufferFrameSize = (TUint)iBufferSize;
            iVideoBufferTimestamp = iVideoTimestamp;
            iVideoBufferRandomAccessPoint = iVideoRandomAccessPoint;
            break;
            }
        case CCMRMediaBuffer::EVideoH264NALDecSpecInfo:
            {
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264NALDecSpecInfo")));            
            HBufC8* outputAVCHeader = 0;
            outputAVCHeader = (HBufC8*) HBufC8::NewLC(16384);
            TPtr8 destptr = outputAVCHeader->Des();

	        // parse header & convert it to AVCDecoderConfigurationRecord -format
	        ConvertAVCHeaderNALL(aBuffer, destptr);
            iVideoDecSpecInfoSize = destptr.Length();

            error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle,
                                                            (mp4_u8 *)destptr.Ptr(),
                                                            (mp4_u32)iVideoDecSpecInfoSize);

			CleanupStack::PopAndDestroy( outputAVCHeader );
            if (error != MP4_OK)
                {
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error));
                User::Leave(KErrGeneral);
                }
            break;
            }
        case CCMRMediaBuffer::EVideoH264BytestreamDecSpecInfo:
            {
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL EVideoH264BytestreamDecSpecInfo")));            
            HBufC8* outputAVCHeader = 0;
            outputAVCHeader = (HBufC8*) HBufC8::NewLC(16384);
            TPtr8 destptr = outputAVCHeader->Des();

	        // parse header & convert it to AVCDecoderConfigurationRecord -format
	        ConvertAVCHeaderByteStreamL(aBuffer, destptr);
            iVideoDecSpecInfoSize = destptr.Length();

            error = MP4ComposeWriteVideoDecoderSpecificInfo(iMP4Handle,
                                                            (mp4_u8 *)destptr.Ptr(),
                                                            (mp4_u32)iVideoDecSpecInfoSize);

			CleanupStack::PopAndDestroy( outputAVCHeader );
            if (error != MP4_OK)
                {
                PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteVideoDecoderSpecificInfo, error=%d"), error));
                User::Leave(KErrGeneral);
                }
            break;
            }
        case CCMRMediaBuffer::EAudioDecSpecInfo:
            {
			PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo in"), error));
            iAudioDecSpecInfoSize = iBufferSize;

            error = MP4ComposeWriteAudioDecoderSpecificInfo(iMP4Handle,
                                                            (mp4_u8 *)aBuffer->Data().Ptr(),
                                                            (mp4_u32)iBufferSize);
            PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo, error=%d"), error));
            if (error != MP4_OK)
                {
                User::Leave(KErrGeneral);
                }

			PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo - flags: iFileCodecType=%d Frameduration=%d"), iFileCodecType, iAudioAACFrameDuration));
            if ( (iFileCodecType & MP4_TYPE_MPEG4_AUDIO) && !iAudioAACFrameDuration )
                {
				PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo determining new AAC samplerate."), error));
                DetermineAACFrameDurationL( aBuffer );
                // done here because timescale is dependent of samplerate.
                error = MP4ComposeAddAudioDescription(iMP4Handle,
                                                     (mp4_u32)iAudioAACSamplerate,
                                                     (mp4_u8)KAACAudioFramesPerSample,
                                                     (mp4_u16)KAudioModeSet);
                if (error != MP4_OK)
                    {
                    PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeAddAudioDescription, error=%d"), error));
                    User::Leave(KErrGeneral);
                    }
                }
			PRINT((_L("CCamC3GPDataSinkImp::WriteBufferL MP4ComposeWriteAudioDecoderSpecificInfo out"), error));
            break;
            }
        default:
            {
            break;
            }
        }
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::SetVideoFrameSize
//
// Give video frame size to sink.
// -----------------------------------------------------------------------------
//
TInt CCamC3GPDataSinkImp::SetVideoFrameSize(TSize aSize)
    {
    if (aSize.iWidth < 0)
        {
        return KErrArgument;
        }
    if (aSize.iHeight < 0)
        {
        return KErrArgument;
        }

    if (iBytesReceived)
        {
        return KErrNotReady;
        }

    iVideoXResolution = aSize.iWidth;
    iVideoYResolution = aSize.iHeight;
    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::SetAverageVideoBitRate
//
// Give average video bitrate to sink.
// -----------------------------------------------------------------------------
//
TInt CCamC3GPDataSinkImp::SetAverageVideoBitRate(TInt aBitRate)
    {
    if (aBitRate < 0)
        {
        return KErrArgument;
        }

    iVideoAverageBitRate = aBitRate;
    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::SetMaxVideoBitRate
//
// Give maximum video bitrate to sink.
// -----------------------------------------------------------------------------
//
TInt CCamC3GPDataSinkImp::SetMaxVideoBitRate(TInt aBitRate)
    {
    if (aBitRate < 0)
        {
        return KErrArgument;
        }

    iVideoMaxBitRate = aBitRate;
    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::SetAverageAudioBitRate
//
// Give average audio bitrate to sink.
// -----------------------------------------------------------------------------
//
TInt CCamC3GPDataSinkImp::SetAverageAudioBitRate(TInt aBitRate)
    {
    if (aBitRate < 0)
        {
        return KErrArgument;
        }

    iAudioAverageBitRate = aBitRate;
    return KErrNone;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::CurrentFileSize
//
// Estimate current output file size.
// Total file size = metadata size + media data size
// -----------------------------------------------------------------------------
//
TUint CCamC3GPDataSinkImp::CurrentFileSize() const
    {
    TUint filesize = 0;

    // Media data
    filesize += 8; // mdat box type and size
    filesize += iBytesReceived; // Data received from media recorder

    return filesize;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::CurrentMetadataSize
//
// Calculates current metadata size.
// -----------------------------------------------------------------------------
//
TUint CCamC3GPDataSinkImp::CurrentMetadataSize() const
    {
    TBool haveAudio;
    TBool haveVideo;
    TUint metadatasize = 0;

    haveAudio = EFalse;
    haveVideo = EFalse;


    // Metadata

    metadatasize += KFTYPSize; // FTYP

    if ((iFileCodecType & MP4_TYPE_H263_PROFILE_0) ||
        (iFileCodecType & MP4_TYPE_H263_PROFILE_3)) // H.263
        {
        haveVideo = ETrue;
        metadatasize += 574; // Constant size H.263 metadata
        metadatasize += (iVideoFrameNumber * 16 + iVideoIntraFrameNumber * 4); // Content dependent H.263 metadata
        }

    if (iFileCodecType & MP4_TYPE_MPEG4_VIDEO) // MPEG-4 video
        {
        haveVideo = ETrue;
        metadatasize += 596; // Constant size MPEG-4 video metadata
        metadatasize += (iVideoFrameNumber * 16 + iVideoIntraFrameNumber * 4 + (TUint)iVideoDecSpecInfoSize); // Content dependent MPEG-4 video metadata
        }

    if ( iFileCodecType & MP4_TYPE_AMR_NB ) // AMR-NB
        {
        haveAudio = ETrue;
        metadatasize += 514; // Constant size AMR metadata
        metadatasize += ((iAudioFrameNumber + KAMRAudioFramesPerSample - 1) / KAMRAudioFramesPerSample) * 16;
        }

    if ( iFileCodecType & MP4_TYPE_MPEG4_AUDIO ) // MPEG-4 AAC-LC
        {
        haveAudio = ETrue;
        metadatasize += 514; // Constant size metadata
        metadatasize += (iAudioFrameNumber * 16) + (TUint)iAudioDecSpecInfoSize;
        }

    if (haveAudio && haveVideo)
        metadatasize -= 116; // There is only one moov and mvhd in a file

    return metadatasize;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::DriveFreeSpaceL
//
// Calculate free space on a drive in bytes.
// -----------------------------------------------------------------------------
//
TInt64 CCamC3GPDataSinkImp::DriveFreeSpaceL()
    {
    TVolumeInfo volumeinfo;

    if (iFreeDiskSpaceCounter % KFreeDiskSpaceCounter == 0)
        {
        PRINT((_L("CCamC3GPDataSinkImp::DriveFreeSpaceL Asking Disk Free space")));
        User::LeaveIfError(iFS->Volume(volumeinfo, iDriveNumber));
        iFreeDiskSpace = volumeinfo.iFree;
        PRINT((_L("CCamC3GPDataSinkImp::DriveFreeSpaceL Received Disk Free space info")));
        }

    iFreeDiskSpaceCounter++;
    return iFreeDiskSpace;
    }


// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::DetermineAACFrameDuration
//
// Determines AAC audio frame duration.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::DetermineAACFrameDurationL( CCMRMediaBuffer* aBuffer )
    {
    TInt sampleRate = 0;
    TUint8 sampleRateIndex = *aBuffer->Data().Mid(0).Ptr();
    sampleRateIndex <<= 5;
    sampleRateIndex >>= 4;
    sampleRateIndex |= ((TUint8)*aBuffer->Data().Mid(1).Ptr())>>7;

    switch ( sampleRateIndex )
        {
        case 0x3:
            {
            PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 48000")));
            sampleRate = 48000;
            break;
            }
        case 0x5:
            {
			PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 32000")));
            sampleRate = 32000;
            break;
            }
        case 0x6:
            {
            PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 24000")));
            sampleRate = 24000;
            break;
            }
        case 0x8:
            {
            PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 16000")));
            sampleRate = 16000;
            break;
            }
        case 0xb:
            {
            PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset to 8000")));
            sampleRate = 8000;
            break;
            }
        default:
            {
            PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL unsupported AAC Samplerate - leaving -6")));
            User::Leave( KErrArgument );
            break;
            }
        }

    PRINT((_L("CCamC3GPDataSinkImp::DetermineAACFrameDurationL AAC Samplerate reset from %d to %d"), iAudioAACSamplerate, sampleRate));
    iAudioAACSamplerate = sampleRate;
    // formula to calculate frameduration from samplerate is: frameduration = (1024/samplerate)*1000
    // and in movie timescale: frameDurationInMovieTimescale = frameduration*samplerate/1000
    // thus with equal samplerate = timescale frameDurationInMovieTimescale for AAC is always 1024
    iAudioAACFrameDuration = 1024;
}

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::ConvertAVCHeaderL
//
// Convert AVC specific decoder config info to
// AVC Decoder Configuration Record -format
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::ConvertAVCHeaderNALL( CCMRMediaBuffer* aBuffer, TDes8& aDstBuf )
    {
    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL in Buffer length: %d"), aBuffer->Data().Length() ));    
	TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr());
    TUint8* outputPtr = (TUint8*)(aDstBuf.Ptr());
    TUint8* spsPtr;
    TUint8* ppsPtr;

    TUint numSPS = 0;
    TUint numPPS = 0;

    TUint totalSPSLength = 0;
    TUint totalPPSLength = 0;

    TUint headerLength = aBuffer->Data().Length();
    TUint endIndex = headerLength;

   	TInt nalType = 0;
   	TUint nalLength;
   	TUint nalIndex;
    TUint nalOffset;

   	// Allocate memory for the temporary buffers
   	HBufC8* temp1 = (HBufC8*) HBufC8::NewLC(1000);
   	HBufC8* temp2 = (HBufC8*) HBufC8::NewLC(5000);

    spsPtr = const_cast<TUint8*>( temp1->Des().Ptr() );
    ppsPtr = const_cast<TUint8*>( temp2->Des().Ptr() );

    TUint numNalUnits = inputPtr[endIndex-4] + (inputPtr[endIndex-3]<<8) + (inputPtr[endIndex-2]<<16) + (inputPtr[endIndex-1]<<24);
    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit count: %d"), numNalUnits));    
    
	// Move endIndex to point to the first NAL unit's offset information
    endIndex = headerLength - numNalUnits*8 - 4;
	nalIndex = 0;

	while (nalIndex < numNalUnits)
        {
    	nalIndex++;

    	TInt tmp1 = inputPtr[endIndex++];
        TInt tmp2 = inputPtr[endIndex++]<<8;
        TInt tmp3 = inputPtr[endIndex++]<<16;
        TInt tmp4 = inputPtr[endIndex++]<<24;

    	nalOffset = tmp1 + tmp2 + tmp3 + tmp4;
        PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit start offset: %d"), nalOffset));    	

    	tmp1 = inputPtr[endIndex++];
        tmp2 = inputPtr[endIndex++]<<8;
        tmp3 = inputPtr[endIndex++]<<16;
        tmp4 = inputPtr[endIndex++]<<24;

    	nalLength = tmp1 + tmp2 + tmp3 + tmp4;
        PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit length: %d"), nalLength));    	

	   	nalType = inputPtr[nalOffset] & 0x1F;
        PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL Nal Unit type: %d"), nalType));
        
	   	if(nalType == 7)
		    {
	   		numSPS++;

		    // First store the SPS unit length with two bytes
   			spsPtr[totalSPSLength] = (nalLength >> 8) & 0xFF;
    		spsPtr[totalSPSLength+1] = nalLength & 0xFF;

			// Copy the SPS unit to the buffer
			Mem::Copy(&spsPtr[totalSPSLength+2], inputPtr+nalOffset , nalLength);
	        PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL stored SPS from offset: %d size: %d"), inputPtr+nalOffset, nalLength));			
			totalSPSLength += nalLength + 2;	// Two more for the size
		    }
  		else if(nalType == 8)
   		    {
			numPPS++;

		    // First store the SPS unit length with two bytes
   			ppsPtr[totalPPSLength] = (nalLength >> 8) & 0xFF;
    		ppsPtr[totalPPSLength+1] = nalLength & 0xFF;

			// Copy the SPS unit to the buffer
			Mem::Copy(&ppsPtr[totalPPSLength+2], inputPtr+nalOffset , nalLength);
            PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderNALL stored PPS from offset: %d size: %d"), inputPtr+nalOffset, nalLength));			
			totalPPSLength += nalLength + 2;	// Two more for the size
	   	    }
		else
   		    {
   		    }
        }

	// When the header has been parsed, form the AVC Decoder Configuration Record
	outputPtr[0] = 0x01;	// configurationVersion
	// AVCProfileIndication contains the profile code as defined in the AVC specification
    if (iFileCodecType & MP4_TYPE_AVC_PROFILE_BASELINE)
        {
        outputPtr[1] = 0x42;
        outputPtr[2] = 0x80;    // Bitstream obeys all Baseline profile constraints.
        // Profile compatibility, i.e. all 4 constrain set flags + reserved 4 zero bits
        if ( iAVCOutputLevel == 101 )
            {
            outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero
            }
        // AVCLevelIndication contains the level code as defined in the AVC specification
        outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel;
        }
    else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_MAIN)
        {
        outputPtr[1] = 0x4D;
        outputPtr[2] = 0x40;    // Bitstream obeys all main profile constraints.
        if ( iAVCOutputLevel == 101 )
            {
            outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero
            }
        // AVCLevelIndication contains the level code as defined in the AVC specification
        outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel;
        }
    else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_HIGH)
        {
        outputPtr[1] = 0x64;
        outputPtr[2] = 0x40;    // Bitstream obeys all Baseline profile constraints.
        outputPtr[3] = (iAVCOutputLevel == 101) ? 0x09 : iAVCOutputLevel;
        }
    else
        {
        User::Leave(KErrNotSupported);
        }

	// lengthSizeMinusOne indicates the length in bytes of the NALUnitLength field minus one.
	outputPtr[4] = 0x03; // 4 bytes
	outputPtr[4] |= 0x0FC; // 6 reserved bits (all 1)
	// numOfSequenceParameterSets indicates the number of sequence parameter sets
	outputPtr[5] = numSPS;
	outputPtr[5] |= 0xE0;  // 3 reserved bits (all 1)

	TInt len = 6;
	// Copy the SPS unit(s) to the buffer
	Mem::Copy(&outputPtr[6], spsPtr , totalSPSLength);
	len += totalSPSLength;
	outputPtr[6+totalSPSLength] = numPPS;
	len += 1;

	// Copy the PPS unit(s) to the buffer
	Mem::Copy(&outputPtr[6+totalSPSLength+1], ppsPtr , totalPPSLength);
	len += totalPPSLength;
	aDstBuf.SetLength(len);

	CleanupStack::PopAndDestroy(temp2);
	CleanupStack::PopAndDestroy(temp1);
}

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL
//
// Convert AVC specific decoder config info  from Bytestream (ElementaryStream) encapsulation to
// AVC Decoder Configuration Record -format
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL( CCMRMediaBuffer* aBuffer, TDes8& aDstBuf )
    {
    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL in")));
	TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr());
    TUint8* outputPtr = (TUint8*)(aDstBuf.Ptr());
    TUint8* spsPtr;
    TUint8* ppsPtr;

    TUint numSPS = 0;
    TUint numPPS = 0;

    TUint totalSPSLength = 0;
    TUint totalPPSLength = 0;

    TUint headerLength = aBuffer->Data().Length();
    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL buffer length: %d"), headerLength));

   	TInt nalType = 0;

   	// Allocate memory for the temporary buffers
   	HBufC8* temp1 = (HBufC8*) HBufC8::NewLC(1000);
   	HBufC8* temp2 = (HBufC8*) HBufC8::NewLC(5000);

    spsPtr = const_cast<TUint8*>( temp1->Des().Ptr() );
    ppsPtr = const_cast<TUint8*>( temp2->Des().Ptr() );

    // scan from beginning of buffer to end for SPS and PSP
    TInt i = 0;
    TInt j = 0;
    for (i=0; i<headerLength; i++)
    	{
    	if ( inputPtr[i] == 0 &&
    		 inputPtr[i+1] == 0 &&
    		 inputPtr[i+2] == 0 &&
    		 inputPtr[i+3] == 1 )
    		{ // found bytestream header [00 00 00 01]
    	    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL found header at: %d"), i));
    	   	nalType = inputPtr[i+4] & 0x1F;
            PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL NAL type: %d"), nalType));
    	   	if(nalType == 7) // SPS
    	   		{
    	   		numSPS++;
    	   		// find length of SPS
    	   		TInt j;
    	   		for (j=4; i+j+3<headerLength; j++)
    	   			{
    	   	    	if ( inputPtr[i+j] == 0 &&
    	   	    		 inputPtr[i+j+1] == 0 &&
    	   	    		 inputPtr[i+j+2] == 0 &&
    	   	    		 inputPtr[i+j+3] == 1 )
    	   	    		{
    	   	    		totalSPSLength = j-i-4;
    	   	            PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL SPS length: %d, count: %d"), totalSPSLength, numSPS));
    	   	    		break;
    	   	    		}
    	   			}
    	   		// if we didn't find next bytestream header then this is last buffer
    	   		if ( totalSPSLength == 0 )
    	   			{
    	   			totalSPSLength = headerLength - i - 4;
                    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL SPS length: %d (last), count: %d"), totalSPSLength, numSPS));
    	   			}

    		    // First store the SPS unit length with two bytes
       			spsPtr[0] = (totalSPSLength >> 8) & 0xFF;
        		spsPtr[1] = totalSPSLength & 0xFF;

        		// Copy the SPS unit to the buffer
    			Mem::Copy(&spsPtr[2], &inputPtr[i+4] , totalSPSLength);
    			totalSPSLength +=2;
    	   		}
    	   	else if ( nalType == 8 ) // PPS)
    	   		{
    	   		numPPS++;
    	   		// find length of PPS
    	   		for (j=4; i+j+3<headerLength; j++)
    	   			{
    	   	    	if ( inputPtr[i+j] == 0 &&
    	   	    		 inputPtr[i+j+1] == 0 &&
    	   	    		 inputPtr[i+j+2] == 0 &&
    	   	    		 inputPtr[i+j+3] == 1 )
    	   	    		{
    	   	    		totalPPSLength = j-i-4;
                        PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL PPS length: %d, count: %d"), totalPPSLength, numPPS));
    	   	    		break;
    	   	    		}
    	   			}
    	   		// if we didn't find next bytestream header then this is last buffer
    	   		if ( totalPPSLength == 0 )
    	   			{
    	   			totalPPSLength = headerLength - i - 4;
                    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL PPS length: %d (last), count: %d"), totalPPSLength, numPPS));
    	   			}

    		    // First store the SPS unit length with two bytes
    	   		ppsPtr[0] = (totalPPSLength >> 8) & 0xFF;
    	   		ppsPtr[1] = totalPPSLength & 0xFF;

    			// Copy the SPS unit to the buffer
    			Mem::Copy(&ppsPtr[2], &inputPtr[i+4], totalPPSLength);
    	   		totalPPSLength +=2;
    	   		}
    		}
    	}

	// When the header has been parsed, form the AVC Decoder Configuration Record
	outputPtr[0] = 0x01;	// configurationVersion
    // AVCProfileIndication contains the profile code as defined in the AVC specification
    if (iFileCodecType & MP4_TYPE_AVC_PROFILE_BASELINE)
        {
        outputPtr[1] = 0x42;
        outputPtr[2] = 0x80;    // Bitstream obeys all Baseline profile constraints.
        // Profile compatibility, i.e. all 4 constrain set flags + reserved 4 zero bits
        if ( iAVCOutputLevel == 101 )
            {
            outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero
            }
        // AVCLevelIndication contains the level code as defined in the AVC specification
        outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel;
        }
    else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_MAIN)
        {
        outputPtr[1] = 0x4D;
        outputPtr[2] = 0x40;    // Bitstream obeys all main profile constraints.
        if ( iAVCOutputLevel == 101 )
            {
            outputPtr[2] |= 0x10; // For level 1b, the 4th bit shall be == 1, otherwise it must be zero
            }
        // AVCLevelIndication contains the level code as defined in the AVC specification
        outputPtr[3] = (iAVCOutputLevel == 101) ? 0x0B : iAVCOutputLevel;
        }
    else if (iFileCodecType & MP4_TYPE_AVC_PROFILE_HIGH)
        {
        outputPtr[1] = 0x64;
        outputPtr[2] = 0x40;    // Bitstream obeys all Baseline profile constraints.
        outputPtr[3] = (iAVCOutputLevel == 101) ? 0x09 : iAVCOutputLevel;
        }
    else
        {
        User::Leave(KErrNotSupported);
        }
    
	// lengthSizeMinusOne indicates the length in bytes of the NALUnitLength field minus one.
	outputPtr[4] = 0x03; // 4 bytes
	outputPtr[4] |= 0x0FC; // 6 reserved bits (all 1)
	// numOfSequenceParameterSets indicates the number of sequence parameter sets
	outputPtr[5] = numSPS;
	outputPtr[5] |= 0xE0;  // 3 reserved bits (all 1)

	TInt len = 6;

	// Copy the SPS unit(s) to the buffer
	Mem::Copy(&outputPtr[6], spsPtr , totalSPSLength);
	len += totalSPSLength;
	outputPtr[6+totalSPSLength] = numPPS;
	len += 1;

	// Copy the PPS unit(s) to the buffer
	Mem::Copy(&outputPtr[6+totalSPSLength+1], ppsPtr , totalPPSLength);
	len += totalPPSLength;
	aDstBuf.SetLength(len);

	CleanupStack::PopAndDestroy(temp2);
	CleanupStack::PopAndDestroy(temp1);
    PRINT((_L("CCamC3GPDataSinkImp::ConvertAVCHeaderByteStreamL out")));
}

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL
//
// Converts AVC frame from Bytestream (ElementaryStream) encapsulation to
// file format AVC sample structure by replacing bytestream headers with NAL unit sizes.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizes( CCMRMediaBuffer* aBuffer )
    {
    PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL in")));
    TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr());
    TUint headerLength = aBuffer->Data().Length();
    PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL buffer length: %d"), headerLength));

    TInt nalLength = 0;
    TBool moreThanOneNAL = EFalse;
    TInt i = 0;
    TInt j = 0;
    for (i=0; i<headerLength; i++)
        {
        if ( inputPtr[i] == 0 &&
             inputPtr[i+1] == 0 &&
             inputPtr[i+2] == 0 &&
             inputPtr[i+3] == 1 )
            { // found bytestream header [00 00 00 01]
            PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL found header at: %d"), i));
            PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL NAL type: %d"), TInt(inputPtr[i+4] & 0x1F) ));
            if (moreThanOneNAL)
                {// we found start of next NAL unit in memory buffer so update previous size
                nalLength = i-j-4; // 4 is the bytestream header
                PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL NAL length: %d"), nalLength));
                inputPtr[j] = TUint8((nalLength >> 24) & 0xff);
                inputPtr[j+1] = TUint8((nalLength >> 16) & 0xff);
                inputPtr[j+2] = TUint8((nalLength >> 8) & 0xff);
                inputPtr[j+3] = TUint8(nalLength & 0xff);
                }
            moreThanOneNAL = ETrue;
            j=i;
            }
        }
    // and update last (or if only 1 NAL size:
    nalLength = headerLength-j-4; // 4 is the bytestream header
    PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL last NAL length: %d"), nalLength));
    inputPtr[j] = TUint8((nalLength >> 24) & 0xff);
    inputPtr[j+1] = TUint8((nalLength >> 16) & 0xff);
    inputPtr[j+2] = TUint8((nalLength >> 8) & 0xff);
    inputPtr[j+3] = TUint8(nalLength & 0xff);
    PRINT((_L("CCamC3GPDataSinkImp::ConvertBytestreamHeadersToNALSizesL out")));
}

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes
//
// Converts AVC frame from NAL (EGenericPayload) encapsulation to
// file format AVC sample structure by replacing NAL encapsulation with NAL unit sizes.
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes( CCMRMediaBuffer* aBuffer )
    {
    PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes in")));
    TUint8* inputPtr = (TUint8*)(aBuffer->Data().Ptr());
    TUint bufferLength = aBuffer->Data().Length();
    PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes buffer length: %d"), bufferLength));

    // Offset to the end and get NAL unit count
    TInt offset = bufferLength-4; //last 4 bytes are the NAL unit count
    TInt nalCount = TInt(inputPtr[offset]) +
                   (TInt(inputPtr[offset + 1]) << 8) +
                   (TInt(inputPtr[offset + 2]) << 16) +
                   (TInt(inputPtr[offset + 3]) << 24);

    TInt frameStart = 0;
    TInt frameSize = 0;
    TInt outputOffset = 0;
    for(TInt i=0; i<nalCount; i++)
        {//go through all NAL units in buffer
        // Offset to the start of NAL Unit infos
        offset = bufferLength-4-(8*nalCount); // 4 is the NAL unit count at end of buffer, 8 bytes used per NAL Unit for FrameStartOffset and FrameSize.

        // Get frame start offset
        offset += 8*i;
        frameStart = TInt(inputPtr[offset]) +
                    (TInt(inputPtr[offset + 1]) << 8) +
                    (TInt(inputPtr[offset + 2]) << 16) +
                    (TInt(inputPtr[offset + 3]) << 24);

        PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() NAL unit %d frame start: %d "), i, frameStart ));

        // Get frame size
        offset += 4;
        frameSize = TInt(inputPtr[offset]) +
                   (TInt(inputPtr[offset + 1]) << 8) +
                   (TInt(inputPtr[offset + 2]) << 16) +
                   (TInt(inputPtr[offset + 3]) << 24);

       PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() NAL unit %d frame size: %d "), i, frameSize ));
       PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() NAL unit %d type: %d "), i, TInt(inputPtr[frameStart] & 0x1F) ));

       iVideoBuffer[outputOffset] = TUint8((frameSize >> 24) & 0xff);
       iVideoBuffer[outputOffset+1] = TUint8((frameSize >> 16) & 0xff);
       iVideoBuffer[outputOffset+2] = TUint8((frameSize >> 8) & 0xff);
       iVideoBuffer[outputOffset+3] = TUint8(frameSize & 0xff);

       Mem::Copy(iVideoBuffer+outputOffset+4, inputPtr+frameStart, frameSize);
       outputOffset += 4 + frameSize; // 4 bytes for length information.
       }
    iVideoBufferFrameSize = outputOffset;
    PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes() new video buffer size: %d "), iVideoBufferFrameSize ));
    PRINT((_L("CCamC3GPDataSinkImp::ConvertNALEncapsulationToNALSizes out")));
    }

// -----------------------------------------------------------------------------
// CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName
// -----------------------------------------------------------------------------
//
void CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName( MP4FileName tempFileName )
    {
    PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName entering")));
    MP4FileName* tempFileNamePtr = NULL;
    TInt result = KErrNoMemory;

    // Add image to the queue.
    tempFileNamePtr = new MP4FileName;
    PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName tempFileName=%x, tempFileNamePtr=%x"), tempFileName, tempFileNamePtr));
    if ( tempFileNamePtr && iDeleteFileQueue )
        {
        PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName file count=%d"), iDeleteFileQueue->Count()));
        
        *tempFileNamePtr = tempFileName;
        result = iDeleteFileQueue->Append( tempFileNamePtr );
        }
    if ( result != KErrNone ) // Append failed -> do sync remove
        {
        TInt err = wremove( tempFileName );
        PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName wremove sync err=%d, tempFileName=%x"), err, tempFileName));
        free(tempFileName);
        tempFileName = 0;
        if ( tempFileNamePtr )
            {
            delete tempFileNamePtr;
            tempFileNamePtr = 0;
            }
        }
    else  // Append OK, start async delete if not running already
        {
        if (iDeleteFileQueue->Count())
            {

            if ( !iIdleDelete->IsActive() )
                {
                PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName() Start IdleDelete, file count=%d"), iDeleteFileQueue->Count()));
                iIdleDelete->Start( TCallBack( IdleDelete, this ) );
                }
            }
        }

    PRINT((_L("CCamC3GPDataSinkImp::M3GPMP4LibDeleteTempFileName exiting")));
    }


// ---------------------------------------------------------------------------
// CCamC3GPDataSinkImp::IdleDelete
// ---------------------------------------------------------------------------
//
TInt CCamC3GPDataSinkImp::IdleDelete( TAny* aCont )
    {
    CCamC3GPDataSinkImp* appCont = static_cast<CCamC3GPDataSinkImp*>( aCont );
    return ( appCont->DoIdleDelete() );
    }

// ---------------------------------------------------------------------------
// CCamC3GPDataSinkImp::DoIdleDelete
// ---------------------------------------------------------------------------
//
TInt CCamC3GPDataSinkImp::DoIdleDelete()
    {
    PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() in")));
    TInt err = KErrNone;
    MP4FileName tempFileName;
    TInt filesLeft = EFalse;

    // Delete one file from queue
    if ( iDeleteFileQueue )
        {
        PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() file count=%d"), iDeleteFileQueue->Count()));    
        if ( iDeleteFileQueue->Count() )
            {
            tempFileName = *(*iDeleteFileQueue)[0];
            PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete index 0:tempFileName=%x %s"), tempFileName, tempFileName));
            delete (*iDeleteFileQueue)[0];
            iDeleteFileQueue->Remove( 0 );
            err = wremove( tempFileName );
            PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete wremove async err=%d, tempFileName=%x %s"), err, tempFileName, tempFileName));
            err++; // remove compiler warning
            free(tempFileName);
            tempFileName = 0;
            }

        // Start next deletion if queue is not empty
        if ( iDeleteFileQueue->Count() )
            {
            PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() continue, file count=%d"), iDeleteFileQueue->Count()));
            filesLeft = ETrue;
            }
        }

    PRINT((_L("CCamC3GPDataSinkImp::DoIdleDelete() out")));
    return ( filesLeft );
    }


//  End of File