camappengine/Engine/Src/CaeStillStatesActive.cpp
changeset 0 9b3e960ffc8a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/camappengine/Engine/Src/CaeStillStatesActive.cpp	Thu Dec 17 08:51:24 2009 +0200
@@ -0,0 +1,2144 @@
+/*
+* Copyright (c) 2005 - 2007 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:  Still capture state machine implementation class
+*
+*/
+
+
+// INCLUDE FILES
+#include <hal.h>                    // For getting the display mode
+#include <ExifRead.h>
+#include "CaeStillStatesActive.h"
+#include "CaeImageQueueExtPro.h"
+
+#ifdef CAE_TEST_VERSION
+#include "CaeEngineImpTestErrors.h" // For TEST_VERSION compilation only
+#endif
+
+#include "OstTraceDefinitions.h"
+#ifdef OST_TRACE_COMPILER_IN_USE
+#include "CaeStillStatesActiveTraces.h"
+#endif
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::CCaeStillStatesActive()
+// C++ constructor.
+// Adds the object to the Active Scheduler.
+// ---------------------------------------------------------------------------
+//
+CCaeStillStatesActive::CCaeStillStatesActive( 
+    CCamera& aCamera,
+    const TCamAppEngineInfo& aInfo,
+    RArray<TCaeExtensionInterfaceImplItem>& aProcessImageImplList )
+    : CActive( EPriorityStandard ), 
+      iCamera( aCamera ),
+      iInfo( aInfo ),
+      iProcessImageImplList( aProcessImageImplList ),
+      iStillInputFormat( CCamera::EFormatFbsBitmapColor16M ), 
+      iStillOutputFormat( CCamera::EFormatFbsBitmapColor16M ), 
+      iStillCompressionQuality( KCaeDefaultCompressionQuality ),
+      iCurrentExtensionIndex( -1 )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::~CCaeStillStatesActive()
+// Destructor. 
+// Cancels operation and closes the timer.
+// ---------------------------------------------------------------------------
+//
+CCaeStillStatesActive::~CCaeStillStatesActive()
+    {
+    Cancel();
+
+    iDelayedCallTimer.Close();
+    
+    DeleteStillBurst(); // Using this removes dependency to still burst class
+
+    CancelAndCleanup();
+
+    // Check that extensions handle flag registration properly
+    CAE_ASSERT_DEBUG( iRequireFullColorSnapInputImageRefCount == 0 );
+
+    delete iEmptySnapImage;
+
+    delete iStillDecoder;
+    delete iStillEncoder;
+
+	delete iSnapBitmap;
+	delete iBitmap;
+	delete iImageData;
+	delete iImageHeaderData;
+    delete iImageQueueExtPro;
+    iFs.Close();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::NewL()
+// Symbian OS two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CCaeStillStatesActive* CCaeStillStatesActive::NewL( 
+    CCamera& aCamera,
+    const TCamAppEngineInfo& aInfo,
+    RArray<TCaeExtensionInterfaceImplItem>& aProcessImageImplList )
+    {
+    CCaeStillStatesActive* self = new( ELeave ) CCaeStillStatesActive( aCamera, aInfo, 
+        aProcessImageImplList );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::ConstructL()
+// Symbian OS 2nd phase constructor that can leave.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::ConstructL()
+    {
+    // Get native screen mode. This can be used as default mode for the snap bitmap.
+    iSnapImageColorMode = KCaeDefaultDisplayMode;
+    (void)GetSystemDisplayMode( iSnapImageColorMode );
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::ConstructL(). Use display mode %d for the snap image" ), iSnapImageColorMode );
+
+    // Create still image encoder object, e.g. for JPEG encoding.
+    iStillEncoder = CCaeStillEncoder::NewL();
+    iStillEncoder->SetObserver( this );
+
+    // Create still image decoder object, e.g. for JPEG decoding.
+    iStillDecoder = CCaeStillDecoder::NewL();
+    iStillDecoder->SetObserver( this );
+
+    // This empty snap image is currently used just for error cases.
+    iEmptySnapImage = new( ELeave ) CFbsBitmap;
+
+    // Create timer 
+    iDelayedCallTimer.CreateLocal();
+    
+    // Connect to file server.
+    User::LeaveIfError( iFs.Connect() );
+
+    // Start in normal mode    
+  	iExtModeActive = EFalse;
+    iStillPrepared = EFalse;
+    
+    // Burst mode VF stopping optimization is not used as default
+    iBurstModeVFOptimization = EFalse;
+
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::GetSystemDisplayMode()
+// In some devices Hal:Get(HAL::EDisplayMode) returns directly TDisplayMode, 
+// in other devices it returns a display mode index.
+// ---------------------------------------------------------------------------
+//
+TBool CCaeStillStatesActive::GetSystemDisplayMode( TDisplayMode& aDisplayMode )
+    {
+    TBool found = EFalse;
+    TInt halInOut = 0;
+    TInt err = HAL::Get( HAL::EDisplayMode, halInOut );
+    if (  err == KErrNone )
+        {       
+        if ( halInOut >= EColor256)
+            {
+            // halInOut contains TDisplayMode
+            aDisplayMode = (TDisplayMode) halInOut;
+            found = ETrue;
+            LOGTEXT( _L( "Cae: CCaeStillStatesActive::GetSystemDisplayMode(). HAL returned a display mode." ) );
+            }
+        else
+            {
+             // halInOut contains index
+           LOGTEXT( _L( "Cae: CCaeStillStatesActive::GetSystemDisplayMode(). HAL returned index." ) );
+            err = HAL::Get( HAL::EDisplayBitsPerPixel, halInOut );
+            
+            // Get the color mode. Note: grayscale modes are not supported. 
+            if (  err == KErrNone )
+                {
+				switch (halInOut)
+					{
+				    case 4:
+					    aDisplayMode = EColor16;
+                        found = ETrue;
+                        break;
+			    	case 8:
+					    aDisplayMode = EColor256;
+                        found = ETrue;
+                        break;
+				    case 12:
+				    	aDisplayMode = EColor4K;
+                        found = ETrue;
+                        break;
+				    case 16:
+					    aDisplayMode = EColor64K;
+                        found = ETrue;
+                        break;
+				    case 24:
+					    aDisplayMode = EColor16M;
+                        found = ETrue;
+                        break;
+			    	case 32:
+					    aDisplayMode = EColor16MU;
+                        found = ETrue;
+                        break;
+				    default:
+					    break;
+					}
+                }
+            }
+        } 
+
+    #ifdef _DEBUG
+    if ( err || !found )
+        {
+        TBuf<256> text;
+        text.Format(_L( "Cae: CCaeStillStatesActive::GetSystemDisplayMode(). Cannot get the display mode from HW. Err:%d, found:%d" ), err, found );
+        LOGTEXT( text );        
+        }
+    else
+        {   
+        LOGTEXT2( _L( "Cae: CCaeStillStatesActive::GetSystemDisplayMode(). Found the display mode:%d" ), aDisplayMode );
+        }
+    #endif
+
+    if ( found && !err && aDisplayMode == EColor16MA )
+        {
+        aDisplayMode = EColor16MU;
+        LOGTEXT2( _L( "Cae: CCaeStillStatesActive::GetSystemDisplayMode(). Display mode EColor16MA changed to EColor16MU (%d)" ), aDisplayMode );
+        }
+
+    return found;   
+    }
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::SetCamAppEngineObserver()
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetCamAppEngineObserver( MCamAppEngineObserver& aObserver )
+    {
+    iCaeObserver = &aObserver;    
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetSnapImageCreation()
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetSnapImageCreation( 
+    TBool aCreateSnapImage )
+    {
+    iCreateSnapImage = aCreateSnapImage;
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetSnapImageSourceL()
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetSnapImageSourceL( 
+    CCaeEngine::TSnapImageSource aSnapImageSource )
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::SetSnapImageSourceL(). aSnapImageSource=%d" ), aSnapImageSource );
+    if ( ( aSnapImageSource < 0 ) || 
+         ( aSnapImageSource > CCaeEngine::ESnapImageSourceThumbnail ) )
+        {
+        LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetSnapImageSourceL(). leaving KErrNotSupported" ));
+        User::Leave( KErrNotSupported );
+        }
+
+    iSnapImageSource = aSnapImageSource;
+    }
+
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetSnapImageSizeL()
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetSnapImageSizeL( 
+    TSize& aSize )
+    {
+    LOGTEXT3( _L( "Cae: CCaeStillStatesActive::SetSnapImageSizeL(). iWidth=%d, iHeight=%d" ), aSize.iWidth, aSize.iHeight );
+	// Calc downscaled size.
+    // Use always the default snap size for the snap image. It is the best compromise 
+    // between memory usage and image quality.
+    TSize stepwiseScaledOptimalSize( KCaeDefaultSnapWidth, KCaeDefaultSnapHeight);
+    CalcDownscaledSnapSize( stepwiseScaledOptimalSize ); 
+
+    // Empty calculated size means that PrepareStillCapture() has not been called.
+    if ( stepwiseScaledOptimalSize == TSize() ) 
+        {
+        LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetSnapImageSizeL(). leaving KErrNotReady (no prepare)" ));
+		User::Leave( KErrNotReady ); 
+        }
+    else
+        {
+        iOptimalSnapImageSize = stepwiseScaledOptimalSize;
+        // If empty, use the still image size
+        if ( aSize == TSize() )
+            {
+            aSize = iStillFrameSize;
+            }
+        iSnapImageSize = aSize;
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SnapImageSize
+// -----------------------------------------------------------------------------
+TSize CCaeStillStatesActive::SnapImageSize() const
+    {
+    return( iSnapImageSize );
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::StillImageSize
+// -----------------------------------------------------------------------------
+TSize CCaeStillStatesActive::StillImageSize() const
+    {
+    return( iStillFrameSize );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetSnapImageColorMode
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetSnapImageColorMode( 
+    TDisplayMode aMode )
+    {
+    iSnapImageColorMode = aMode;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetJpegQuality
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetJpegQuality(
+    TInt aQuality )
+    {
+    iStillCompressionQuality = aQuality;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::JpegQuality
+// -----------------------------------------------------------------------------
+//
+TInt CCaeStillStatesActive::JpegQuality() const
+    {
+    return( iStillCompressionQuality );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetImageCodecsL
+// Sets the specific image codec implementation to be used in decoding and 
+// encoding.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetImageCodecsL( 
+	TUid aDecoderUid, TUid aEncoderUid )
+    {
+    iStillEncoder->SetImageCodecL( aEncoderUid );
+    iStillDecoder->SetImageCodecL( aDecoderUid );
+    }
+
+        
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetViewFinderMode
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetViewFinderMode(
+    TBool aIsEnabled )
+    {
+    iIsViewFinderEnabled = aIsEnabled;
+
+    // Issue event, if the view finder is stopped, and the state machine is 
+    // waiting for it. Do not issue the same event twice (it will panic).
+    if ( !iIsViewFinderEnabled 
+         && ( iCurrentState == CCaeStillStatesActive::ECaeStateBurstWaitingForViewFinder ) 
+         && !( IsActive() && ( iStatus == CCaeStillStatesActive::ECaeEventViewFinderForBurstReady ) ) )
+        {
+        Event( CCaeStillStatesActive::ECaeEventViewFinderForBurstReady );        
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::IsRunning
+// Check if the state is other than ECaeStateNone.
+// -----------------------------------------------------------------------------
+//
+TBool CCaeStillStatesActive::IsRunning() const
+    {
+    return( iCurrentState != CCaeStillStatesActive::ECaeStateNone );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeEngineImp::RegisterFlags
+// Increment reference counters.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::RegisterFlags( TUint32 aFlags )
+	{
+    if ( aFlags & ECaeExtFlagRequireFullColorSnapInputImage )
+        { 
+        CAE_ASSERT_DEBUG( iRequireFullColorSnapInputImageRefCount < KMaxTInt32 );
+        if ( iRequireFullColorSnapInputImageRefCount < KMaxTInt32 )
+            {
+            iRequireFullColorSnapInputImageRefCount++;
+            }
+        }
+	}
+
+
+// -----------------------------------------------------------------------------
+// CCaeEngineImp::DeregisterFlags
+// Decrement reference counters.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DeregisterFlags( TUint32 aFlags )
+    {
+    if ( aFlags & ECaeExtFlagRequireFullColorSnapInputImage )
+        {
+        CAE_ASSERT_DEBUG( iRequireFullColorSnapInputImageRefCount > 0 );
+        if ( iRequireFullColorSnapInputImageRefCount > 0 )
+            {
+            iRequireFullColorSnapInputImageRefCount--;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::PrepareStillCaptureL
+// Using cropping only if supported by Camera API impl.
+// Calls RetrieveStillSizeIndex() that calls Camera API EnumerateCaptureSizes().
+// Calls Camera API PrepareImageCaptureL().
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::PrepareStillCaptureL( 
+    const TSize&      aFrameSize, 
+    CCamera::TFormat  aFormat, 
+    const TRect&      aCropRect,
+    TSize&            aSnapSize )
+    {
+    LOGTEXT3( _L( "Cae: CCaeStillStatesActive::PrepareStillCaptureL() entering aFrameSize=(w=%d,h=%d)" ), aFrameSize.iWidth, aFrameSize.iHeight );
+
+    // Handle empty crop rect
+    TRect cropRect( aCropRect );
+    if ( cropRect.IsEmpty() )
+        cropRect = TRect(TPoint(0, 0 ), aFrameSize);
+
+    CCamera::TFormat stillOutputFormat = aFormat;
+    CCamera::TFormat stillInputFormat = aFormat;
+
+    // Try if this size and format is supported by the Camera API.
+    TInt sizeIndex = RetrieveStillSizeIndex( aFrameSize, aFormat );
+    if ( sizeIndex != -1 )
+        {
+        stillInputFormat = aFormat;
+        }
+    // If the application requires Jpeg we can encode it from bitmap
+    else if ( aFormat == CCamera::EFormatJpeg )
+        {
+        // Try if this size and format KBaseStillInputFormat1 
+        // is supported by the Camera API.
+        stillInputFormat = KBaseStillInputFormat1;
+        sizeIndex = RetrieveStillSizeIndex( aFrameSize, stillInputFormat );
+        if ( sizeIndex == -1 )
+            {
+            // Try if this size and format KBaseStillInputFormat2 
+            // is supported by the Camera API.
+            stillInputFormat = KBaseStillInputFormat2;
+            sizeIndex = RetrieveStillSizeIndex( aFrameSize, stillInputFormat );
+            if ( sizeIndex == -1 )
+                {
+                LOGTEXT2( _L( "Cae: CCaeStillStatesActive::PrepareStillCaptureL() leaving KErrNotSupported, stillInputFormat=%d" ), stillInputFormat );
+                User::Leave( KErrNotSupported );
+                }
+            }
+        }
+    else 
+        {
+        LOGTEXT2( _L( "Cae: CCaeStillStatesActive::PrepareStillCaptureL() leaving KErrNotSupported, aFormat=%d" ), aFormat );
+        User::Leave( KErrNotSupported );
+        }
+
+    // Prepare still image capturing on Camera API.
+    if ( !( iInfo.iOptionsSupported & TCameraInfo::EImageClippingSupported ) ) 
+        {
+        iCamera.PrepareImageCaptureL( stillInputFormat, sizeIndex );
+        }
+    else 
+        {
+        iCamera.PrepareImageCaptureL( stillInputFormat, sizeIndex, cropRect );
+        }
+
+    // Store values 
+    iStillFrameSize = aFrameSize;
+    iStillInputFormat = stillInputFormat;
+    iStillOutputFormat = stillOutputFormat;
+
+    // Calc downscaled size if needed
+    SetSnapImageSizeL( aSnapSize );     
+    
+    // Prepare done
+    iStillPrepared = ETrue;
+    
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::PrepareStillCaptureL() returning" ) );    
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::RetrieveStillSizeIndex
+// Retrieves/fetches still image size index from Camera API.
+// -----------------------------------------------------------------------------
+//
+TInt CCaeStillStatesActive::RetrieveStillSizeIndex( 
+    const TSize& aFrameSize, 
+    CCamera::TFormat aStillDataFormat ) const
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::RetrieveStillSizeIndex() entering" ) );
+
+    TInt index( -1 );
+    TInt i( 0 );
+    TSize size;
+    while ( ( i < iInfo.iNumImageSizesSupported ) && ( index == -1 ) )
+        {
+        iCamera.EnumerateCaptureSizes ( size, i, aStillDataFormat );
+        if ( size == aFrameSize )
+            {
+            index = i;
+            }
+        i++;
+        }
+
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::RetrieveStillSizeIndex() returning" ) );
+
+    return index;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::CalcDownscaledSnapSize
+// Calc suitable downscaled snap size. Assumed that integer arithmetic is used 
+// also in CImageDecoder class for calculating image scaling to 1/2, 1/4 or 1/8 
+// of size (i.e. no rounding). The scaled snap size is not allowed to be smaller
+// than given snap size in any dimension. Do not do downscaling if aSnapSize is 
+// empty.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::CalcDownscaledSnapSize(
+    TSize& aSnapSize) const
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::CalcDownscaledSnapSize() entering" ) );    
+
+    // The new snap image size is equal to frame size by default
+    TSize newSnapSize = iStillFrameSize;
+
+    // Calculate downscaled snap size
+    if ( aSnapSize != TSize( 0, 0 ) 
+        && ( ( iStillInputFormat == CCamera::EFormatExif ) || 
+             ( iStillInputFormat == CCamera::EFormatJpeg )   ) )
+        {
+        // Try scaling to 1/8, 1/4 and 1/2
+        for  ( TInt divider = 8; divider >= 2;  divider /= 2 ) 
+            {
+            TInt scaledWidth = iStillFrameSize.iWidth / divider;
+            TInt scaledHeight = iStillFrameSize.iHeight / divider;
+            if ( scaledHeight >= aSnapSize.iHeight && scaledWidth >= aSnapSize.iWidth ) 
+                {
+                newSnapSize = TSize( scaledWidth, scaledHeight );
+                divider = -1; // exit loop
+                }
+            }
+        }
+
+    // Return new size
+    aSnapSize = newSnapSize;
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::CalcDownscaledSnapSize() returning" ) );    
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::GetThumbnailL()
+// Extracts thumbnail image and its size from Exif image.
+// Uses Exif reader to extract the thumbnail and 
+// ICL decoder to extract the size.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::GetThumbnailL( 
+    HBufC8*& aReadThumbnail, 
+    TSize&   aThumbnailSize )
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::GetThumbnailL()" ) );    
+
+    if ( iImageData && ( iStillOutputFormat == CCamera::EFormatExif ) )
+        {
+        // Instantiate exif reader.
+        CExifRead* read = NULL;
+        read = CExifRead::NewL( *iImageData );
+        CleanupStack::PushL( read );
+        
+        // Get thumbnail.
+        aReadThumbnail = read->GetThumbnailL();
+        CleanupStack::PopAndDestroy( read );
+        
+        // Find out thumbnail size by using ICL decoder.
+        // Check first that the size is valid.
+        CImageDecoder* decoder = CImageDecoder::DataNewL( iFs, *aReadThumbnail ); 
+        TFrameInfo frameInfo = decoder->FrameInfo();
+        delete decoder;
+
+        if ( frameInfo.iOverallSizeInPixels.iWidth > 0 && 
+             frameInfo.iOverallSizeInPixels.iHeight > 0 )
+            {
+            aThumbnailSize = frameInfo.iOverallSizeInPixels;
+            LOGTEXT3( _L( "Cae: CCaeStillStatesActive::GetThumbnailL(): extracted %dx%d thumbnail" ), 
+                aThumbnailSize.iWidth, aThumbnailSize.iHeight );
+            }
+        else
+            {
+            LOGTEXT3(_L("Cae: CCaeStillStatesActive::GetThumbnailL(): leaving KErrCorrupt due invalid thumbnail size=(w=%d,h=%d)"), 
+                frameInfo.iOverallSizeInPixels.iWidth, frameInfo.iOverallSizeInPixels.iHeight );
+            delete aReadThumbnail;
+            aReadThumbnail = NULL;
+            aThumbnailSize = TSize( 0, 0 );
+            User::Leave( KErrCorrupt );
+            }
+        }
+    else if ( iImageData && ( iStillOutputFormat != CCamera::EFormatExif ) )
+        {
+        // we can't get the thumbnail from exif header if the exif header doesn't exist
+        LOGTEXT( _L( "Cae: CCaeStillStatesActive::GetThumbnailL() leaving because iStillOutputFormat is not EFormatExif" ) );
+        User::Leave( KErrNotFound );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::IsBitmapOutput()
+// ---------------------------------------------------------------------------
+//
+TBool CCaeStillStatesActive::IsBitmapOutput()
+    {
+    return ( !( ( iStillOutputFormat == CCamera::EFormatJpeg ) 
+              || ( iStillOutputFormat == CCamera::EFormatExif ) ) );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::Event()
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::Event( TCaeEvent aEvent, TTimeIntervalMicroSeconds32 aDelay )
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::Event(). aEvent=%d" ), aEvent );
+    CAE_ASSERT_ALWAYS( !IsActive() );
+
+    iDelayedEvent = CCaeStillStatesActive::ECaeEventNone;
+
+    if ( aEvent != CCaeStillStatesActive::ECaeEventEnd )
+        {
+        if ( aDelay == TTimeIntervalMicroSeconds32( 0 ) )
+            {
+            // Issue request
+            TRequestStatus* statusPtr = &iStatus;
+            User::RequestComplete( statusPtr, aEvent );
+            }
+        else
+            {
+            // Use delayed request
+            iDelayedCallTimer.After( iStatus, aDelay );
+            iDelayedEvent = aEvent;
+            }
+    	SetActive();
+        }
+    else
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateNone; // The end
+        if ( ExtModeActive() )
+            {
+            // If there are no images in the queue, then extension processing is ended
+            TInt count = iImageQueueExtPro->ImageCount();
+            if ( count > 0 )
+                {  // Continue and read next image from the queue
+                Event( CCaeStillStatesActive::ECaeEventImageQueueExtPro );
+                }
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::CancelCaptureStill()
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::CancelCaptureStill()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::CancelCaptureStill()" ) );
+
+    if ( !ExtModeActive() ) // in extension mode capture/cancelling is not possible
+        {
+        iStillCancelled = ETrue;
+        Cancel();
+        CancelAndCleanup();
+        }
+
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::Cancel()
+// Calls the base class Cancel().
+// As calling this is not allowed outside this class, this is a private method
+// and it overrides CActive::Cancel(). 
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::Cancel()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::Cancel()" ) );
+    CActive::Cancel();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::DoCancel()
+// Cancel all pending actions. This does not cancel actions that use callback
+// for signaling for completion, e.g. image encoding and decoding.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoCancel()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCancel()" ) );
+    if ( iStatus == KRequestPending )
+        {
+        if ( ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage )
+             || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage ) 
+             || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage ) )
+            {
+            // Cancel extension processing            
+            CAE_ASSERT_ALWAYS( iCurrentExtensionIndex != -1 );
+            TAny* interfacePtr = iProcessImageImplList[iCurrentExtensionIndex].iImplPtr;
+	        STATIC_CAST( MCaeExtProcessImageInterface*, interfacePtr )->CaeExtensionCancel();   
+            }
+        else if ( iDelayedEvent != CCaeStillStatesActive::ECaeEventNone )
+            {
+            // Cancel timer
+            iDelayedCallTimer.Cancel();
+            iDelayedEvent = CCaeStillStatesActive::ECaeEventNone;
+            }
+        else
+            {
+            User::Panic( KCaePanicText, ECaePanicInvalidState );
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ErrorRecovery
+//
+// For still capture recovery: Delete images, cancel and cleanup. Client 
+// callbacks should be called also in error cases, except when user has 
+// cancelled the action. 
+//
+// Burst case is handled differently in BurstErrorRecovery().
+//
+// Note: If ownership is transferred, the image pointers should be NULLed before
+// calling the observer method. That is because the observer method can call back
+// CancelStill() which tries to delete images. That is no allowed if an image 
+// should be owned by the observer.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::ErrorRecovery( TInt aError )
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::ErrorRecovery(): %d" ), aError );
+
+    // Check if snap image callback should be called. Do not call it twice.
+
+    if ( ( iCurrentState <= CCaeStillStatesActive::ECaeStateDeliveringSnapImage ) // Callback not yet called
+         && !iStillCancelled 
+         && iCreateSnapImage ) 
+        {
+        if ( iCurrentState == CCaeStillStatesActive::ECaeStateDecodingCapturedImageToBitmap ) 
+            {
+            // Give decoded image to the client even if there is decoding error
+            iCaeObserver->McaeoSnapImageReady( *iBitmap, aError );
+
+            // Not needed any more. Delete now to free memory.
+            delete iBitmap;
+            iBitmap = NULL;
+            }
+        else
+            {
+            // Give empty snap image to the client
+            iCaeObserver->McaeoSnapImageReady( *iEmptySnapImage, aError );
+            }
+        }
+
+    // Check if still image callback should be called. Do not call it twice.
+
+    if ( ( iCurrentState <= CCaeStillStatesActive::ECaeStateDeliveringStillImage ) // Callback not yet called
+         && !iStillCancelled )
+        {
+        if ( iCurrentState == CCaeStillStatesActive::ECaeStateDecodingCapturedImageToBitmap ) 
+            {
+            // Give original image to the client even if there is decoding error.
+            HBufC8* tmpImageData = iImageData;   
+            iImageData = NULL; 
+            iCaeObserver->McaeoStillImageReady( NULL, tmpImageData, aError );
+            }
+        else if ( iCurrentState == CCaeStillStatesActive::ECaeStateEncodingToJpeg )
+            {
+            // Give original image to the client even if there is encoding error
+            HBufC8* tmpImageData = iImageData;   
+            iImageData = NULL; // Ownership tranferred
+            iCaeObserver->McaeoStillImageReady( NULL, tmpImageData, aError );            
+            }
+        else
+            {
+            // Give error to the client
+            iCaeObserver->McaeoStillImageReady( NULL, NULL, aError );
+            }
+
+        // In burst case, increment delivery counter. 
+        if ( iStillBurst )
+            {
+            iCountOfDeliveredBurstImages++;
+            }
+        }
+
+    if ( !iStillCancelled )
+        {
+        // Handle still burst
+        if ( iStillBurst )
+            {
+            BurstErrorRecovery( aError );
+            }
+        else
+            {
+            Cancel();
+            CancelAndCleanup();
+            }  
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::CancelAndCleanup
+// Cancel all actions and free resources.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::CancelAndCleanup()
+    {
+    iDelayedEvent = CCaeStillStatesActive::ECaeEventNone;
+
+    CompleteStillBurst();
+
+    if ( iStillEncoder )
+        {
+        iStillEncoder->Cancel();
+        iStillEncoder->Cleanup(); 
+        }
+
+    if ( iStillDecoder )
+        {
+        iStillDecoder->Cancel();
+        iStillDecoder->Cleanup();
+        }    
+
+    // Delete all that is not NULL already. 
+    delete iSnapBitmap;
+    iSnapBitmap = NULL;
+    delete iBitmap;
+    iBitmap = NULL;
+    delete iImageData;
+    iImageData = NULL;
+    delete iImageHeaderData;
+    iImageHeaderData = NULL;
+    if ( iImageQueueExtPro )
+        {
+        iImageQueueExtPro->ResetAndDestroyImages();
+        }    
+
+    iCurrentState = CCaeStillStatesActive::ECaeStateNone;   
+    }
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::RunL()
+// The main function that receives all events. Simple events are also handled 
+// here. For more complex events, specific handler functions are called.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::RunL()
+    {
+    LOGTEXT3( _L( "Cae: CCaeStillStatesActive::RunL() entering, iStatus=%d, iCurrentState=%d" ), iStatus.Int(), iCurrentState );
+
+    // Handle external errors 
+
+    if ( iStatus.Int() < 0 )
+        {
+        HandleExternalError();
+        return;
+        }
+
+    // Handle all state transitions
+
+    switch( iStatus.Int() )
+        {
+        case CCaeStillStatesActive::ECaeEventNone:
+            HandleExternalEvent();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventStartStillCapture:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateNone );
+            HandleStart();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventImageCaptureReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateCapturing );
+            HandleImageCaptureReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventBurstImageCaptureReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateCapturingBurst );
+            iCurrentState = CCaeStillStatesActive::ECaeStateAppendingBurstImage;            
+            DoAppendCapturedBurstImageToArray();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventAppendCapturedBurstImageReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateAppendingBurstImage );
+            HandleAppendCapturedBurstImageReady();            
+            break;
+
+        case CCaeStillStatesActive::ECaeEventViewFinderForBurstReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateBurstWaitingForViewFinder );
+            iCurrentState = CCaeStillStatesActive::ECaeStateCapturingBurst;            
+            DoCaptureStillBurstImage();            
+            break;
+
+        case CCaeStillStatesActive::ECaeEventBurstCaptureReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateCapturingBurst );
+            iCurrentState = CCaeStillStatesActive::ECaeStateFetchingNextBurstImage;    
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoFetchNextBurstImage();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventBurstImageFetchReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateFetchingNextBurstImage );
+            HandleBurstImageFetchReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventDecodeToBitmapReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateDecodingCapturedImageToBitmap );
+            HandleDecodeToBitmapReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventExtractExifMetaDataReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtractingExifMetaData );
+            iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage;         
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoExtensionsProcessCapturedImage();    
+            break;
+
+        case CCaeStillStatesActive::ECaeEventProcessCapturedImageStepReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage );
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoExtensionsProcessCapturedImage();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventProcessCapturedImageAllReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage );
+            HandleProcessCapturedImageAllReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventProcessSnapImageStepReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage );
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoExtensionsProcessSnapImage();    
+            break;
+
+        case CCaeStillStatesActive::ECaeEventProcessSnapImageAllReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage );
+            iCurrentState = CCaeStillStatesActive::ECaeStateDeliveringSnapImage;         
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoDeliverSnapImage();    
+            break;
+
+        case CCaeStillStatesActive::ECaeEventDeliverSnapImageReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateDeliveringSnapImage );
+            iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage;         
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoExtensionsProcessStillImage();    
+            break;
+
+        case CCaeStillStatesActive::ECaeEventProcessStillImageStepReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage );
+            iStatus = CCaeStillStatesActive::ECaeEventNone;
+            DoExtensionsProcessStillImage();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventProcessStillImageAllReady:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage );
+            HandleProcessStillImageAllReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventEncodeToJpegReady:
+             CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateEncodingToJpeg );
+            HandleEncodeToJpegReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventDeliverStillBurstImageReady:
+            // We can end up here from any state, if there occurs an error
+            HandleDeliverStillBurstImageReady();
+            break;
+
+        case CCaeStillStatesActive::ECaeEventImageQueueExtPro:
+            CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateNone );
+            HandleImageQueueExtPro();
+            break;
+
+        default:
+            CAE_ASSERT_DEBUG( iCurrentState != iCurrentState ); // Always false
+            break;
+        }
+
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::RunL() returning" ) );
+    }
+
+
+// ---------------------------------------------------------------------------
+// EVENT HANDLERS
+//
+// Event handlers should decide what is the next state and next action after the 
+// current event. Modes and flags are checked here leaving the actual action 
+// functions as simple as possible. 
+// ---------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleExternalError
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleExternalError() 
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleExternalError()" ));
+
+    CAE_ASSERT_DEBUG( ( ( iDelayedEvent != CCaeStillStatesActive::ECaeEventNone )
+                       || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage ) 
+                       || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage ) 
+                       || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage ) ) ); 
+         
+    // Cancelling delayed event timer is not considered as error, but early completion              
+    if ( (iStatus.Int() == KErrCancel ) && ( iDelayedEvent != CCaeStillStatesActive::ECaeEventNone ) )
+        {
+    	LOGTEXT2( _L( "Cae: CCaeStillStatesActive::HandleExternalError(). Delayed event %d completed early." ), iDelayedEvent);
+    	HandleExternalEvent();
+        }
+    else
+    	{
+    	ErrorRecovery( iStatus.Int() );                        		
+    	}    
+
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleExternalEvent
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleExternalEvent() 
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleExternalEvent()" ));
+    CAE_ASSERT_DEBUG( ( ( iDelayedEvent != CCaeStillStatesActive::ECaeEventNone )
+                       || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage ) 
+                       || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage ) 
+                       || ( iCurrentState == CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage ) ) ); 
+
+        
+    if ( iDelayedEvent != CCaeStillStatesActive::ECaeEventNone )
+        {
+        // Timer has finished, issue delayed event now
+        Event( iDelayedEvent );
+        }
+    else          
+        {
+        switch ( iCurrentState )
+            {
+            case ECaeStateExtensionsProcessingCapturedImage:
+                Event( CCaeStillStatesActive::ECaeEventProcessCapturedImageStepReady );
+                break;
+
+            case ECaeStateExtensionsProcessingSnapImage:
+                Event( CCaeStillStatesActive::ECaeEventProcessSnapImageStepReady );
+                break;
+
+            case ECaeStateExtensionsProcessingStillImage:
+                Event( CCaeStillStatesActive::ECaeEventProcessStillImageStepReady );
+                break;
+
+            default:
+                CAE_ASSERT_DEBUG( iCurrentState !=  iCurrentState ); // Always false
+                break;
+
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleStart()
+// Start either single or burst image capture.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleStart()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleStart()" ));
+    CAE_ASSERT_ALWAYS( ( iBitmap == NULL ) && ( iSnapBitmap == NULL ) );
+    CAE_ASSERT_ALWAYS( ( iImageData == NULL ) && ( iImageHeaderData == NULL ) );
+    
+    iStatus = CCaeStillStatesActive::ECaeEventNone;
+    if ( iStillBurst )
+        {               
+        iCurrentState = CCaeStillStatesActive::ECaeStateCapturingBurst;            
+        DoCaptureStillBurst();
+        }
+    else
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateCapturing;            
+        DoCaptureStill();
+        }   
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleImageCaptureReady()
+// Decode the captured image, extract Exif metadata, or process the 
+// image by the extensions.  
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleImageCaptureReady()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageCaptureReady()" ));
+
+    iStatus = CCaeStillStatesActive::ECaeEventNone;
+
+    if ( !iBitmap                   // Does not already exist
+         && ( iCreateSnapImage ) )    // Snap bitmap required by UI
+            /* Not yet implemented
+            || iRequireStillImageAsBitmapRefCount ) ) // Still bitmap required by any extensions
+            */
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateDecodingCapturedImageToBitmap;            
+        DoDecodeCapturedImageToBitmap();
+        }
+    else
+        {
+        /* Not yet implemented
+        if ( iRequireImageFormatHeaderRefCount )
+            {
+            iCurrentState = CCaeStillStatesActive::ECaeStateExtractingExifMetaData;            
+            DoExtractExifMetaData();
+           }
+        else
+        */
+            {
+            iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage;            
+            DoExtensionsProcessCapturedImage();    
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleDecodeToBitmapReady()
+// Extract Exif metadata, or process the captured image by the 
+// extensions.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleDecodeToBitmapReady()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleDecodeToBitmapReady()" ));
+    CAE_ASSERT_ALWAYS( ( iBitmap != NULL ) && ( iSnapBitmap == NULL ) );
+    CAE_ASSERT_ALWAYS( ( iImageData != NULL ) && ( iImageHeaderData == NULL ) );
+
+    iStatus = CCaeStillStatesActive::ECaeEventNone;
+
+    if ( iCreateSnapImage )    // Snap bitmap required by UI
+        /* Not yet implemented
+       && !iRequireStillImageAsBitmapRefCount ) // Still bitmap not required by any extensions
+       */
+        {
+        // Decoded bitmap is used for the snap bitmap only
+        iSnapBitmap = iBitmap;
+        iBitmap = NULL;
+        }    
+
+     /* Not yet implemented
+    if ( iRequireImageFormatHeaderRefCount )
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateExtractingExifMetaData;            
+        DoExtractExifMetaData();
+        }
+    else
+    */
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage;            
+        DoExtensionsProcessCapturedImage();    
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleProcessCapturedImageAllReady()
+// Process the snap image or the still image by the extensions.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleProcessCapturedImageAllReady()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleProcessCapturedImageAllReady()" ));
+
+    iStatus = CCaeStillStatesActive::ECaeEventNone;
+    if ( iCreateSnapImage )
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage;            
+        DoExtensionsProcessSnapImage();    
+        }
+    else
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage;            
+        DoExtensionsProcessStillImage();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleProcessStillImageAllReady()
+// Encode the still bitmap to Jpeg, or deliver the 
+// still image to the client.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleProcessStillImageAllReady()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleProcessStillImageAllReady()" ));
+
+    iStatus = CCaeStillStatesActive::ECaeEventNone;
+
+    // Encode to Jpeg if there is a separate (Exif) header or bitmap to 
+    // Jpeg coversion is needed for client.
+    if ( iImageHeaderData 
+         || ( ( iStillOutputFormat == CCamera::EFormatJpeg ) && !iImageData ) )
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateEncodingToJpeg;            
+        DoEncodeStillImageToJpeg();
+        }
+   else
+        {
+        if ( iStillBurst )
+            {
+            iCurrentState = CCaeStillStatesActive::ECaeStateDeliveringStillBurstImage;            
+            DoDeliverStillBurstImage();
+            }
+        else
+            {
+            iCurrentState = CCaeStillStatesActive::ECaeStateDeliveringStillImage;            
+            DoDeliverStillImage();
+            }
+        }
+    }
+    
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleEncodeToJpegReady()
+// Deliver the still image to the client.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleEncodeToJpegReady()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleEncodeToJpegReady()" ));
+
+    iStatus = CCaeStillStatesActive::ECaeEventNone;
+    if ( iStillBurst )
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateDeliveringStillBurstImage;            
+        DoDeliverStillBurstImage();
+        }
+    else
+        {
+        iCurrentState = CCaeStillStatesActive::ECaeStateDeliveringStillImage;            
+        DoDeliverStillImage();
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CCaeStillStatesActive::HandleImageQueueExtPro()
+// Deliver the still image to the client.
+// ---------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::HandleImageQueueExtPro()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro()" ));
+
+    CFbsBitmap* bitmap = NULL;
+    HBufC8*     imagedata = NULL;
+    TBool       lastimage = EFalse;
+    TBool       snapimage = EFalse;
+
+    // Get next snap or main image from image queue
+    if ( iImageQueueExtPro )
+        {
+        TInt result = iImageQueueExtPro->GetNextImage( bitmap, imagedata, lastimage, snapimage );
+
+        // If prepare has not been done then format has default value
+        if ( !iStillPrepared )
+            {
+            iStillOutputFormat = CCamera::EFormatExif; // Only exif/jpeg is supported
+            }
+        if ( result == KErrNone )
+            {
+            iLastImageExtPro = lastimage;
+            if ( bitmap && snapimage ) // Snap image
+                {
+                LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro() Snap bitmap" ));
+                iStatus = CCaeStillStatesActive::ECaeEventNone;
+                iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingSnapImage;            
+                iSnapBitmap = bitmap;
+                Event( CCaeStillStatesActive::ECaeEventProcessSnapImageStepReady );
+                }
+            else if ( imagedata && !snapimage) // Main captured image (jpeg)
+                {
+                LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro() JPG imagedata" ));
+                iStatus = CCaeStillStatesActive::ECaeEventNone;
+                iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingStillImage;            
+                iImageData = imagedata;
+                Event( CCaeStillStatesActive::ECaeEventProcessStillImageStepReady );
+                }
+            else if ( bitmap && !snapimage) // Main captured image (bitmap)
+                {
+                LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro() bitmap imagedata" ));
+                iStatus = CCaeStillStatesActive::ECaeEventNone;
+                iCurrentState = CCaeStillStatesActive::ECaeStateDeliveringSnapImage;            
+                iBitmap = bitmap;
+                Event( CCaeStillStatesActive::ECaeEventDeliverSnapImageReady );
+                }
+            else 
+                {
+                LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro() iImageQueueExtPro return empty image" ));
+                }
+            }
+        else
+            {
+            LOGTEXT2( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro() iImageQueueExtPro error %d" ), result);
+            }
+        }
+    else
+        {
+        LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleImageQueueExtPro() iImageQueueExtPro not found" ));
+        }
+
+    }
+
+
+// ---------------------------------------------------------------------------
+// EXTERNAL CALLBACKS
+//
+// Callbacks from external objects are mapped to the internal events.
+// ---------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ImageReady
+// Store the captured image and send event to the state machine.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::ImageReady( 
+    CFbsBitmap* aBitmap, 
+    HBufC8*     aImageData, 
+    TInt        aError )
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::ImageReady() entering, aError=%d" ), aError );
+    CAE_ASSERT_ALWAYS( ( iBitmap == NULL ) && ( iSnapBitmap == NULL ) );
+    CAE_ASSERT_ALWAYS( ( iImageData == NULL ) && ( iImageHeaderData == NULL ) );
+    
+    #ifdef _DEBUG
+    // Performance debugging
+    iImageReadyTime.HomeTime();
+    TTimeIntervalMicroSeconds convertInterval =
+        iImageReadyTime.MicroSecondsFrom( iCaptureStartTime );
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::ImageReady(): Captured image ready %f seconds after capture" ),
+                   I64LOW( convertInterval.Int64() ) * 1.0 / KOneSecond );
+    #endif
+
+    #ifdef CAE_TEST_VERSION
+    // For simulating errors when compiled as special "test version".
+    CaeImageReadyError( aError );
+    #endif    
+
+    // Get ownership and store pointers
+    iBitmap = aBitmap;
+    iImageData = aImageData;
+
+    if ( iStillBurst )
+        {
+        iFirstStillBurstError =  iFirstStillBurstError ? iFirstStillBurstError : aError;
+        Event( CCaeStillStatesActive::ECaeEventBurstImageCaptureReady );
+        }
+
+    // Single image capture
+    else if ( !aError )
+        {
+        Event( CCaeStillStatesActive::ECaeEventImageCaptureReady );
+        }
+    else
+        {
+        // Handle error
+        ErrorRecovery( aError );
+        }
+
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::ImageReady() returning" ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::McaesdoCFbsBitmapImageReady
+// Store original and decoded images and send event to the state machine.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::McaesdoCFbsBitmapImageReady( 
+    HBufC8*     aImageData, 
+    CFbsBitmap* aBitmap, 
+    TInt        aError,
+    TInt        /*aImageSize*/ ) // Not yet used
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::McaesdoCFbsBitmapImageReady() entering" ) );
+    CAE_ASSERT_ALWAYS( ( iBitmap == NULL ) && ( iSnapBitmap == NULL ) );
+    CAE_ASSERT_ALWAYS( iImageHeaderData == NULL );
+    CAE_ASSERT_ALWAYS( !iStillCancelled );
+
+   #ifdef _DEBUG
+    // Performance debugging
+    iFinalImageReadyTime.HomeTime();
+    TTimeIntervalMicroSeconds convertInterval =
+        iFinalImageReadyTime.MicroSecondsFrom( iCaptureStartTime );
+    LOGTEXT2( _L( "Cae: CCaeEngineImp::McaesdoCFbsBitmapImageReady(): Final decoded image ready %f seconds after capture" ),
+                   I64LOW( convertInterval.Int64() ) * 1.0 / KOneSecond );
+    #endif
+
+    #ifdef CAE_TEST_VERSION
+    // For simulating errors when compiled as special "test version".
+    CaeMcaesdoCFbsBitmapImageReadyError( aError );
+    #endif
+    
+    // Get ownership and store pointers
+    iBitmap = aBitmap;
+
+    // Delete image data if not the original (extracted thumbnail was used as decoder input).
+    if ( iImageData != NULL )
+        {
+        delete ( aImageData ); // Delete (exif) thumbnail source image
+        }
+    else
+        {
+        iImageData = aImageData; // Store original still image
+        }
+
+    if ( !aError )
+        {
+        Event( CCaeStillStatesActive::ECaeEventDecodeToBitmapReady );
+        }
+    else
+        {
+        // Handle error
+        ErrorRecovery( aError );
+        }
+
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::McaesdoCFbsBitmapImageReady() returning" ) );
+    }
+    
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::McaeseoHBufC8ImageReady
+// Store original and encoded images and send event to the state machine.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::McaeseoHBufC8ImageReady( 
+    CFbsBitmap* aBitmap, 
+    HBufC8*     aImageData, 
+    TInt        aError,
+    TInt        /*aImageSize*/ )
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::McaeseoHBufC8ImageReady() entering" ) );
+    CAE_ASSERT_ALWAYS( ( iBitmap == NULL ) && ( iSnapBitmap == NULL ) );
+    CAE_ASSERT_ALWAYS( ( iImageData == NULL ) && ( iImageHeaderData == NULL ) );
+    CAE_ASSERT_ALWAYS( !iStillCancelled );
+    
+    #ifdef _DEBUG
+    // Performance debugging
+    iFinalImageReadyTime.HomeTime();
+    TTimeIntervalMicroSeconds convertInterval =
+        iFinalImageReadyTime.MicroSecondsFrom( iCaptureStartTime );
+    LOGTEXT2(_L( "Cae: CCaeStillStatesActive::McaeseoHBufC8ImageReady(): Final encoded image ready %f seconds after capture" ), 
+        I64LOW( convertInterval.Int64() ) * 1.0 / KOneSecond);
+    #endif
+
+    #ifdef CAE_TEST_VERSION
+    // For simulating errors when compiled as special "test version".
+    CaeMcaeseoHBufC8ImageReadyError( aError );
+    #endif
+    
+    // Get ownership and store pointers
+    iBitmap = aBitmap;
+    iImageData = aImageData;
+
+    if ( !aError )
+        {
+        Event( CCaeStillStatesActive::ECaeEventEncodeToJpegReady );
+        }
+    else 
+        {
+        // Handle error
+        ErrorRecovery( aError );
+        }
+
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::McaeseoHBufC8ImageReady() returning" ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ViewFinderFrameReady
+// Send event if the state machine is waiting for the view finder. 
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::ViewFinderFrameReady()
+    {
+	iViewFinderFrameReceived = ETrue;
+
+    if ( iCurrentState == CCaeStillStatesActive::ECaeStateBurstWaitingForViewFinder 
+         && !IsActive() ) // To make sure the previous ECaeEventViewFinderForBurstReady has been handled
+        {
+        Event( CCaeStillStatesActive::ECaeEventViewFinderForBurstReady );        
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// ACTION FUNCTIONS FOR STATES
+//
+// To keep it simple, action functions should do only one task each if 
+// possible. If there is a lot of conditions, make several action functions 
+// and call them from event handlers. 
+// ---------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoCaptureStill
+// Start image capturing in Camera API.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoCaptureStill()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStill() entering" ) );
+
+    #ifdef _DEBUG
+    // Performance debugging
+    iCaptureStartTime.HomeTime();
+    #endif
+
+    iViewFinderFrameReceived = EFalse;
+    iStillCancelled = EFalse;
+
+    iCamera.CaptureImage(); // Start capture
+
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStill() returning" ) );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoDecodeCapturedImageToBitmap
+//
+// Decode to bitmap. CCaeStillDecoder calls McaesdoCFbsBitmapImageReady 
+// callback when decoding is ready.
+// Decodes Exif thumbnail to bitmap if requested (by iSnapImageSource).
+// Note that the callback can be called synchronously by iStillDecoder, if 
+// an error occurs in the still decoder. In that case also  ErrorRecovery() 
+// has been called in McaesdoCFbsBitmapImageReady() *before* the method 
+// below returns.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoDecodeCapturedImageToBitmap()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoDecodeCapturedImageToBitmap()" ) );
+    HBufC8* tmpImageData = NULL;
+    TSize   tmpSnapImageSize( 0, 0 );
+    TInt    error( KErrNone );
+    
+    // Use thumbnail for snap image basis if requested to use it.
+    if ( iSnapImageSource == CCaeEngine::ESnapImageSourceThumbnail ) 
+        {
+        TRAP( error, GetThumbnailL( tmpImageData, tmpSnapImageSize ) );
+        if ( error )
+            {
+            LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoDecodeCapturedImageToBitmap(): Thumbnail extraction failed" ) );
+            delete( tmpImageData );
+            tmpImageData = iImageData;
+            tmpSnapImageSize = iOptimalSnapImageSize;
+	        iImageData = NULL; 
+            }
+        }
+    else // Use the captured image for snap image basis.
+        {
+        tmpImageData = iImageData;
+        tmpSnapImageSize = iOptimalSnapImageSize;
+	    iImageData = NULL; 
+        }
+
+    // Ownership will be transferred. Null the pointer already before the method
+    // call because it can call McaesdoCFbsBitmapImageReady() callback synchronously 
+    // inside the method.
+    // Always decode and scale to the correct size if free scaling is supported.
+    TDisplayMode displayMode = iRequireFullColorSnapInputImageRefCount ? 
+        EColor16M : iSnapImageColorMode;
+    TRAP( error, iStillDecoder->ConvertHBufC8ToCFbsBitmapL( 
+            tmpImageData, displayMode, tmpSnapImageSize, iSnapImageSize) );
+
+    #ifdef CAE_TEST_VERSION
+    // For simulating errors when compiled as special "test version".
+    CaeCreateAndDeliverSnapImageError( error );
+    #endif
+
+    if ( error )
+        {
+        // Handle error.
+        ErrorRecovery( error );
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoExtensionsProcessCapturedImage
+//
+// Call the extensions for processing the captured image. Subsequent synchronous
+// methods are called inside a loop. After an asynchronous method, the extension
+// signals the state machine which calls this function again for the next 
+// extension.  
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoExtensionsProcessCapturedImage()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoExtensionsProcessCapturedImage()" ) );
+    
+    OstTrace0( CAMERASRV_PERFORMANCE, CCAESTILLSTATESACTIVE_DOEXTENSIONSPROCESSCAPTUREDIMAGE, "e_CAM_CAE_OPERATIONS 1" );   //CAE_ENGINE_OPERATIONS_START
+        
+	TBool isAsyncOperation = EFalse;
+
+	// Execute synchronous operations in loop. Exit the loop if there is an 
+	// asynchronous function or a syncronous function has returned error status.  		
+	while ( iStatus == KErrNone  
+            && !iStillCancelled
+		    && !isAsyncOperation 
+		    && ( ++iCurrentExtensionIndex <  iProcessImageImplList.Count() ) )
+		{
+
+        TAny* interfacePtr = iProcessImageImplList[iCurrentExtensionIndex].iImplPtr;
+
+        // Call extensions. Note that references to image pointers are given as
+        // parameters. The engine has shared the ownership with the extensions,
+        // which can also delete and create new images.
+        if ( iProcessImageImplList[iCurrentExtensionIndex].iIsActive )
+            {
+    		isAsyncOperation = STATIC_CAST( MCaeExtProcessImageInterface*, interfacePtr )->ProcessCapturedImage(
+                iStatus, iBitmap, iImageData, iImageHeaderData );
+            }
+        else
+            {
+	        LOGTEXT2(_L("Cae: CCaeStillStatesActive::DoExtensionsProcessCapturedImage().Skipping extension %x"),
+	            iProcessImageImplList[iCurrentExtensionIndex].iImplUid.iUid);
+            }
+	    
+	    #ifdef _DEBUG
+	    if ( ( iStatus != KErrNone ) && ( iStatus != KRequestPending ) )
+	        {
+	        LOGTEXT3(_L("Cae: CCaeStillStatesActive::DoExtensionsProcessCapturedImage().Error: %d in ProcessCapturedImage() for Extension %x"),
+	            iStatus.Int(), iProcessImageImplList[iCurrentExtensionIndex].iImplUid.iUid);
+	        }
+	    #endif
+		}
+
+    if (!iStillCancelled)
+        {
+	    // Note: For an asynchronous operation the status can be KErrNone 
+	    //       if the operation has already finished and this thread has 
+	    //       been signaled. 
+		if ( ( iStatus == KErrNone || iStatus == KRequestPending ) && isAsyncOperation )
+			{
+			// Come back after an asynchronous operation has finished
+			SetActive();
+			}
+		else
+			{
+            iCurrentExtensionIndex = -1;
+            if ( iStatus == KErrNone )
+                {
+                OstTrace0( CAMERASRV_PERFORMANCE, DUP1_CCAESTILLSTATESACTIVE_DOEXTENSIONSPROCESSCAPTUREDIMAGE, "e_CAM_CAE_OPERATIONS 0" );  //CAE_ENGINE_OPERATIONS_END
+                Event( CCaeStillStatesActive::ECaeEventProcessCapturedImageAllReady );            
+                }
+            else
+                {
+                // Note: negative status values are handled as "external errors"
+                // in RunL(). Check that the received iStatus is negative, extension can return any value
+                
+                if ( iStatus.Int() <= 0 )
+                    {
+                    Event( (CCaeStillStatesActive::TCaeEvent)iStatus.Int() );    
+                    }
+                else
+                    {
+                    Event( (CCaeStillStatesActive::TCaeEvent) KErrGeneral );    
+                    }
+                }
+			}
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoExtensionsProcessSnapImage
+//
+// Call the extensions for processing the snap image. Subsequent synchronous
+// methods are called inside a loop. After an asynchronous method, the extension
+// signals the state machine which calls this function again for the next 
+// extension.  
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoExtensionsProcessSnapImage()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoExtensionsProcessSnapImage()" ) );
+    
+    OstTrace0( CAMERASRV_PERFORMANCE, CCAESTILLSTATESACTIVE_DOEXTENSIONSPROCESSSNAPIMAGE, "e_CAM_CAE_OPERATIONS 1" );   //CAE_ENGINE_OPERATIONS_START
+        
+	TBool isAsyncOperation = EFalse;
+
+	// Execute synchronous operations in loop. Exit the loop if there is an 
+	// asynchronous function or a syncronous function has returned error status.  
+	
+	while ( iStatus == KErrNone  
+            && !iStillCancelled
+		    && !isAsyncOperation 
+		    && ( ++iCurrentExtensionIndex <  iProcessImageImplList.Count() ) )
+		{
+
+        TAny* interfacePtr = iProcessImageImplList[iCurrentExtensionIndex].iImplPtr;
+
+        // Call extensions. Note that references to image pointers are given as
+        // parameters. The engine has shared the ownership with the extensions,
+        // which can also delete and create new images.
+        if ( iProcessImageImplList[iCurrentExtensionIndex].iIsActive )
+            {
+    		isAsyncOperation = STATIC_CAST( MCaeExtProcessImageInterface*, interfacePtr )->ProcessSnapImage(
+                iStatus, iBitmap, iSnapBitmap );
+            }
+        else
+            {
+	        LOGTEXT2(_L("Cae: CCaeStillStatesActive::DoExtensionsProcessSnapImage(). Skipping Extension %x"),
+	            iProcessImageImplList[iCurrentExtensionIndex].iImplUid.iUid );
+            }
+	    
+	    #ifdef _DEBUG
+	    if ( ( iStatus != KErrNone ) && ( iStatus != KRequestPending ) )
+	        {
+	        LOGTEXT3(_L("Cae: CCaeStillStatesActive::DoExtensionsProcessSnapImage(). Error %d in ProcessSnapImage() for Extension %x"),
+	            iStatus.Int(), iProcessImageImplList[iCurrentExtensionIndex].iImplUid.iUid );
+	        }
+	    #endif
+		}
+
+    if (!iStillCancelled)
+        {
+		// Note: For an asynchronous operation the status can be KErrNone 
+		//       if the operation has already finished and this thread has 
+		//       been signaled. 
+		if ( ( iStatus == KErrNone || iStatus == KRequestPending ) && isAsyncOperation )
+			{
+			// Come back after an asynchronous operation has finished
+			SetActive();
+			}
+		else
+			{
+            iCurrentExtensionIndex = -1;
+            if ( iStatus == KErrNone )
+                {
+                OstTrace0( CAMERASRV_PERFORMANCE, DUP1_CCAESTILLSTATESACTIVE_DOEXTENSIONSPROCESSSNAPIMAGE, "CamAppEngine_Perf:e_CAM_CAE_OPERATIONS 0" );    //CAE_ENGINE_OPERATIONS_END
+                Event( CCaeStillStatesActive::ECaeEventProcessSnapImageAllReady );            
+                }
+            else
+                {
+                // Note: negative status values are handled as "external errors"
+                // in RunL().
+                if ( iStatus.Int() <= 0 )
+                    {
+                    Event( (CCaeStillStatesActive::TCaeEvent)iStatus.Int() );    
+                    }
+                else
+                    {
+                    Event( (CCaeStillStatesActive::TCaeEvent) KErrGeneral );    
+                    }
+                }
+			}
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoDeliverSnapImage
+// Deliver the snap image to the client.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoDeliverSnapImage()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoDeliverSnapImage()" ) );
+    CAE_ASSERT_ALWAYS( !iStillCancelled );
+
+    if ( iSnapBitmap )
+        {
+        iCaeObserver->McaeoSnapImageReady( *iSnapBitmap, KErrNone );  
+        delete( iSnapBitmap );
+        iSnapBitmap = NULL;   
+        }
+    else
+        {
+        iCaeObserver->McaeoSnapImageReady( *iBitmap, KErrNone );  
+        }
+   
+    if ( !iStillCancelled )
+        {
+        if ( ExtModeActive() )
+            {
+            Event( CCaeStillStatesActive::ECaeEventEnd ); // extension mode operation is completed
+            }
+        else
+            {
+            Event( CCaeStillStatesActive::ECaeEventDeliverSnapImageReady );
+            }
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoExtensionsProcessStillImage
+//
+// Call the extensions for processing the still image. Subsequent synchronous
+// methods are called inside a loop. After an asynchronous method, the extension
+// signals the state machine which calls this function again for the next 
+// extension.  
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoExtensionsProcessStillImage()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoExtensionsProcessStillImage()" ) );
+    
+    OstTrace0( CAMERASRV_PERFORMANCE, CCAESTILLSTATESACTIVE_DOEXTENSIONSPROCESSSTILLIMAGE, "e_CAM_CAE_OPERATIONS 1" );  //CAE_ENGINE_OPERATIONS_START
+        
+	TBool isAsyncOperation = EFalse;
+
+	// Execute synchronous operations in loop. Exit the loop if there is an 
+	// asynchronous function or a syncronous function has returned error status.  
+	
+	while ( iStatus == KErrNone  
+            && !iStillCancelled
+		    && !isAsyncOperation 
+		    && ( ++iCurrentExtensionIndex <  iProcessImageImplList.Count() ) )
+		{
+
+        TAny* interfacePtr = iProcessImageImplList[iCurrentExtensionIndex].iImplPtr;
+
+        // Call extensions. Note that references to image pointers are given as
+        // parameters. The engine has shared the ownership with the extensions,
+        // which can also delete and create new images.
+        if ( iProcessImageImplList[iCurrentExtensionIndex].iIsActive )
+            {
+    		isAsyncOperation = STATIC_CAST( MCaeExtProcessImageInterface*, interfacePtr )->ProcessStillImage(
+                iStatus, iBitmap, iImageData, iImageHeaderData );
+            }
+        else
+            {
+	        LOGTEXT2(_L("Cae: CCaeStillStatesActive::DoExtensionsProcessStillImage(). Skipping extension %x"),
+	            iProcessImageImplList[iCurrentExtensionIndex].iImplUid.iUid);
+            }
+	    
+	    #ifdef _DEBUG
+	    if ( ( iStatus != KErrNone ) && ( iStatus != KRequestPending ) )
+	        {
+	        LOGTEXT3(_L("Cae: CCaeStillStatesActive::DoExtensionsProcessStillImage(). Error %d in ProcessStillImage() for Extension %x"),
+	            iStatus.Int(), iProcessImageImplList[iCurrentExtensionIndex].iImplUid.iUid);
+	        }
+	    #endif
+		}
+
+    if (!iStillCancelled)
+        {
+		// Note: For an asynchronous operation the status can be KErrNone 
+		//       if the operation has already finished and this thread has 
+		//       been signaled. 
+		if ( ( iStatus == KErrNone || iStatus == KRequestPending ) && isAsyncOperation )
+			{
+			// Come back after an asynchronous operation has finished
+			SetActive();
+			}
+		else
+			{
+            iCurrentExtensionIndex = -1;
+            if ( iStatus == KErrNone )
+                {
+                OstTrace0( CAMERASRV_PERFORMANCE, DUP1_CCAESTILLSTATESACTIVE_DOEXTENSIONSPROCESSSTILLIMAGE, "e_CAM_CAE_OPERATIONS 0" ); //CAE_ENGINE_OPERATIONS_END
+                Event( CCaeStillStatesActive::ECaeEventProcessStillImageAllReady );            
+                }
+            else
+                {
+                // Note: negative status values are handled as "external errors"
+                // in RunL().
+                if ( iStatus.Int() <= 0 )
+                    {
+                    Event( (CCaeStillStatesActive::TCaeEvent)iStatus.Int() );    
+                    }
+                else
+                    {
+                    Event( (CCaeStillStatesActive::TCaeEvent) KErrGeneral );    
+                    }
+                }
+			}
+        }
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoEncodeStillImageToJpeg
+//
+// Encode bitmap to the Jpeg image. CCaeStillEncoder calls 
+// McaeseoHBufC8ImageReady callback when encoding is ready.
+// Note that the callback can be called synchronously by , iStillEncoder
+// if an error occurs in the still encoder. In that case also
+// ErrorRecovery() has been called in McaeseoHBufC8ImageReady() *before* 
+// the method below returns.
+//
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoEncodeStillImageToJpeg()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoEncodeStillImageToJpeg()" ) );
+    // Ownership will be transferred. Null the pointer already before the method
+    // call because it can call McaesdoCFbsBitmapImageReady() callback synchronously 
+    // inside the method.
+    CFbsBitmap* tmpBitmap = iBitmap;   
+	iBitmap = NULL; 
+	iStillEncoder->SetCompressionQuality( iStillCompressionQuality );
+	TRAPD( error, iStillEncoder->ConvertCFbsBitmapToHBufC8L( tmpBitmap ) );
+
+    #ifdef CAE_TEST_VERSION
+    // For simulating errors when compiled as special "test version".
+    CaeCreateAndDeliverStillImageError( error );
+    #endif
+
+    if ( error )
+        {
+        // Handle error
+        ErrorRecovery( error );
+        }
+   }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::DoDeliverStillImage
+// 
+// Deliver the still image to the client and delete internal images after that.
+// Note: If ownership is transferred, the image pointers should be NULLed before
+// calling the observer method. That is because the observer method can call back
+// CancelStill() which tries to delete images. That is no allowed as images 
+// should be owned by the observer.
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::DoDeliverStillImage()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoDeliverStillImage()" ) );
+    CAE_ASSERT_ALWAYS( !iStillCancelled && ( iSnapBitmap == NULL ) );
+
+    // Deliver the still image to the client.
+    if ( IsBitmapOutput() )
+        {
+        CFbsBitmap* tmpBitmap = iBitmap;
+        iBitmap = NULL; // ownership is transferred      
+        OstTrace0( CAMERASRV_PERFORMANCE, CCAESTILLSTATESACTIVE_DODELIVERSTILLIMAGE, "e_CAM_ENG_SHOT_TO_STILL 0" ); //CAE_ENGINE_SHOT_TO_STILL_END
+        iCaeObserver->McaeoStillImageReady( tmpBitmap, NULL, KErrNone );
+        }
+    else
+        {
+        HBufC8* tmpImageData = iImageData;   
+        iImageData = NULL; // Ownership is tranferred
+        OstTrace0( CAMERASRV_PERFORMANCE, DUP1_CCAESTILLSTATESACTIVE_DODELIVERSTILLIMAGE, "e_CAM_ENG_SHOT_TO_STILL 0" );    //CAE_ENGINE_SHOT_TO_STILL_END
+        iCaeObserver->McaeoStillImageReady( NULL, tmpImageData, KErrNone );
+        }
+ 
+    // Delete all that is not NULL already. 
+    delete iImageData;
+    iImageData = NULL;
+    delete iImageHeaderData;
+    iImageHeaderData = NULL;
+    delete iBitmap;
+    iBitmap = NULL;
+
+    Event( CCaeStillStatesActive::ECaeEventEnd ); // The end. Actuall does no issue any event. 
+    }
+
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::StartQuickCapture()
+// 
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::StartQuickCapture()
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::StartQuickCapture()" ) );
+    CAE_ASSERT_DEBUG( iCurrentState == CCaeStillStatesActive::ECaeStateNone );
+    HandleStart();
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ExtModeActive()
+// 
+// -----------------------------------------------------------------------------
+//
+TBool CCaeStillStatesActive::ExtModeActive()
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::ExtModeActive() %d" ), iExtModeActive );
+    return( iExtModeActive );
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetExtModeActiveL()
+// 
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetExtModeActiveL( TBool aExtModeActive )
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::SetExtModeActiveL() %d" ), aExtModeActive );
+    iExtModeActive = aExtModeActive;
+    iStillCancelled = EFalse;           // clear previous cancel request of still capture
+
+    // Create new instance of still image queue object.
+    if ( aExtModeActive && !iImageQueueExtPro )
+        {
+        iImageQueueExtPro = CCaeImageQueueExtPro::NewL();
+        }
+    else if ( !aExtModeActive )
+        {
+        delete iImageQueueExtPro;
+        iImageQueueExtPro = 0;
+        }
+
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ProcessExtSnapImage
+// Process extension for snap image
+// -----------------------------------------------------------------------------
+//
+TInt CCaeStillStatesActive::ProcessExtSnapImage( CFbsBitmap* aSnapImage )
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::ProcessExtSnapImage()" ));
+    
+    TInt result = iImageQueueExtPro->AppendImage( aSnapImage, NULL, EFalse, ETrue );
+    if ( result == KErrNone &&                                      // image was saved ok
+        iCurrentState == CCaeStillStatesActive::ECaeStateNone &&    // state machine is idle
+        iImageQueueExtPro->ImageCount() < 2 )                       // queue was empty
+        {
+        // Send event to start processing, state machine will stop when queue is empty
+        // and return then back to ECaeStateNone state
+        Event( CCaeStillStatesActive::ECaeEventImageQueueExtPro );
+        }
+    return ( result );
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ProcessExtCapturedImage
+// Process extension for captured jpg image
+// -----------------------------------------------------------------------------
+//
+TInt CCaeStillStatesActive::ProcessExtCapturedImage( HBufC8* aImageData, TBool aLastImage  )
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::ProcessExtCapturedImage() jpg" ));
+
+    TInt result = KErrNone;
+    result = iImageQueueExtPro->AppendImage( NULL, aImageData, aLastImage, EFalse );
+
+    if ( result == KErrNone &&                                      // image was saved ok
+        iCurrentState == CCaeStillStatesActive::ECaeStateNone &&    // state machine is idle
+        iImageQueueExtPro->ImageCount() < 2 )                       // queue was empty
+        {
+        // Send event to start processing, state machine will stop when queue is empty
+        // and return then back to ECaeStateNone state
+        Event( CCaeStillStatesActive::ECaeEventImageQueueExtPro );
+        }
+
+    return ( result );
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::ProcessExtCapturedImage
+// Process extension for captured bitmap image
+// -----------------------------------------------------------------------------
+//
+TInt CCaeStillStatesActive::ProcessExtCapturedImage( CFbsBitmap* aImageBitmapData, TBool aLastImage  )
+    {
+    LOGTEXT( _L( "Cae: CCaeStillStatesActive::ProcessExtCapturedImage() bitmap" ));
+
+    TInt result = KErrNone;
+    result = iImageQueueExtPro->AppendImage( aImageBitmapData, NULL, aLastImage, EFalse );
+
+    if ( result == KErrNone &&                                      // image was saved ok
+        iCurrentState == CCaeStillStatesActive::ECaeStateNone &&    // state machine is idle
+        iImageQueueExtPro->ImageCount() < 2 )                       // queue was empty
+        {
+        // Send event to start processing, state machine will stop when queue is empty
+        // and return then back to ECaeStateNone state
+        Event( CCaeStillStatesActive::ECaeEventImageQueueExtPro );
+        }
+
+    return ( result );
+    }
+
+// -----------------------------------------------------------------------------
+// CCaeStillStatesActive::SetBurstModeVFOptimization()
+// -----------------------------------------------------------------------------
+//
+void CCaeStillStatesActive::SetBurstModeVFOptimization(
+    TBool aBurstModeVFOptimization )
+    {
+    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::SetBurstModeVFOptimization(%d)" ), aBurstModeVFOptimization);
+    iBurstModeVFOptimization = aBurstModeVFOptimization;
+    }
+
+// End of File