camappengine/Engine/Src/CaeStillStatesActiveBurst.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:23:23 +0100
branchRCL_3
changeset 21 27fe719c32e6
parent 0 9b3e960ffc8a
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201031 Kit: 201035

/*
* 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:  Camera Application Engine still image burst capturing 
*                interface implementation
*
*/


// INCLUDE FILES
#include "CaeEngineImp.h"                   // Engine implementation header.
#include "CaeStillBurst.h"                  // Still capturing burst mode class.
#include "CaeStillStatesActive.h"           // Still capturing burst mode class.

#ifdef CAE_TEST_VERSION
#include "CaeEngineImpTestErrors.h"         // For TEST_VERSION compilation only
#endif


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

// -----------------------------------------------------------------------------
// CCaeStillStatesActive::SetCaeStillBurstObserver
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::SetCaeStillBurstObserver( 
    MCaeStillBurstObserver& aObserver )
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetCaeStillBurstObserver()" ) );
    iCaeStillBurstObserver = &aObserver;
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::SetStillCaptureImageCountL
// Delete old instance and create a new burst object if required. 
// -----------------------------------------------------------------------------
//
TInt CCaeStillStatesActive::SetStillCaptureImageCountL( 
    TInt aImageCount )
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetStillCaptureImageCountL() entering" ) );

    // Leave if still capturing is running.
    if ( IsRunning() ) 
        {
        LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetStillCaptureImageCountL() leaving KErrNotReady (IsRunning)" ) );
        User::Leave( KErrNotReady );
        }
    
    // Leave if the image count requested is invalid.
    if ( aImageCount <= 0 ) 
        {
        LOGTEXT2( _L( "Cae: invalid input argument aImageCount = %d, leaving KErrArgument" ), aImageCount );
        User::Leave( KErrArgument );
        }

    // Delete possible old still burst instance.
    DeleteStillBurst();

    // Prepare for burst capturing if requested image count more than 1.
    // Otherwise iStillBurst stays NULL.
    if ( aImageCount > 1 )
        {
        // Create new instance of still image burst object.
        iStillBurst = CCaeStillBurst::NewL();

        // Set parameter(s).
        iStillBurst->SetLengthL( aImageCount );

        LOGTEXT2( _L( "Cae: image count set successfully = %d" ), aImageCount );
        }

    LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetStillCaptureImageCountL() returning" ) );    

    return aImageCount;
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::StillCaptureImageCount
// -----------------------------------------------------------------------------
//
TInt CCaeStillStatesActive::StillCaptureImageCount() const
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::StillCaptureImageCount() entering" ) );
    
    // Nonexistence of still burst object implies image count of 1 
    // (= normal single still capture).
    TInt imageCount( 1 );
    if ( iStillBurst ) 
        {
        imageCount = iStillBurst->Length();
        }
        
    LOGTEXT2( _L( "Cae: CCaeStillStatesActive::StillCaptureImageCount() returning: %d" ), imageCount );
    
    return imageCount;
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::SetStillBurstCaptureIntervalL
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::SetStillBurstCaptureIntervalL( 
    TTimeIntervalMicroSeconds aInterval )
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetStillBurstCaptureIntervalL()" ) );

    if ( IsRunning() ) 
        {
        LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetStillBurstCaptureIntervalL(), leaving KErrNotReady" ) );
        User::Leave( KErrNotReady );
        }
        
    // Note: KMaxTInt32 in microseconds is about 35 minutes
    if ( aInterval < TTimeIntervalMicroSeconds( 0 ) || 
         aInterval > TTimeIntervalMicroSeconds( KMaxTInt32 ) )
        {
        LOGTEXT( _L( "Cae: CCaeStillStatesActive::SetStillBurstCaptureIntervalL(), leaving KErrArgument" ) );
        User::Leave( KErrArgument );
        }

    iStillBurstCaptureInterval = I64INT( aInterval.Int64() );
    }
        

// -----------------------------------------------------------------------------
// CCaeStillStatesActive::StillBurstCaptureInterval
// -----------------------------------------------------------------------------
//
TTimeIntervalMicroSeconds CCaeStillStatesActive::StillBurstCaptureInterval() const 
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::StillBurstCaptureInterval()" ) );
    
    TInt64 intInterval = iStillBurstCaptureInterval.Int();

    TTimeIntervalMicroSeconds interval( intInterval );

    return interval;
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::StopStillBurstCapture
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::StopStillBurstCapture()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::StopStillBurstCapture()" ) );

    iStillBurstStopped = ETrue;
    
    // Complete early any pending delayed event 
	if ( iDelayedEvent != CCaeStillStatesActive::ECaeEventNone )
    	{
        iDelayedCallTimer.Cancel();
        }
    }


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


// ---------------------------------------------------------------------------
// CCaeStillStatesActive::HandleAppendCapturedBurstImageReady()
// Fetch the first burst image from the array, or continue burst capturing.
// ---------------------------------------------------------------------------
//
void CCaeStillStatesActive::HandleAppendCapturedBurstImageReady()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleAppendCapturedBurstImageReady()" ));

    iStatus = CCaeStillStatesActive::ECaeEventNone;

    if ( iStillBurst->IsBurstCaptured() || iStillBurstStopped )
        {
        // Fetch the first burst image from the array

        iCurrentState = CCaeStillStatesActive::ECaeStateFetchingNextBurstImage;
        iStillBurstDeliveryStarted = ETrue;            
        DoFetchNextBurstImage();
        }
    else
        {         
        // Continue burst capturing.
        // If view finder is enabled, at least one view finder image 
        // should be received before the next capture.
        // Otherwise, start directly the next capture.

         // wait alway next iViewFinderFrameReceived if optimization is not used
         // with optimization old VF updates are acccepted
        if ( iIsViewFinderEnabled &&
             !(iBurstModeVFOptimization && iViewFinderFrameReceived ) )
            {
            LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleAppendCapturedBurstImageReady(). Waiting for the view finder." ) );
            iCurrentState = CCaeStillStatesActive::ECaeStateBurstWaitingForViewFinder;            
            }
        else        
            {
            iCurrentState = CCaeStillStatesActive::ECaeStateCapturingBurst;            
            DoCaptureStillBurstImage();
            }
        }
    }


// ---------------------------------------------------------------------------
// CCaeStillStatesActive::HandleBurstImageFetchReady()
// Decode the captured image, extract Exif metadata, or process the 
// image by the extensions.  
// ---------------------------------------------------------------------------
//
void CCaeStillStatesActive::HandleBurstImageFetchReady()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleBurstImageFetchReady()" ));

    iStatus = CCaeStillStatesActive::ECaeEventNone;

    if ( !iBitmap                   // Does not already exist
         && ( iCreateSnapImage ) )   // Snap bitmap required by UI
        {
        // Need to decode first.
        iCurrentState = CCaeStillStatesActive::ECaeStateDecodingCapturedImageToBitmap;            
        DoDecodeCapturedImageToBitmap();
        }
    else
        {
        // No need to decode.
            {
            iCurrentState = CCaeStillStatesActive::ECaeStateExtensionsProcessingCapturedImage;            
            DoExtensionsProcessCapturedImage();    
            }
        }
    }


// ---------------------------------------------------------------------------
// CCaeStillStatesActive::HandleDeliverStillBurstImageReady()
// Complete still burst or fetch the next image.
// ---------------------------------------------------------------------------
//
void CCaeStillStatesActive::HandleDeliverStillBurstImageReady()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::HandleDeliverStillBurstImageReady()" ));
    CAE_ASSERT_ALWAYS( iStillBurst && ( iBitmap == NULL ) && ( iImageData == NULL ) && ( iSnapBitmap == NULL ) );

    iStatus = CCaeStillStatesActive::ECaeEventNone;
    if ( CheckForStillBurstCompletion() )
        {
        iCurrentState = CCaeStillStatesActive::ECaeStateCompletingStillBurst;            
        DoCompleteStillBurst();
        }
    else
        {
        iCurrentState = CCaeStillStatesActive::ECaeStateFetchingNextBurstImage;            
        DoFetchNextBurstImage();
        }
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DoCaptureStillBurst
// Start the burst and capture the first burst image.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::DoCaptureStillBurst()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStillBurst() entering" ) );
    MEM();
 
    iFirstStillBurstError = KErrNone;
    iStillBurstDeliveryStarted = EFalse;
        
    // Do not wait for the view finder for the first capture
    iViewFinderFrameReceived = ETrue; 
    iStillCancelled = EFalse;

    // Capture the first image in the burst.
    DoCaptureStillBurstImage();

    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStillBurst() returning" ) );
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DoCaptureStillBurstImage
// Capture one image for the burst.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::DoCaptureStillBurstImage()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStillBurstImage() entering" ) );
    MEM();
    CAE_ASSERT_ALWAYS( !iStillCancelled );

    // Notify client about capturing moment.
    if ( !iStillBurstStopped )
        {
        iCaeStillBurstObserver->McaesboStillBurstCaptureMoment( KErrNone );       
        }

    // Note: If still burst is cancelled in the callback, the state 
    // machine has already been reseted. Any member data is not allowed
    // to be changed any more. Just return from this function. 

    if ( !iStillCancelled && !iStillBurstStopped ) 
        {
        LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStillBurstImage() capture next image" ) );
        iViewFinderFrameReceived = EFalse;
        iCamera.CaptureImage();
        }

    // Separate "if" (instead of "else if") due 
    // the possibility of stopping or cancelling in callback above.
    if ( !iStillCancelled ) // Return immediately, if cancelled
        {
        if ( iStillBurstStopped )
            {
            // Deliver the images to the client if the burst was stopped.
            // This call delivers the first image in the burst.
            if ( !iStillBurstDeliveryStarted )
                {
                LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStillBurstImage(): burst stopped, starting delivery" ) );
                iStillBurstDeliveryStarted = ETrue;
                Event( CCaeStillStatesActive::ECaeEventBurstCaptureReady );
                }
        
            }
        }

    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCaptureStillBurstImage() returning" ) );
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DoAppendCapturedBurstImageToArray
// Append the captured image to the still burst array.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::DoAppendCapturedBurstImageToArray()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoAppendCapturedBurstImageToArray() entering" ) );
    CAE_ASSERT_ALWAYS( !iStillCancelled );
    MEM();

    TInt error = iFirstStillBurstError; // We may have had error during previous capture phase

    if ( !error ) 
        {
        // Put the image into buffer.
        // All appended images will have KErrNone code.
        // AppendImage does not delete the image if unable to append (error is returned).
        error = iStillBurst->AppendImage( iBitmap, iImageData, KErrNone ); 
        }

    if ( !error ) 
        {
        // Ownership transferred
        iBitmap = NULL;
        iImageData = NULL;
        }
    else
        {
        LOGTEXT2( _L( "Cae: CCaeStillStatesActive::DoAppendCapturedBurstImageToArray(): error detected: %d" ), error );
    	    
        // Delete images
        delete( iBitmap );
        iBitmap = NULL;
	    delete( iImageData );
        iImageData = NULL;

        iFirstStillBurstError =  iFirstStillBurstError ? iFirstStillBurstError : error;
        iStillBurstStopped = ETrue; // Stop burst if an error was detected.    
        }

    if ( !iStillBurstStopped && !iStillBurst->IsBurstCaptured() ) 
        {
        // Activate (delayed) capturing of new image if burst is not complete yet.
        Event( CCaeStillStatesActive::ECaeEventAppendCapturedBurstImageReady, iStillBurstCaptureInterval );
        }
    else  
        {
        // Start delivering immediately
        Event( CCaeStillStatesActive::ECaeEventAppendCapturedBurstImageReady );
        }

    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoAppendCapturedBurstImageToArray() returning" ) );
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DoFetchNextBurstImage
// Get the next image from the burst array.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::DoFetchNextBurstImage()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoFetchNextBurstImage() entering" ) );
    MEM();
    CAE_ASSERT_ALWAYS( ( iBitmap == NULL ) && ( iImageData == NULL ) && ( iSnapBitmap == NULL ) );
    CAE_ASSERT_ALWAYS( !iStillCancelled );
    CAE_ASSERT_ALWAYS( iStillBurst );

    if ( ExtModeActive() ) // Extension processing mode
        {
            Event( CCaeStillStatesActive::ECaeEventEnd ); // extension mode operation is completed when queue is empty
        }
    else  // Normal mode
        {
        LOGTEXT2( _L( "Cae: CCaeStillStatesActive::DoFetchNextBurstImage(): count of burst images in queue = %d" ), iStillBurst->ImageCount() );

        // Get next image from the array

        CFbsBitmap* bitmap = NULL; 
        HBufC8* imageData = NULL;
        TInt imageError( KErrNone );

        TInt error = iStillBurst->GetNextImage( bitmap, imageData, imageError );

        // If there is no items in the array, return the first error
        if ( (error == KErrUnderflow) && iFirstStillBurstError)
            {
            error = iFirstStillBurstError;
            }

        error = error ? error : imageError;
        iImageData = imageData;
        iBitmap = bitmap;

        if ( error )
            {
            // Handle error
            ErrorRecovery( error );                    
            }
        else
            {
            Event( CCaeStillStatesActive::ECaeEventBurstImageFetchReady );
            }
        }
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoFetchNextBurstImage() returning" ) );
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::CheckForStillBurstCompletion
// -----------------------------------------------------------------------------
//
TBool CCaeStillStatesActive::CheckForStillBurstCompletion()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::CheckForStillBurstCompletion()" ) );
    MEM();
    
    TBool burstShouldBeCompleted( EFalse );

    if ( iStillBurst )
        {
        if ( ExtModeActive() )  // In extension mode client knows when completed
            {
            burstShouldBeCompleted = iLastImageExtPro;
            }
        else if ( iCountOfProcessedBurstImages >= iStillBurst->CaptureCount() ) // Normal mode
            {
            // All captures have now been processed, ready to complete the burst.
            LOGTEXT2( _L( "Cae: CCaeStillStatesActive::CheckForStillBurstCompletion(): Burst complete, count of images = %d" ), iCountOfProcessedBurstImages );
            burstShouldBeCompleted = ETrue;
            }
        }

    return( burstShouldBeCompleted );
    }
    

// -----------------------------------------------------------------------------
// CCaeStillStatesActive::BurstErrorRecovery
// Recover from burst errors.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::BurstErrorRecovery( TInt aError )
    {
    // Handle burst image mode errors   
    
    // Store error code
    iFirstStillBurstError =  iFirstStillBurstError ? iFirstStillBurstError : aError;

    iCountOfProcessedBurstImages++;

    // Delete all images which are not deleted already. 
    delete iSnapBitmap;
    iSnapBitmap = NULL;
    delete iBitmap;
    iBitmap = NULL;
    delete iImageData;
    iImageData = NULL;

    // Ignore error and continue processing
    Event( CCaeStillStatesActive::ECaeEventDeliverStillBurstImageReady );       
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DoCompleteStillBurst
// Complete still image burst capture. 
// Calls the observer method McaesboStillBurstComplete if capturing was not 
// cancelled.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::DoCompleteStillBurst()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCompleteStillBurst() entering" ) );

    if ( !iStillCancelled && IsRunning() )
        {
        // Notify client about completing the burst.
        iCaeStillBurstObserver->McaesboStillBurstComplete( iCountOfDeliveredBurstImages, iFirstStillBurstError );
        LOGTEXT2( _L( "Cae: CCaeStillStatesActive::DoCompleteStillBurst(): Count of delivered burst images = %d" ), iCountOfDeliveredBurstImages );
        }
    iFirstStillBurstError = KErrNone;
    CompleteStillBurst();
    Event( CCaeStillStatesActive::ECaeEventEnd ); // The end. Actuall does not issue any event. 

    MEM();
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoCompleteStillBurst() returning" ) );
    }

// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DoDeliverStillBurstImage
//
// Deliver the still burst 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::DoDeliverStillBurstImage()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DoDeliverStillBurstImage()" ) );
    CAE_ASSERT_ALWAYS( !iStillCancelled && ( iSnapBitmap == NULL ) );

    // Deliver the still burst image to the client.
    if ( IsBitmapOutput() )
        {
        // Give original image to the client even if there is decoding error.
        CFbsBitmap* tmpBitmap = iBitmap;
        iBitmap = NULL; // ownership is transferred      
        iCaeObserver->McaeoStillImageReady( tmpBitmap, NULL, KErrNone );
        }
    else
        {
        // Give original image to the client even if there is encoding error
        HBufC8* tmpImageData = iImageData;   
        iImageData = NULL; // Ownership is tranferred
        iCaeObserver->McaeoStillImageReady( NULL, tmpImageData, KErrNone );
        }

    iCountOfDeliveredBurstImages++;
    iCountOfProcessedBurstImages++;

    // Delete all that is not NULL already. 
    delete iImageData;
    iImageData = NULL;
    delete iImageHeaderData;
    iImageHeaderData = NULL;
    delete iBitmap;
    iBitmap = NULL;

    Event( CCaeStillStatesActive::ECaeEventDeliverStillBurstImageReady );
    }


// -----------------------------------------------------------------------------
// CCaeStillStatesActive::CompleteStillBurst()
// Complete still image burst capture but do not delete still burst object. 
// Calls the observer method McaesboStillBurstComplete if capturing was not 
// cancelled.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::CompleteStillBurst()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::CompleteStillBurst() entering" ) );
    MEM();
    if ( iStillBurst )
        {
        iStillBurst->ResetAndDestroyImages();
        }
  
    iCountOfProcessedBurstImages = 0;
    iCountOfDeliveredBurstImages = 0;
    iStillBurstStopped = EFalse;
    MEM();
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::CompleteStillBurst() returning" ) );
   }

// -----------------------------------------------------------------------------
// CCaeStillStatesActive::DeleteStillBurst
// Delete still burst object and reset burst related variables.
// -----------------------------------------------------------------------------
//
void CCaeStillStatesActive::DeleteStillBurst()
    {
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DeleteStillBurst() entering" ) );

    delete iStillBurst;
    iStillBurst = NULL;

    iCountOfProcessedBurstImages = 0;
    iCountOfDeliveredBurstImages = 0;

    iStillBurstStopped = EFalse;

    MEM();
    LOGTEXT( _L( "Cae: CCaeStillStatesActive::DeleteStillBurst() returning" ) );    
    }


//  End of File