--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/videoeditorengine/vedengine/videoprocessor/src/VideoEncoderMDF.cpp Fri Jan 29 14:08:33 2010 +0200
@@ -0,0 +1,1285 @@
+/*
+* Copyright (c) 2010 Ixonos Plc.
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - Initial contribution
+*
+* Contributors:
+* Ixonos Plc
+*
+* Description:
+* Implementation for video encoder.
+*
+*/
+
+
+#include "statusmonitor.h"
+#include "videoencoder.h"
+#include "vedvideosettings.h"
+#include "vedvolreader.h"
+#include "vedavcedit.h"
+
+
+// Assertion macro wrapper for code cleanup
+#define VEASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CVIDEOENCODER"), EInternalAssertionFailure))
+
+// Debug print macro
+#ifdef _DEBUG
+#include <e32svr.h>
+#define PRINT(x) RDebug::Print x
+#else
+#define PRINT(x)
+#endif
+
+// Constants
+
+
+// time increment resolution
+const TUint KTimeIncrementResolutionHW = 30000;
+//const TUint KTimeIncrementResolutionSW = 29;
+
+const TReal KMinRandomAccessRate = 0.2;
+//const TUint KPictureQuality = 50;
+//const TReal KLatencyQyalityTradeoff = 1.0;
+//const TReal KQualityTemporalTradeoff = 0.8;
+//const TBool KEncodingRealTime = EFalse;
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// CVideoEncoder::NewL
+// Two-phased constructor.
+// ---------------------------------------------------------
+//
+
+CVideoEncoder* CVideoEncoder::NewL(CStatusMonitor *aMonitor, CVedAVCEdit* aAvcEdit,
+ const TPtrC8& aVideoMimeType)
+{
+ PRINT((_L("CVideoEncoder::NewL() : MDF")));
+
+ CVideoEncoder* self = new (ELeave) CVideoEncoder();
+ CleanupStack::PushL( self );
+ self->ConstructL(aMonitor, aAvcEdit, aVideoMimeType);
+ CleanupStack::Pop();
+
+ return self;
+}
+
+
+CVideoEncoder::CVideoEncoder() : CActive(EPriorityStandard), iInputBuffer(0,0)
+{
+ iPreviousTimeStamp = TTimeIntervalMicroSeconds(0);
+ iKeyFrame = EFalse;
+}
+
+
+void CVideoEncoder::ConstructL(CStatusMonitor *aMonitor, CVedAVCEdit* aAvcEdit,
+ const TPtrC8& aVideoMimeType)
+{
+ iTranscoder = NULL;
+ iMonitor = aMonitor;
+ iAvcEdit = aAvcEdit;
+
+ iFrameSize = KVedResolutionQCIF;
+ iFrameRate = 15.0;
+ iInputFrameRate = 15.0;
+ iRandomAccessRate = KMinRandomAccessRate;
+
+ // interpret and store video codec MIME-type. Allocates also iDataBuffer
+ SetVideoCodecL( aVideoMimeType );
+
+ iStatus = NULL;
+
+ iVolReader = CVedVolReader::NewL();
+
+ // allocate input picture
+ iInputPicture = new (ELeave) TTRVideoPicture;
+
+ // Create a timer
+ User::LeaveIfError(iTimer.CreateLocal());
+ iTimerCreated = ETrue;
+
+ // Add us to active scheduler
+ CActiveScheduler::Add(this);
+}
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::~CVideoEncoder()
+// Destructor
+// ---------------------------------------------------------
+//
+CVideoEncoder::~CVideoEncoder()
+ {
+
+ Cancel();
+
+ if ( iInputPicture )
+ {
+ delete iInputPicture;
+ iInputPicture = 0;
+ }
+
+ if ( iDataBuffer )
+ {
+ delete iDataBuffer;
+ iDataBuffer = 0;
+ }
+
+ if ( iTranscoder )
+ {
+ delete iTranscoder;
+ iTranscoder = 0;
+ }
+
+ if ( iVolReader )
+ {
+ delete iVolReader;
+ iVolReader = 0;
+ }
+
+ if ( iTimerCreated )
+ {
+ iTimer.Close();
+ iTimerCreated = EFalse;
+ }
+
+
+ }
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetVideoCodecL()
+// Interpret and store video mime type
+// ---------------------------------------------------------
+//
+void CVideoEncoder::SetVideoCodecL(const TPtrC8& aMimeType)
+ {
+ TBuf8<256> string;
+ TBuf8<256> newMimeType;
+ string = KVedMimeTypeH263;
+ string += _L8( "*" );
+ TInt dataBufferSize = KMaxCodedPictureSizeQCIF;
+
+ iMaxFrameRate = 15.0;
+ iArbitrarySizeAllowed = EFalse;
+
+ if ( aMimeType.MatchF( (const TDesC8& )string ) != KErrNotFound )
+ {
+ // H.263
+
+ newMimeType = KVedMimeTypeH263;
+
+ if ( aMimeType.MatchF( _L8("*profile*") ) != KErrNotFound )
+ {
+ // profile given, check if we support it
+ if ( aMimeType.MatchF( _L8("*profile=0*")) != KErrNotFound )
+ {
+ // profile 0 requested
+ newMimeType += _L8( "; profile=0" );
+ }
+ else
+ {
+ // no other profiles supported
+ PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported profile")));
+ User::Leave(KErrNotSupported);
+ }
+ }
+ else
+ {
+ // no profile is given => assume 0
+ newMimeType += _L8( "; profile=0" );
+ }
+
+ if ( aMimeType.MatchF( _L8("*level=10*") ) != KErrNotFound )
+ {
+ iMaxBitRate = iBitRate = KVedBitRateH263Level10;
+ iMaxResolution = KVedResolutionQCIF;
+ dataBufferSize = KMaxCodedPictureSizeQCIF;
+ newMimeType += _L8( "; level=10" );
+ }
+ else if ( aMimeType.MatchF( _L8("*level=45*") ) != KErrNotFound )
+ {
+ iMaxBitRate = iBitRate = KVedBitRateH263Level45;
+ iMaxResolution = KVedResolutionQCIF;
+ dataBufferSize = KMaxCodedPictureSizeQCIF;
+ newMimeType += _L8( "; level=45" );
+ }
+ else if ( aMimeType.MatchF( _L8("*level*") ) != KErrNotFound )
+ {
+ // no other levels supported
+ PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported level")));
+ User::Leave(KErrNotSupported);
+ }
+ else
+ {
+ // if no level is given assume 10
+ iMaxBitRate = iBitRate = KVedBitRateH263Level10;
+ iMaxResolution = KVedResolutionQCIF;
+ dataBufferSize = KMaxCodedPictureSizeQCIF;
+ newMimeType += _L8( "; level=10" );
+ }
+ }
+ else
+ {
+ string = KVedMimeTypeMPEG4Visual;
+ string += _L8( "*" );
+
+ if ( aMimeType.MatchF( string ) != KErrNotFound )
+ {
+ // MPEG-4 Visual
+ newMimeType = KVedMimeTypeMPEG4Visual;
+ if ( aMimeType.MatchF( _L8("*profile-level-id=8*") ) != KErrNotFound )
+ {
+ // simple profile level 0
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level0;
+ iMaxResolution = KVedResolutionQCIF;
+ // define max size 10K
+ dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
+ newMimeType += _L8("; profile-level-id=8");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=9*") ) != KErrNotFound )
+ {
+ // simple profile level 0b
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level0;
+ iMaxResolution = KVedResolutionQCIF;
+ // define max size 10K
+ dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
+ newMimeType += _L8("; profile-level-id=9");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=1*") ) != KErrNotFound )
+ {
+ // simple profile level 1
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level0;
+ iMaxResolution = KVedResolutionQCIF;
+ // define max size 10K
+ dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=1");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=2*") ) != KErrNotFound )
+ {
+ // simple profile level 2
+ dataBufferSize = KMaxCodedPictureSizeMPEG4CIF;
+ iMaxResolution = KVedResolutionCIF;
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level2;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=2");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=3*") ) != KErrNotFound )
+ {
+ // simple profile level 3
+ dataBufferSize = KMaxCodedPictureSizeMPEG4CIF;
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level2;
+ iMaxResolution = KVedResolutionCIF;
+ iMaxFrameRate = 30.0;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=3");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=4*") ) != KErrNotFound )
+ {
+ // simple profile level 4a
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level4A;
+ dataBufferSize = KMaxCodedPictureSizeVGA;
+ iMaxResolution = KVedResolutionVGA;
+ iMaxFrameRate = 30.0;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=4");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound )
+ {
+ // no other profile-level ids supported
+ PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported MPEG-4 profile-level")));
+ User::Leave(KErrNotSupported);
+ }
+ else
+ {
+ // Default is level 0 in our case (normally probably level 1)
+ iMaxBitRate = iBitRate = KVedBitRateMPEG4Level0;
+ iMaxResolution = KVedResolutionQCIF;
+ // define max size 10K
+ dataBufferSize = KMaxCodedPictureSizeMPEG4QCIF;
+ newMimeType += _L8("; profile-level-id=8");
+ }
+ }
+ else
+ {
+
+#ifdef VIDEOEDITORENGINE_AVC_EDITING
+ string = KVedMimeTypeAVC;
+ string += _L8( "*" );
+ if ( aMimeType.MatchF( string ) != KErrNotFound )
+ {
+ // AVC
+ newMimeType = KVedMimeTypeAVC;
+ if ( aMimeType.MatchF( _L8("*profile-level-id=42800A*") ) != KErrNotFound )
+ {
+ // baseline profile level 1
+ iMaxBitRate = iBitRate = KVedBitRateAVCLevel1;
+ iMaxResolution = KVedResolutionQCIF;
+ dataBufferSize = KMaxCodedPictureSizeAVCLevel1;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=42800A");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=42900B*") ) != KErrNotFound )
+ {
+ // baseline profile level 1b
+ iMaxBitRate = iBitRate = KVedBitRateAVCLevel1b;
+ iMaxResolution = KVedResolutionQCIF;
+ dataBufferSize = KMaxCodedPictureSizeAVCLevel1B;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=42900B");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=42800B*") ) != KErrNotFound )
+ {
+ // baseline profile level 1.1
+ iMaxBitRate = iBitRate = KVedBitRateAVCLevel1_1;
+ iMaxResolution = KVedResolutionCIF;
+ dataBufferSize = KMaxCodedPictureSizeAVCLevel1_1;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=42800B");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=42800C*") ) != KErrNotFound )
+ {
+ // baseline profile level 1.2
+ iMaxBitRate = iBitRate = KVedBitRateAVCLevel1_2;
+ iMaxResolution = KVedResolutionCIF;
+ dataBufferSize = KMaxCodedPictureSizeAVCLevel1_2;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=42800C");
+ }
+ //WVGA task
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=42801F*") ) != KErrNotFound )
+ {
+ // baseline profile level 1.3
+ iMaxBitRate = iBitRate = KVedBitRateAVCLevel3_1;
+ iMaxResolution = KVedResolutionWVGA;
+ dataBufferSize = KMaxCodedPictureSizeAVCLevel3_1;
+ iArbitrarySizeAllowed = ETrue;
+ newMimeType += _L8("; profile-level-id=42801F");
+ }
+ else if ( aMimeType.MatchF( _L8("*profile-level-id=*") ) != KErrNotFound )
+ {
+ // no other profile-level ids supported
+ PRINT((_L("CVideoEncoder::SetVideoCodecL() unsupported AVC profile-level")));
+ User::Leave(KErrNotSupported);
+ }
+ else
+ {
+ // Default is level 1 (?)
+ iMaxBitRate = iBitRate = KVedBitRateAVCLevel1;
+ iMaxResolution = KVedResolutionQCIF;
+ dataBufferSize = KMaxCodedPictureSizeAVCLevel1;
+ newMimeType += _L8("; profile-level-id=42800A");
+ }
+ }
+ else
+ {
+ // unknown mimetype
+ User::Leave( KErrNotSupported );
+ }
+#else
+ // unknown mimetype
+ User::Leave( KErrNotSupported );
+#endif
+ }
+ }
+
+ // successfully interpreted the input mime type
+ iMimeType = newMimeType;
+ if ( iDataBuffer )
+ {
+ delete iDataBuffer;
+ iDataBuffer = NULL;
+ }
+ iDataBuffer = (HBufC8*) HBufC8::NewL(dataBufferSize);
+
+ }
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetFrameSizeL
+// Sets the used frame size
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::SetFrameSizeL(const TSize& aSize)
+ {
+
+ if (iFrameSize == aSize)
+ return;
+
+ if ( (aSize.iWidth > iMaxResolution.iWidth) || (aSize.iHeight > iMaxResolution.iHeight))
+ {
+ if ( iArbitrarySizeAllowed ) // This is for future-proofness. Currently the checking of standard sizes below overrules this one
+ {
+ if ( aSize.iWidth * aSize.iHeight > iMaxResolution.iWidth*iMaxResolution.iHeight )
+ {
+ PRINT((_L("CVideoEncoder::SetFrameSizeL() too high resolution requested")));
+ User::Leave( KErrNotSupported );
+ }
+ }
+ else
+ {
+ PRINT((_L("CVideoEncoder::SetFrameSizeL() incompatible or too high resolution requested")));
+ User::Leave( KErrNotSupported );
+ }
+ }
+
+ // check new size. For now only standard sizes are allowed
+ if ( (aSize != KVedResolutionSubQCIF) &&
+ (aSize != KVedResolutionQCIF) &&
+ (aSize != KVedResolutionCIF) &&
+ (aSize != KVedResolutionQVGA) &&
+ (aSize != KVedResolutionVGA16By9) &&
+ (aSize != KVedResolutionVGA) &&
+ //WVGA task
+ (aSize != KVedResolutionWVGA) )
+ {
+ User::Leave( KErrArgument );
+ }
+
+ iFrameSize = aSize;
+
+ }
+
+// ---------------------------------------------------------
+// CVideoEncoder::GetFrameSize
+// Gets the used frame size
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::FrameSize(TSize& aSize) const
+ {
+
+ aSize = iFrameSize;
+
+ }
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetFrameRate
+// Sets the used targt frame rate
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CVideoEncoder::SetFrameRate(const TReal aFrameRate)
+{
+ VEASSERT(aFrameRate > 0.0);
+
+ if ( aFrameRate <= iMaxFrameRate )
+ {
+ iFrameRate = TReal32(aFrameRate);
+ }
+ else
+ {
+ iFrameRate = iMaxFrameRate;
+ }
+
+ // target framerate cannot be larger than source framerate
+ if (iFrameRate > iInputFrameRate)
+ iFrameRate = iInputFrameRate;
+
+ return KErrNone;
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetInputFrameRate
+// Sets the used input sequence frame rate
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CVideoEncoder::SetInputFrameRate(const TReal aFrameRate)
+ {
+
+ VEASSERT(aFrameRate > 0.0);
+
+ iInputFrameRate = aFrameRate;
+
+ // target framerate cannot be larger than source framerate
+ if (iFrameRate > iInputFrameRate)
+ iFrameRate = iInputFrameRate;
+
+ return KErrNone;
+
+ }
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetRandomAccessRate
+// Sets the used target random access rate
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CVideoEncoder::SetRandomAccessRate(const TReal aRate)
+{
+ VEASSERT(aRate > 0.0);
+
+ iRandomAccessRate = aRate;
+
+ return KErrNone;
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetBitrate
+// Sets the used target bitrate
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CVideoEncoder::SetBitrate(const TInt aBitrate)
+{
+ VEASSERT(aBitrate > 0);
+
+ if ( aBitrate <= iMaxBitRate )
+ {
+ iBitRate = aBitrate;
+ }
+ else
+ {
+ iBitRate = iMaxBitRate;
+ }
+
+ return KErrNone;
+
+}
+
+// --------------------------------------------------------
+
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::InitializeL
+// Initializes the encoder
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::InitializeL(TRequestStatus &aStatus)
+ {
+
+ PRINT((_L("CVideoEncoder::InitializeL() in")));
+
+ iResetRequestStatus = &aStatus;
+
+ // Create DevVideoRecord & select video encoder
+
+ if ( iTranscoder )
+ {
+ // need to recreate since parameters changed
+ delete iTranscoder;
+ iTranscoder = 0;
+ }
+
+ iFatalError = EFalse;
+
+ iTranscoder = CTRTranscoder::NewL(*this);
+
+ // Select & set parameters to transcoder
+ TRAPD(err, SetupEncoderL());
+
+ if ( err != KErrNone )
+ {
+ // error
+ User::Leave( err );
+ }
+
+ iTranscoder->InitializeL();
+
+ PRINT((_L("CVideoEncoder::InitializeL() out")));
+
+
+ }
+
+// ---------------------------------------------------------
+// CVideoEncoder::Start
+// Starts the encoder
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+
+void CVideoEncoder::Start()
+{
+ TRAPD( error, iTranscoder->StartL() );
+
+ if (error != KErrNone)
+ {
+ if (iMonitor)
+ iMonitor->Error(error);
+ }
+}
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetRandomAccessPoint
+// Forces the next encoded frame to Intra
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::SetRandomAccessPoint()
+{
+ VEASSERT(iTranscoder);
+
+ iTranscoder->SetRandomAccessPoint();
+
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::Stop
+// Stops the encoder
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::Stop()
+{
+
+ if ( !iFatalError )
+ {
+
+ if (iStarted)
+ {
+ TRAPD( error, iTranscoder->StopL() );
+ if (error != KErrNone)
+ {
+ if (iMonitor)
+ iMonitor->Error(error);
+ }
+ }
+
+ iStarted = EFalse;
+ }
+}
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::Reset
+// Resets the encoder
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::Reset(TRequestStatus &aStatus)
+{
+
+ PRINT((_L("CVideoEncoder::Reset() in")));
+
+ iPreviousTimeStamp = TTimeIntervalMicroSeconds(0);
+
+ iResetRequestStatus = &aStatus;
+
+ if ( iFatalError )
+ {
+ MtroAsyncStopComplete();
+ }
+ else
+ {
+ TRAPD(err, iTranscoder->AsyncStopL());
+ if (err != KErrNone)
+ iMonitor->Error(err);
+ }
+
+ iStarted = EFalse;
+
+ PRINT((_L("CVideoEncoder::Reset() out")));
+}
+
+void CVideoEncoder::Reset()
+{
+
+ PRINT((_L("CVideoEncoder::Reset() (sync.) in")));
+
+ iPreviousTimeStamp = TTimeIntervalMicroSeconds(0);
+
+ if ( !iFatalError )
+ {
+ if (iStarted)
+ {
+ TRAPD(err, iTranscoder->StopL());
+ if (err != KErrNone)
+ iMonitor->Error(err);
+ }
+ }
+
+ iStarted = EFalse;
+
+ PRINT((_L("CVideoEncoder::Reset() (sync.) out")));
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::RunL
+// Active object running method.
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::RunL()
+{
+
+ // Timer elapsed, complete encoding request
+ // with KErrCancel
+
+ PRINT((_L("CVideoEncoder::RunL() in")));
+
+ if (iTimerRequestPending)
+ {
+ iTimerRequestPending = EFalse;
+ if (iEncodeRequestStatus)
+ {
+#ifdef _DEBUG
+ TTime current;
+ current.UniversalTime();
+ TInt64 time = current.MicroSecondsFrom(iEncodeStartTime).Int64();
+ PRINT((_L("CVideoEncoder::RunL(), completing request, time since encoding started %d"), I64INT( time )));
+#endif
+
+ VEASSERT(*iEncodeRequestStatus == KRequestPending);
+ // complete request
+ User::RequestComplete(iEncodeRequestStatus, KErrCancel);
+ iEncodeRequestStatus = 0;
+ iEncodePending = EFalse;
+ }
+ }
+ PRINT((_L("CVideoEncoder::RunL() out")));
+
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::RunError
+// Active object error method.
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TInt CVideoEncoder::RunError(TInt aError)
+{
+ PRINT((_L("CVideoEncoder::RunError() in")));
+
+ Cancel();
+
+ iMonitor->Error(aError);
+
+ PRINT((_L("CVideoEncoder::RunError() out")));
+
+ return KErrNone;
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::DoCancel
+// Active object cancelling method
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::DoCancel()
+{
+
+ PRINT((_L("CVideoEncoder::DoCancel() in")));
+
+ // Cancel our timer request if we have one
+ if ( iTimerRequestPending )
+ {
+ iTimer.Cancel();
+ iTimerRequestPending = EFalse;
+ return;
+ }
+
+}
+
+// ---------------------------------------------------------
+// CVideoEncoder::EncodeFrameL
+// Encodes a frame
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::EncodeFrameL(TPtr8& aYUVFrame, TRequestStatus &aStatus, TTimeIntervalMicroSeconds aTimeStamp)
+ {
+ PRINT((_L("CVideoEncoder::EncodeFrameL() in, aTimeStamp = %d"), I64INT( aTimeStamp.Int64() ) ));
+
+ if ( iFatalError )
+ {
+ PRINT((_L("CVideoEncoder::EncodeFrameL() can't encode since fatal error has occurred earlier")));
+ User::Leave( KErrGeneral );
+ }
+
+ iEncodeRequestStatus = &aStatus;
+
+ if (!iStarted)
+ {
+ PRINT((_L("CVideoEncoder::EncodeFrameL() - starting devVideoRec")));
+ //iTranscoder->StopL(); // NOTE: needed ??
+ iTranscoder->StartL();
+ iStarted = ETrue;
+ }
+
+ // wrap input frame to encoder input buffer
+ iInputBuffer.Set(aYUVFrame);
+ iInputPicture->iRawData = &iInputBuffer;
+ iInputPicture->iDataSize.SetSize(iFrameSize.iWidth, iFrameSize.iHeight);
+
+ if (aTimeStamp > TTimeIntervalMicroSeconds(0))
+ {
+ TInt64 diff = aTimeStamp.Int64() - iPreviousTimeStamp.Int64();
+
+ if (diff < 0)
+ {
+ aTimeStamp = iPreviousTimeStamp.Int64() + TInt64(66667);
+ }
+ // NOTE: Could the real difference between two consecutive
+ // frames be used instead of assuming 15 fps ?
+ }
+ iPreviousTimeStamp = aTimeStamp;
+
+ iInputPicture->iTimestamp = aTimeStamp;
+ //iInputPicture->iLink = NULL;
+ iInputPicture->iUser = this;
+
+#ifdef _DEBUG
+ iEncodeStartTime.UniversalTime();
+#endif
+
+
+ iEncodePending = ETrue;
+
+ iTranscoder->SendPictureToTranscoderL( iInputPicture );
+
+ PRINT((_L("CVideoEncoder::EncodeFrameL() out")));
+
+ }
+
+
+// ---------------------------------------------------------
+// CVideoEncoder::GetBuffer
+// Gets encoded frame bitstream buffer
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+TPtrC8& CVideoEncoder::GetBufferL(TBool& aKeyFrame)
+ {
+ if ( iFatalError )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ VEASSERT(iDataBuffer->Length() > 0);
+
+ PRINT((_L("CVideoEncoder::GetBufferL(), keyFrame = %d"), iKeyFrame));
+
+ aKeyFrame = iKeyFrame;
+
+ iReturnDes.Set(iDataBuffer->Des());
+ return iReturnDes;
+
+ }
+
+// ---------------------------------------------------------
+// CVideoEncoder::ReturnBuffer
+// Returns used bitstream buffer to devVideoRec
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::ReturnBuffer()
+ {
+ if ( iFatalError )
+ {
+ return;
+ }
+
+ iDataBuffer->Des().Zero();
+
+ }
+
+// ---------------------------------------------------------
+// CVideoEncoder::SetupEncoderL
+// Private helper method to select & setup the encoder
+// plugin devvr must use
+// (other items were commented in a header).
+// ---------------------------------------------------------
+//
+void CVideoEncoder::SetupEncoderL()
+ {
+
+ if ( !(iTranscoder->SupportsOutputVideoFormat(iMimeType) ) )
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ TTRVideoFormat videoInputFormat;
+ TTRVideoFormat videoOutputFormat;
+
+ videoInputFormat.iSize = iFrameSize;
+ videoInputFormat.iDataType = CTRTranscoder::ETRYuvRawData420;
+
+ videoOutputFormat.iSize = iFrameSize;
+ videoOutputFormat.iDataType = CTRTranscoder::ETRDuCodedPicture;
+
+ iTranscoder->OpenL( this,
+ CTRTranscoder::EEncoding,
+ KNullDesC8,
+ iMimeType,
+ videoInputFormat,
+ videoOutputFormat,
+ EFalse );
+
+ // default, will be updated by ParseVolHeader
+ iTimeIncrementResolution = KTimeIncrementResolutionHW; //KTimeIncrementResolutionSW;
+
+ iTranscoder->SetVideoBitRateL(iBitRate);
+
+ iTranscoder->SetFrameRateL(iFrameRate);
+
+ iTranscoder->SetChannelBitErrorRateL(0.0);
+
+ // Get processing time estimate from transcoder, divide it by the framerate to get processing time per frame
+ // and then multiply it by 2 to get some safety margin and by unit conversion factor 1000000.
+ // The delay is used to determine if a frame was skipped, hence there should be some margin.
+#ifdef __WINSCW__
+ iMaxEncodingDelay = 5000000; // emulator can be really slow, use 5 seconds timeout
+#else
+ iMaxEncodingDelay = (TUint)(2*1000000*iTranscoder->EstimateTranscodeTimeFactorL(videoInputFormat,videoOutputFormat)/iFrameRate);
+ iMaxEncodingDelay += 100000; // Add 100 ms for safety margin
+#endif
+
+ TTRVideoCodingOptions codingOptions;
+ codingOptions.iSyncIntervalInPicture = 0;
+ codingOptions.iMinRandomAccessPeriodInSeconds = (TInt) (1.0 / iRandomAccessRate);
+
+ // NOTE: What about these ???
+ codingOptions.iDataPartitioning = EFalse;
+ codingOptions.iReversibleVLC = EFalse;
+ codingOptions.iHeaderExtension = 0;
+
+ iTranscoder->SetVideoCodingOptionsL(codingOptions);
+
+ iTranscoder->SetVideoPictureSinkOptionsL(iFrameSize, this);
+
+ }
+
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::MtroSetInputFrameRate
+// Sets input sequence frame rate for encoding
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::MtroSetInputFrameRate(TReal& aRate)
+ {
+
+ aRate = iInputFrameRate;
+
+ }
+
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::MtroPictureFromTranscoder
+// Called by transcoder to return the input picture buffer
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::MtroPictureFromTranscoder(TTRVideoPicture* aPicture)
+ {
+ PRINT((_L("CVideoEncoder::MtroPictureFromTranscoder() %x"), aPicture));
+
+ if (iInputPicture != aPicture)
+ {
+ iMonitor->Error(KErrGeneral);
+ return;
+ }
+
+ if (iEncodePending)
+ {
+ if (!iTimerRequestPending)
+ {
+ // Activate timer to wait for encoding, if the encoding didn't complete already.
+ // Timeout is needed since we don't get notification if frame was skipped.
+ SetActive();
+ iStatus = KRequestPending;
+ iTimer.After(iStatus, TTimeIntervalMicroSeconds32(iMaxEncodingDelay));
+ iTimerRequestPending = ETrue;
+ }
+ }
+ }
+
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::WriteBufferL
+// Called by transcoder to notify that new bitsream buffer is ready
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::WriteBufferL(CCMRMediaBuffer* aBuffer)
+ {
+
+ PRINT((_L("CVideoEncoder::WriteBufferL(), iEncodePending = %d"), iEncodePending));
+
+#ifdef _DEBUG
+ TTime current;
+ current.UniversalTime();
+ TInt64 time = current.MicroSecondsFrom(iEncodeStartTime).Int64();
+ PRINT((_L("CVideoEncoder::WriteBufferL(), time spent encoding = %d ms, iEncodeRequestStatus = 0x%x"),
+ (I64INT(time))/1000 ,iEncodeRequestStatus));
+
+#endif
+
+ if (aBuffer->Type() == CCMRMediaBuffer::EVideoMPEG4DecSpecInfo)
+ {
+ // copy data to bitstream buffer
+ TPtr8 ptr = iDataBuffer->Des();
+ ptr.Copy( aBuffer->Data() );
+ return;
+ }
+
+ // Cancel timer
+ Cancel();
+
+ iEncodePending = EFalse;
+
+ if (aBuffer->BufferSize() == 0)
+ {
+ PRINT((_L("CVideoEncoder::WriteBufferL() buffer length == 0")));
+
+ if ( iEncodeRequestStatus != 0 )
+ {
+ // complete request
+ User::RequestComplete(iEncodeRequestStatus, KErrUnderflow);
+ iEncodeRequestStatus = 0;
+ }
+ return;
+ }
+
+ VEASSERT(aBuffer->Data().Length() <= KMaxCodedPictureSizeVGA);
+
+#ifdef VIDEOEDITORENGINE_AVC_EDITING
+ TInt avcFrameLen = 0;
+ if ( iMimeType.FindF(KVedMimeTypeAVC) != KErrNotFound )
+ {
+ // get avc frame length
+ TUint8* tmp = const_cast<TUint8*>(aBuffer->Data().Ptr() + aBuffer->Data().Length());
+ // support for 1 frame in 1 NAL unit currently
+ tmp -= 4;
+ TInt numNalUnits = TInt(tmp[0]) + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);
+ if (numNalUnits > 0) { }
+
+ VEASSERT( numNalUnits == 1 );
+ tmp -=4;
+
+ avcFrameLen = tmp[0] + (TInt(tmp[1])<<8) + (TInt(tmp[2])<<16) + (TInt(tmp[3])<<24);
+
+ TInt error = KErrNone;
+ // check that there is enough room for length field and the frame
+ if ( iDataBuffer->Des().MaxLength() < (avcFrameLen + 4) )
+ TRAP( error, iDataBuffer->ReAllocL(avcFrameLen + 4) );
+
+ if (error != KErrNone)
+ {
+ iMonitor->Error(error);
+ return;
+ }
+
+ TUint8* buf = const_cast<TUint8*>(iDataBuffer->Des().Ptr());
+
+ // set length
+ buf[0] = TUint8((avcFrameLen >> 24) & 0xff);
+ buf[1] = TUint8((avcFrameLen >> 16) & 0xff);
+ buf[2] = TUint8((avcFrameLen >> 8) & 0xff);
+ buf[3] = TUint8(avcFrameLen & 0xff);
+
+ iDataBuffer->Des().SetLength(4);
+ }
+#endif
+
+ // copy data to bitstream buffer
+ TPtr8 ptr = iDataBuffer->Des();
+
+#ifdef VIDEOEDITORENGINE_AVC_EDITING
+ if ( iMimeType.FindF(KVedMimeTypeAVC) != KErrNotFound )
+ {
+ ptr.Append( aBuffer->Data().Ptr(), avcFrameLen );
+ }
+ else
+#endif
+ {
+ ptr.Append( aBuffer->Data() );
+ }
+
+ // save keyframe flag
+ iKeyFrame = aBuffer->RandomAccessPoint();
+
+ if ( iEncodeRequestStatus != 0 )
+ {
+ // complete request
+ User::RequestComplete(iEncodeRequestStatus, KErrNone);
+ iEncodeRequestStatus = 0;
+ }
+
+ // --> user calls GetBuffer();
+
+ }
+
+TInt CVideoEncoder::SetVideoFrameSize(TSize /*aSize*/)
+ {
+ return KErrNone;
+ }
+
+TInt CVideoEncoder::SetAverageVideoBitRate(TInt /*aSize*/)
+ {
+ return KErrNone;
+ }
+
+TInt CVideoEncoder::SetMaxVideoBitRate(TInt /*aSize*/)
+ {
+ return KErrNone;
+ }
+
+TInt CVideoEncoder::SetAverageAudioBitRate(TInt /*aSize*/)
+ {
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::MtroFatalError
+// Called by transcoder when a fatal error has occurred
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::MtroFatalError(TInt aError)
+ {
+
+ PRINT((_L("CVideoEncoder::MtroFatalError() %d"), aError));
+ iFatalError = ETrue;
+
+ iMonitor->Error(aError);
+
+ }
+
+void CVideoEncoder::MtroReturnCodedBuffer(CCMRMediaBuffer* /*aBuffer*/)
+ {
+
+ User::Panic(_L("CVIDEOENCODER"), EInternalAssertionFailure);
+ }
+
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::MdvroInitializeComplete
+// Called by transcoder when initialization is complete
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::MtroInitializeComplete(TInt aError)
+ {
+ PRINT((_L("CVideoEncoder::MtroInitializeComplete %d, iResetRequestStatus %x"), aError, iResetRequestStatus));
+
+ VEASSERT(iResetRequestStatus);
+
+ if ( aError != KErrNone )
+ {
+ iMonitor->Error(aError);
+ if ( iResetRequestStatus != 0 )
+ {
+ User::RequestComplete(iResetRequestStatus, aError);
+ iResetRequestStatus = 0;
+ }
+ return;
+ }
+
+ TInt error = KErrNone;
+ // Handle MPEG-4 VOL / AVC SPS/PPS data reading/writing
+ TRAP(error, HandleCodingStandardSpecificInfoL());
+
+ if ( error != KErrNone )
+ iMonitor->Error(error);
+
+ if ( iResetRequestStatus != 0 )
+ {
+ PRINT((_L("CVideoEncoder::MtroInitializeComplete() complete request")));
+ // complete request:
+ User::RequestComplete(iResetRequestStatus, error);
+ iResetRequestStatus = 0;
+ }
+
+ }
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::MtroAsyncStopComplete
+// Called by transcoder when all pictures have been processed
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::MtroAsyncStopComplete()
+ {
+
+ PRINT((_L("CVideoEncoder::MtroAsyncStopComplete()")));
+
+ if ( iResetRequestStatus != 0 )
+ {
+ PRINT((_L("CVideoEncoder::MdvroStreamEnd() complete request")));
+ // complete request
+ User::RequestComplete(iResetRequestStatus, KErrNone);
+ iResetRequestStatus = 0;
+ }
+
+ }
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::GetTimeIncrementResolution
+// Gets time increment resolution used in MPEG-4
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TInt CVideoEncoder::GetTimeIncrementResolution() const
+ {
+ if ( iVolReader->TimeIncrementResolution() != 0 )
+ return iVolReader->TimeIncrementResolution();
+
+ return iTimeIncrementResolution;
+ }
+
+// -----------------------------------------------------------------------------
+// CVideoEncoder::HandleCodingStandardSpecificInfoL
+// Parses the MPEG-4 VOL header / AVC Dec. configuration record
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+void CVideoEncoder::HandleCodingStandardSpecificInfoL()
+ {
+
+ // Parse the VOL header for mpeg-4
+ if ( iMimeType.FindF(KVedMimeTypeMPEG4Visual) != KErrNotFound )
+ {
+ HBufC8* headerData = iTranscoder->GetCodingStandardSpecificInitOutputLC();
+ if ( headerData != 0 )
+ {
+ iVolReader->ParseVolHeaderL( (TDesC8&) *headerData );
+
+ // Insert VOL header to bitstream buffer
+ TPtr8 ptr = iDataBuffer->Des();
+ ptr.Append( *headerData );
+
+ CleanupStack::PopAndDestroy( headerData );
+ }
+ }
+
+#ifdef VIDEOEDITORENGINE_AVC_EDITING
+ // Parse & write SPS/PPS data for AVC
+ else if ( iMimeType.FindF(KVedMimeTypeAVC) != KErrNotFound )
+ {
+ HBufC8* headerData = iTranscoder->GetCodingStandardSpecificInitOutputLC();
+
+ if ( headerData != 0 )
+ {
+
+ HBufC8* outputAVCHeader = 0;
+ // is the max. size of AVCDecoderConfigurationRecord known here ??
+ outputAVCHeader = (HBufC8*) HBufC8::NewLC(16384);
+ TPtr8 ptr = outputAVCHeader->Des();
+
+ // parse header & convert it to AVCDecoderConfigurationRecord -format
+ iAvcEdit->ConvertAVCHeaderL(*headerData, ptr);
+
+ // save it to avc module for later use
+ iAvcEdit->SaveAVCDecoderConfigurationRecordL(ptr, ETrue /* aFromEncoder */);
+
+ CleanupStack::PopAndDestroy( 2 ); // headerData, outputAVCHeader
+
+ }
+ }
+#endif
+
+ }