diff -r 000000000000 -r 951a5db380a0 videditor/VideoEditorCommon/src/VeiImageClipGenerator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/videditor/VideoEditorCommon/src/VeiImageClipGenerator.cpp Fri Jan 29 14:08:33 2010 +0200 @@ -0,0 +1,999 @@ +/* +* Copyright (c) 2010 Ixonos Plc. +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - Initial contribution +* +* Contributors: +* Ixonos Plc +* +* Description: +* +*/ + + + +#include "VeiImageClipGenerator.h" + +#include +#include +#include +#include +#include +#include +#include + +#define KMiddleFrameDuration TTimeIntervalMicroSeconds(1000000) + +const TInt KNumberOfTransitionFrames = 10; + +EXPORT_C CVeiImageClipGenerator* CVeiImageClipGenerator::NewL(const TDesC& aFilename, + const TSize& aMaxResolution, + const TTimeIntervalMicroSeconds& aDuration, + const TRgb& aBackgroundColor, + TDisplayMode aMaxDisplayMode, + RFs& aFs, + MVeiImageClipGeneratorObserver& aObserver) + { + CVeiImageClipGenerator* self = + CVeiImageClipGenerator::NewLC(aFilename, aMaxResolution, aDuration, aBackgroundColor, aMaxDisplayMode, aFs, aObserver); + CleanupStack::Pop(self); + return self; + } + + +EXPORT_C CVeiImageClipGenerator* CVeiImageClipGenerator::NewLC(const TDesC& aFilename, + const TSize& aMaxResolution, + const TTimeIntervalMicroSeconds& aDuration, + const TRgb& aBackgroundColor, + TDisplayMode aMaxDisplayMode, + RFs& aFs, + MVeiImageClipGeneratorObserver& aObserver) + { + CVeiImageClipGenerator* self = new (ELeave) CVeiImageClipGenerator(aDuration, aBackgroundColor, aMaxResolution); + CleanupStack::PushL(self); + self->ConstructL(aFilename, aObserver, aMaxDisplayMode, aFs); + return self; + } + + +CVeiImageClipGenerator::CVeiImageClipGenerator(const TTimeIntervalMicroSeconds& aDuration, + const TRgb& aBackgroundColor, + const TSize& aMaxResolution) + : iReady(EFalse), iMaxResolution(aMaxResolution), iBackgroundColor(aBackgroundColor), iInitializing(ETrue) + { + __ASSERT_ALWAYS(iMaxResolution.iHeight >= 0, TVedPanic::Panic(TVedPanic::EImageClipGeneratorIllegalMaxResolution)); + __ASSERT_ALWAYS(iMaxResolution.iWidth >= 0, TVedPanic::Panic(TVedPanic::EImageClipGeneratorIllegalMaxResolution)); + + SetDuration(aDuration); + + iInitializing = EFalse; + } + + +void CVeiImageClipGenerator::ConstructL(const TDesC& aFilename, + MVeiImageClipGeneratorObserver& aObserver, + TDisplayMode aMaxDisplayMode, RFs& aFs) + { + iDecodeOperation = CVeiImageClipDecodeOperation::NewL(*this, aFilename, aObserver, aFs); + iFrameOperation = CVeiImageClipFrameOperation::NewL(*this); + + iFilename = aFilename.AllocL(); + + TParse parse; + parse.Set(aFilename, 0, 0); + iDescriptiveName = parse.Name().AllocL(); + + iDecodeOperation->StartOperationL(iMaxResolution, aMaxDisplayMode); + } + + +EXPORT_C CVeiImageClipGenerator::~CVeiImageClipGenerator() + { + delete iDecodeOperation; + delete iFrameOperation; + delete iDescriptiveName; + delete iBitmap; + delete iMask; + delete iFilename; + } + + +EXPORT_C TPtrC CVeiImageClipGenerator::DescriptiveName() const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + + return *iDescriptiveName; + } + + +EXPORT_C TUid CVeiImageClipGenerator::Uid() const + { + return KUidImageClipGenerator; + } + +EXPORT_C TTimeIntervalMicroSeconds CVeiImageClipGenerator::Duration() const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + + return iDuration; + } + + +EXPORT_C TInt CVeiImageClipGenerator::VideoFrameCount() const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + + TInt frameCount = 0; + + TInt maxFramerate = 10; + if (IsInserted()) + { + maxFramerate = Movie()->MaximumFramerate(); + } + + TTimeIntervalMicroSeconds frameDuration(TInt64(1000000 / maxFramerate)); + if (iDuration.Int64() < (TInt64(KNumberOfTransitionFrames * 2 + 1) * frameDuration.Int64())) + { + frameCount = (static_cast(iDuration.Int64() / frameDuration.Int64())); + if ((iDuration.Int64() % frameDuration.Int64()) != 0) + { + frameCount++; + } + } + else + { + frameCount = KNumberOfTransitionFrames * 2; + TTimeIntervalMicroSeconds middleTime(iDuration.Int64() - (TInt64(KNumberOfTransitionFrames * 2) * frameDuration.Int64())); + frameCount += (static_cast(middleTime.Int64() / KMiddleFrameDuration.Int64())); + if ((middleTime.Int64() % KMiddleFrameDuration.Int64()) != 0) + { + frameCount++; + } + } + return frameCount; + } + + +EXPORT_C TTimeIntervalMicroSeconds CVeiImageClipGenerator::VideoFrameStartTime(TInt aIndex) const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < VideoFrameCount(), TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalVideoFrameIndex)); + + TInt maxFramerate = 10; + if (IsInserted()) + { + maxFramerate = Movie()->MaximumFramerate(); + } + + TTimeIntervalMicroSeconds frameDuration(TInt64(1000000 / maxFramerate)); + TTimeIntervalMicroSeconds finalThreshold(iDuration.Int64() - TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + TTimeIntervalMicroSeconds startThreshold(TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + TTimeIntervalMicroSeconds startTime(-1); + TInt frameCount = VideoFrameCount(); + + + if (frameCount < (KNumberOfTransitionFrames * 2 + 1)) + { + // Special case: less than KNumberOfTransitionFrames frames in the movie + startTime = TTimeIntervalMicroSeconds(TInt64(aIndex) * frameDuration.Int64()); + } + else if (aIndex < KNumberOfTransitionFrames) + { + // Start frames + startTime = TTimeIntervalMicroSeconds(TInt64(aIndex) * frameDuration.Int64()); + } + else if (aIndex >= (frameCount - KNumberOfTransitionFrames)) + { + // End frames + startTime = TTimeIntervalMicroSeconds( + static_cast((aIndex - frameCount) + KNumberOfTransitionFrames) + * frameDuration.Int64() + finalThreshold.Int64() ); + } + else + { + // Middle frames + startTime = TTimeIntervalMicroSeconds(startThreshold.Int64() + + TInt64(aIndex- KNumberOfTransitionFrames) * KMiddleFrameDuration.Int64()); + } + + return startTime; + } + + +EXPORT_C TTimeIntervalMicroSeconds CVeiImageClipGenerator::VideoFrameEndTime(TInt aIndex) const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < VideoFrameCount(), TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalVideoFrameIndex)); + + if (aIndex == VideoFrameCount() - 1) + { + return iDuration; + } + + TInt maxFramerate = 10; + if (IsInserted()) + { + maxFramerate = Movie()->MaximumFramerate(); + } + + TTimeIntervalMicroSeconds frameDuration(TInt64(1000000 / maxFramerate)); + TTimeIntervalMicroSeconds finalThreshold(iDuration.Int64() - TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + TTimeIntervalMicroSeconds startThreshold(TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + TTimeIntervalMicroSeconds endTime(-1); + + + TInt frameCount = VideoFrameCount(); + + if (frameCount < (KNumberOfTransitionFrames * 2 + 1)) + { + // Special case: less than KNumberOfTransitionFrames frames in the movie + endTime = TTimeIntervalMicroSeconds(TInt64(aIndex + 1) * frameDuration.Int64()); + } + else if (aIndex < KNumberOfTransitionFrames) + { + // start frames + endTime = TTimeIntervalMicroSeconds(TInt64(aIndex + 1) * frameDuration.Int64()); + } + else if (aIndex > (frameCount - KNumberOfTransitionFrames)) + { + // end frames + endTime = TTimeIntervalMicroSeconds(TInt64((aIndex - frameCount) + + KNumberOfTransitionFrames) * frameDuration.Int64() + + finalThreshold.Int64()); + } + else + { + // middle frames + endTime = TTimeIntervalMicroSeconds(startThreshold.Int64() + + TInt64(aIndex - (KNumberOfTransitionFrames - 1)) + * KMiddleFrameDuration.Int64()); + + if (endTime.Int64() >= finalThreshold.Int64()) + { + // last of the middle frames may be shorter than normal + endTime = finalThreshold; + } + } + return endTime; + } + + +EXPORT_C TTimeIntervalMicroSeconds CVeiImageClipGenerator::VideoFrameDuration(TInt aIndex) const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < VideoFrameCount(), TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalVideoFrameIndex)); + + + // check maximum framerate + TInt maxFramerate = 10; + if (IsInserted()) + { + maxFramerate = Movie()->MaximumFramerate(); + } + + // calculate some timing values. + TTimeIntervalMicroSeconds frameDuration(TInt64(1000000 / maxFramerate)); + TTimeIntervalMicroSeconds finalThreshold(iDuration.Int64() - TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + TTimeIntervalMicroSeconds startThreshold(TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + + + TInt frameCount = VideoFrameCount(); + TInt finalThresholdIndex = GetVideoFrameIndex(finalThreshold); + + if ((frameCount < (KNumberOfTransitionFrames * 2 + 1)) && (aIndex == (frameCount - 1))) + { + // Special case: short clip with only frames that have max framerate + // - all of the frames are of equal duration (frameDuration) except + // the last one. + frameDuration = TTimeIntervalMicroSeconds(iDuration.Int64() - (TInt64(frameCount - 1) * frameDuration.Int64())); + } + else if (aIndex >= KNumberOfTransitionFrames && aIndex < finalThresholdIndex) + { + if (aIndex == (finalThresholdIndex - 1)) + { + // Last one of the middle frames + frameDuration = TTimeIntervalMicroSeconds(finalThreshold.Int64() - VideoFrameStartTime(aIndex).Int64()); + } + else + { + // Ordinary middle frame + frameDuration = KMiddleFrameDuration; + } + } + return frameDuration; + } + +EXPORT_C TBool CVeiImageClipGenerator::VideoFrameIsIntra(TInt aIndex) const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + if (aIndex == 0) + { + return ETrue; + } + return EFalse; + } + +EXPORT_C TInt CVeiImageClipGenerator::VideoFirstFrameComplexityFactor() const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + return iFirstFrameComplexityFactor; + } + +EXPORT_C TInt CVeiImageClipGenerator::VideoFrameDifferenceFactor(TInt aIndex) const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < VideoFrameCount(), TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalVideoFrameIndex)); + + if (aIndex == 0) + { + return 1000; + } + else + { + return 0; + } + } + + +EXPORT_C TInt CVeiImageClipGenerator::GetVideoFrameIndex(TTimeIntervalMicroSeconds aTime) const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS(aTime.Int64() >= 0, TVedPanic::Panic(TVedPanic::EVideoClipInfoIllegalVideoFrameTime)); + __ASSERT_ALWAYS(aTime.Int64() <= iDuration.Int64(), TVedPanic::Panic(TVedPanic::EVideoClipInfoIllegalVideoFrameTime)); + + TInt index = -1; + + TInt maxFramerate = 10; + if (IsInserted()) + { + maxFramerate = Movie()->MaximumFramerate(); + } + + TTimeIntervalMicroSeconds frameDuration(TInt64(1000000 / maxFramerate)); + TTimeIntervalMicroSeconds finalThreshold( + iDuration.Int64() - TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + TTimeIntervalMicroSeconds startThreshold( + TInt64(KNumberOfTransitionFrames) * frameDuration.Int64()); + + if (iDuration <= (TInt64(KNumberOfTransitionFrames * 2) * frameDuration.Int64())) + { + index = static_cast(aTime.Int64() / frameDuration.Int64()); + } + else if (aTime < startThreshold) + { + index = static_cast(aTime.Int64() / frameDuration.Int64()); + } + else if (aTime >= finalThreshold) + { + TTimeIntervalMicroSeconds middleDuration(finalThreshold.Int64() - startThreshold.Int64()); + TInt numberOfMiddleFrames = + static_cast(middleDuration.Int64() / KMiddleFrameDuration.Int64()); + if (middleDuration.Int64() % KMiddleFrameDuration.Int64() != 0) + { + numberOfMiddleFrames++; + } + + index = KNumberOfTransitionFrames + numberOfMiddleFrames + + static_cast((aTime.Int64() - finalThreshold.Int64()) / frameDuration.Int64()); + } + else + { + index = KNumberOfTransitionFrames + + static_cast((aTime.Int64() - startThreshold.Int64()) / KMiddleFrameDuration.Int64()); + } + + return index; + } + + +EXPORT_C void CVeiImageClipGenerator::GetFrameL(MVedVideoClipGeneratorFrameObserver& aObserver, + TInt aIndex, TSize* const aResolution, + TDisplayMode aDisplayMode, TBool aEnhance, + TInt aPriority) + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS((aIndex >= 0 && aIndex < VideoFrameCount()) || + aIndex == KFrameIndexBestThumb, + TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalVideoFrameIndex)); + __ASSERT_ALWAYS((aResolution->iHeight <= iMaxResolution.iHeight && + aResolution->iWidth <= iMaxResolution.iWidth), + TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalFrameResolution)); + __ASSERT_ALWAYS((aResolution->iHeight >= 0 && aResolution->iWidth >= 0), + TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalFrameResolution)); + + + TDisplayMode displayMode = aDisplayMode; + + // check validity of thumbnail and associated operation + if(aEnhance) // for saving to file + { + if(displayMode == ENone) // if no preference + { + displayMode = EColor16M; // 24-bit color image for enhancement + } + else if(displayMode != EColor16M) // invalid combination + { + User::Leave(KErrNotSupported); + } + } + else // for screen display + { + if(displayMode == ENone) // if no preference + { + displayMode = EColor64K; // 16-bit image + } + } + + CFbsBitmap* destBitmap = new (ELeave) CFbsBitmap; + CleanupStack::PushL(destBitmap); + User::LeaveIfError(destBitmap->Create(*aResolution, displayMode)); + CleanupStack::Pop(destBitmap); + + iFrameOperation->StartOperationL(&aObserver, aIndex, aEnhance, iBitmap, + destBitmap, iMask, aPriority); + } + + +EXPORT_C void CVeiImageClipGenerator::CancelFrame() + { + iFrameOperation->Cancel(); + } + + +EXPORT_C void CVeiImageClipGenerator::SetDuration(const TTimeIntervalMicroSeconds& aDuration) + { + __ASSERT_ALWAYS(iReady || iInitializing, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + __ASSERT_ALWAYS(aDuration.Int64() > 0, + TVedPanic::Panic(TVedPanic::EVideoClipGeneratorIllegalDuration)); + + iDuration = aDuration; + + if (!iInitializing) + { + ReportDurationChanged(); + } + } + + +EXPORT_C void CVeiImageClipGenerator::SetBackgroundColor(const TRgb& aBackgroundColor) + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + + iBackgroundColor = aBackgroundColor; + ReportSettingsChanged(); + } + +EXPORT_C const TRgb& CVeiImageClipGenerator::BackgroundColor() const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + + return iBackgroundColor; + } + +EXPORT_C TPtrC CVeiImageClipGenerator::ImageFilename() const + { + __ASSERT_ALWAYS(iReady, + TVedPanic::Panic(TVedPanic::EImageClipGeneratorNotReady)); + return *iFilename; + } + +void CVeiImageClipGenerator::UpdateFirstFrameComplexityFactorL() + { + iFirstFrameComplexityFactor = CalculateFrameComplexityFactor(iBitmap); + } + +////////////////////////////////////////////////////////////////////////// +// Decode operation +////////////////////////////////////////////////////////////////////////// + + +CVeiImageClipDecodeOperation* CVeiImageClipDecodeOperation::NewL(CVeiImageClipGenerator& aGenerator, + const TDesC& aFilename, + MVeiImageClipGeneratorObserver& aObserver, + RFs& aFs, + TInt aPriority) + { + CVeiImageClipDecodeOperation* self = + new (ELeave) CVeiImageClipDecodeOperation(aGenerator, aObserver, aPriority); + CleanupStack::PushL(self); + self->ConstructL(aFilename, aFs); + CleanupStack::Pop(self); + return self; + } + + +CVeiImageClipDecodeOperation::CVeiImageClipDecodeOperation(CVeiImageClipGenerator& aGenerator, + MVeiImageClipGeneratorObserver& aObserver, + TInt aPriority) + : CActive(aPriority), iGenerator(aGenerator), iObserver(aObserver) + { + CActiveScheduler::Add(this); + } + + +void CVeiImageClipDecodeOperation::ConstructL(const TDesC& aFilename, RFs& aFs) + { + iDecoder = CImageDecoder::FileNewL(aFs, aFilename); + } + + +CVeiImageClipDecodeOperation::~CVeiImageClipDecodeOperation() + { + Cancel(); + + delete iDecoder; + iDecoder = 0; + delete iBitmap; + iBitmap = 0; + delete iMask; + iMask = 0; + } + + +void CVeiImageClipDecodeOperation::DoCancel() + { + if (iDecoder) + { + iDecoder->Cancel(); + } + + delete iDecoder; + iDecoder = 0; + + delete iBitmap; + iBitmap = 0; + + delete iMask; + iMask = 0; + + iObserver.NotifyImageClipGeneratorInitializationComplete(iGenerator, KErrCancel); + } + + +void CVeiImageClipDecodeOperation::RunL() + { + /* Transfer ownership of iBitmap to generator. */ + iGenerator.iBitmap = iBitmap; + iBitmap = 0; + iGenerator.iMask = iMask; + iMask = 0; + iGenerator.iReady = ETrue; + iGenerator.UpdateFirstFrameComplexityFactorL(); + + /* Notify observer. */ + iObserver.NotifyImageClipGeneratorInitializationComplete(iGenerator, KErrNone); + delete iDecoder; + iDecoder = 0; + } + +TInt CVeiImageClipDecodeOperation::RunError(TInt aError) + { + if (iDecoder) + { + iDecoder->Cancel(); + } + delete iDecoder; + iDecoder = 0; + delete iBitmap; + iBitmap = 0; + delete iMask; + iMask = 0; + + iObserver.NotifyImageClipGeneratorInitializationComplete(iGenerator, aError); + return KErrNone; + } + + + +void CVeiImageClipDecodeOperation::StartOperationL(const TSize& aMaxResolution, TDisplayMode aDisplayMode) + { + __ASSERT_ALWAYS(!IsActive(), TVedPanic::Panic(TVedPanic::EInternal)); + + const TFrameInfo& info = iDecoder->FrameInfo(); + TSize targetResolution(0, 0); + const TSize sourceResolution(info.iOverallSizeInPixels); + + /* Calculate resolution. */ + + if ((sourceResolution.iWidth <= aMaxResolution.iWidth) + && (sourceResolution.iHeight <= aMaxResolution.iHeight)) + { + targetResolution.iWidth = sourceResolution.iWidth; + targetResolution.iHeight = sourceResolution.iHeight; + } + else if (info.iFlags & TFrameInfo::EFullyScaleable) + { + if ((sourceResolution.iWidth * aMaxResolution.iHeight) > + (sourceResolution.iHeight * aMaxResolution.iWidth)) + { + targetResolution.iWidth = aMaxResolution.iWidth; + targetResolution.iHeight = + (targetResolution.iWidth * sourceResolution.iHeight) / sourceResolution.iWidth; + } + else + { + targetResolution.iHeight = aMaxResolution.iHeight; + targetResolution.iWidth = + (targetResolution.iHeight * sourceResolution.iWidth) / sourceResolution.iHeight; + } + } + else + { + targetResolution.iWidth = (sourceResolution.iWidth / 8) + 1; + targetResolution.iHeight = (sourceResolution.iHeight / 8) + 1; + + if ((targetResolution.iWidth < aMaxResolution.iWidth) + && (targetResolution.iHeight < aMaxResolution.iHeight)) + { + targetResolution.iWidth = (sourceResolution.iWidth / 4) + 1; + targetResolution.iHeight = (sourceResolution.iHeight / 4) + 1; + } + + if ((targetResolution.iWidth < aMaxResolution.iWidth) + && (targetResolution.iHeight < aMaxResolution.iHeight)) + { + targetResolution.iWidth = (sourceResolution.iWidth / 2) + 1; + targetResolution.iHeight = (sourceResolution.iHeight / 2) + 1; + } + + if ((targetResolution.iWidth < aMaxResolution.iWidth) + && (targetResolution.iHeight < aMaxResolution.iHeight)) + { + targetResolution.iWidth = (sourceResolution.iWidth); + targetResolution.iHeight = (sourceResolution.iHeight); + } + } + + + iBitmap = new (ELeave) CFbsBitmap; + TInt err = iBitmap->Create(targetResolution, aDisplayMode); + + if (err != KErrNone) + { + delete iBitmap; + iBitmap = 0; + iObserver.NotifyImageClipGeneratorInitializationComplete(iGenerator, err); + return; + } + + if (info.iFlags & TFrameInfo::ETransparencyPossible) + { + iMask = new (ELeave) CFbsBitmap; + if (info.iFlags & TFrameInfo::EAlphaChannel) + { + err = iMask->Create(targetResolution, EGray256); + } + else + { + err = iMask->Create(targetResolution, EGray2); + } + } + + if (err != KErrNone) + { + delete iBitmap; + iBitmap = 0; + delete iMask; + iMask = 0; + iObserver.NotifyImageClipGeneratorInitializationComplete(iGenerator, err); + return; + } + + if (iMask != 0) + { + iDecoder->Convert(&iStatus, *iBitmap, *iMask); + } + else + { + iDecoder->Convert(&iStatus, *iBitmap); + } + + SetActive(); + } + + +////////////////////////////////////////////////////////////////////////// +// Frame operation +////////////////////////////////////////////////////////////////////////// + +CVeiImageClipFrameOperation* CVeiImageClipFrameOperation::NewL(CVeiImageClipGenerator& aGenerator) + { + CVeiImageClipFrameOperation* self = + new (ELeave) CVeiImageClipFrameOperation(aGenerator); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + + +CVeiImageClipFrameOperation::CVeiImageClipFrameOperation(CVeiImageClipGenerator& aGenerator) + : CActive(EPriorityStandard), iGenerator(aGenerator) + { + CActiveScheduler::Add(this); + } + + +void CVeiImageClipFrameOperation::ConstructL() + { + } + + +CVeiImageClipFrameOperation::~CVeiImageClipFrameOperation() + { + Cancel(); + delete iScaler; + iScaler = 0; + delete iDestBitmap; + iDestBitmap = 0; + delete iScaledBitmap; + iScaledBitmap = 0; + delete iScaledMask; + iScaledMask = 0; + + iSourceBitmap = 0; + iSourceMask = 0; + iObserver = 0; + } + + +void CVeiImageClipFrameOperation::StartOperationL(MVedVideoClipGeneratorFrameObserver* aObserver, + TInt aIndex, TBool aEnhance, + CFbsBitmap* aSourceBitmap, CFbsBitmap* aDestBitmap, + CFbsBitmap* aSourceMask, TInt aPriority) + { + __ASSERT_ALWAYS(!IsActive(), TVedPanic::Panic(TVedPanic::EImageClipGeneratorFrameOperationAlreadyRunning)); + + iObserver = aObserver; + iSourceBitmap = aSourceBitmap; + iDestBitmap = aDestBitmap; + iSourceMask = aSourceMask; + iIndex = aIndex; + iEnhance = aEnhance; + + SetPriority(aPriority); + + + TSize sourceRes = iSourceBitmap->SizeInPixels(); + TSize destRes = iDestBitmap->SizeInPixels(); + TSize movieRes = iGenerator.Movie()->Resolution(); + + TSize imageResInMovie(0,0); + if ((sourceRes.iWidth >= movieRes.iWidth) || (sourceRes.iHeight >= movieRes.iHeight)) + { + // Downscaling + if ((sourceRes.iWidth * movieRes.iHeight) > + (sourceRes.iHeight * movieRes.iWidth)) + { + imageResInMovie.iWidth = movieRes.iWidth; + imageResInMovie.iHeight = + (movieRes.iWidth * sourceRes.iHeight) / sourceRes.iWidth; + } + else + { + imageResInMovie.iHeight = movieRes.iHeight; + imageResInMovie.iWidth = + (movieRes.iHeight * sourceRes.iWidth) / sourceRes.iHeight; + } + } + else + { + // Upscaling - limit to a factor of two + if ((sourceRes.iWidth * movieRes.iHeight) > + (sourceRes.iHeight * movieRes.iWidth)) + { + imageResInMovie.iWidth = Min(movieRes.iWidth, (sourceRes.iWidth * 2)); + imageResInMovie.iHeight = (imageResInMovie.iWidth * sourceRes.iHeight) / sourceRes.iWidth; + } + else + { + imageResInMovie.iHeight = Min((sourceRes.iHeight * 2), movieRes.iHeight); + imageResInMovie.iWidth = (imageResInMovie.iHeight * sourceRes.iWidth) / sourceRes.iHeight; + } + } + + TSize movieResInDestBitmap(-1,-1); + if ((movieRes.iWidth * destRes.iHeight) > + (movieRes.iHeight * destRes.iWidth)) + { + movieResInDestBitmap.iWidth = destRes.iWidth; + movieResInDestBitmap.iHeight = + (movieResInDestBitmap.iWidth * movieRes.iHeight) / movieRes.iWidth; + } + else + { + movieResInDestBitmap.iHeight = destRes.iHeight; + movieResInDestBitmap.iWidth = + (movieResInDestBitmap.iHeight * movieRes.iWidth) / movieRes.iHeight; + } + + + TSize targetRes(imageResInMovie); + targetRes.iWidth = imageResInMovie.iWidth * movieResInDestBitmap.iWidth / movieRes.iWidth; + targetRes.iHeight = imageResInMovie.iHeight * movieResInDestBitmap.iHeight / movieRes.iHeight; + + TSize cachedRes(-1, -1); + if (iScaledBitmap) + { + cachedRes = iScaledBitmap->SizeInPixels(); + } + + /* Check if we already have scaled this bitmap.*/ + if ((cachedRes.iWidth == targetRes.iWidth) || + (cachedRes.iHeight == targetRes.iHeight)) + { + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + return; + } + else if (iScaledBitmap) + { + delete iScaledBitmap; + iScaledBitmap = 0; + delete iScaledMask; + iScaledMask = 0; + } + + delete iScaler; + iScaler = NULL; + iScaler = CBitmapScaler::NewL(); + + iScaledBitmap = new (ELeave) CFbsBitmap; + User::LeaveIfError(iScaledBitmap->Create(targetRes, iDestBitmap->DisplayMode())); + iScaler->Scale(&iStatus, *iSourceBitmap, *iScaledBitmap, ETrue); + SetActive(); + } + + + +void CVeiImageClipFrameOperation::RunL() + { + if (!iNoScaling && iSourceMask && !iScaledMask) + { + /* Scale the mask. */ + iScaledMask = new (ELeave) CFbsBitmap; + User::LeaveIfError(iScaledMask->Create(iScaledBitmap->SizeInPixels(), iSourceMask->DisplayMode())); + iScaler->Scale(&iStatus, *iSourceMask, *iScaledMask, ETrue); + SetActive(); + return; + } + + /* Select source. */ + CFbsBitmap* bitmap = 0; + CFbsBitmap* mask = 0; + + if (iScaledBitmap) + { + bitmap = iScaledBitmap; + } + else + { + bitmap = iSourceBitmap; + } + + if (iScaledMask) + { + mask = iScaledMask; + } + else + { + mask = iSourceMask; + } + + + /* Initialize context. */ + CFbsDevice* device = CFbsBitmapDevice::NewL(iDestBitmap); + CleanupStack::PushL(device); + CFbsBitGc* gc = NULL; + User::LeaveIfError(device->CreateContext(gc)); + + /* Calculate source point. */ + TSize destRes = iDestBitmap->SizeInPixels(); + TSize sourceRes = bitmap->SizeInPixels(); + TPoint sourcePoint((destRes.iWidth - sourceRes.iWidth) / 2, + (destRes.iHeight - sourceRes.iHeight) / 2); + + /* Draw background (this is relevant for scaled images and transparency). */ + gc->SetBrushColor(iGenerator.BackgroundColor()); + gc->SetBrushStyle(CGraphicsContext::ESolidBrush); + gc->DrawRect(TRect(TPoint(0, 0), destRes)); + + if (mask) + { + TRect sourceRect(bitmap->SizeInPixels()); + gc->BitBltMasked(sourcePoint, bitmap, sourceRect, mask, EFalse); + } + else + { + gc->BitBlt(sourcePoint, bitmap); + } + + delete gc; + CleanupStack::PopAndDestroy(device); + + /* This transfers the bitmap ownership to the observer. */ + iObserver->NotifyVideoClipGeneratorFrameCompleted(iGenerator, KErrNone, iDestBitmap); + + delete iScaler; + iScaler = 0; + + iSourceBitmap = 0; + iSourceMask = 0; + iDestBitmap = 0; + iObserver = 0; + iIndex = -1; + iNoScaling = EFalse; + } + +TInt CVeiImageClipFrameOperation::RunError(TInt aError) + { + iObserver->NotifyVideoClipGeneratorFrameCompleted(iGenerator, aError, NULL); + + if (iScaler) + { + iScaler->Cancel(); + } + + delete iScaler; + iScaler = 0; + delete iScaledBitmap; + iScaledBitmap = 0; + delete iScaledMask; + iScaledMask = 0; + delete iDestBitmap; + iDestBitmap = 0; + iSourceBitmap = 0; + iSourceMask = 0; + iObserver = 0; + iIndex = -1; + + return KErrNone; + } + + +void CVeiImageClipFrameOperation::DoCancel() + { + iObserver->NotifyVideoClipGeneratorFrameCompleted(iGenerator, KErrCancel, 0); + + if (iScaler) + { + iScaler->Cancel(); + } + + delete iScaler; + iScaler = 0; + delete iScaledBitmap; + iScaledBitmap = 0; + delete iScaledMask; + iScaledMask = 0; + + delete iDestBitmap; + iDestBitmap = 0; + iSourceBitmap = 0; + iSourceMask = 0; + iObserver = 0; + iIndex = -1; + } +// End of File +