photosgallery/viewframework/texturemanager/src/glxbitmapdecoderwrapper.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 12:42:31 +0300
branchRCL_3
changeset 32 78ad99c24f08
parent 18 bcb43dc84c44
child 47 f9e827349359
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* Copyright (c) 2008-2009 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:    Texture Manager component/Decodes the Image in step for large sized images
 *
*/




// INCLUDE FILES
#include "glxbitmapdecoderwrapper.h"
#include <glxtracer.h>      //  For Log
#include <bitmaptransforms.h>
#include <imageconversion.h>
#include <ExifRead.h>
#include <glxlog.h>
#include <hal.h>
#include <hal_data.h>
#include <mglxcache.h>
#include <oommonitorsession.h>
namespace
{
const TInt KGlxDecodingThreshold = 3000000;
const TInt KGlxDecodingThresholdDimension = 2000;


// Photos low_ram_threshold [8.637 MB] as in oomconfig.xml
const TInt KGlxCriticalRAMForPhotos = 9056550;
const TInt KGlxDecodeBitmapFactor = 3;
// All EXIF data is within the first KGlxMaxExifSize bytes of the file
const TInt KGlxMaxExifSize = 0x10000;
}

// ---------------------------------------------------------------------------
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CGlxBitmapDecoderWrapper* CGlxBitmapDecoderWrapper::NewL(MGlxBitmapDecoderObserver* aObserver)
    {
    TRACER("CGlxBitmapDecoderWrapper:: NewL ");
    CGlxBitmapDecoderWrapper* self = new(ELeave)CGlxBitmapDecoderWrapper();
    CleanupStack::PushL(self);
    self->ConstructL(aObserver);
    CleanupStack::Pop(self);
    return self;
    }

// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CGlxBitmapDecoderWrapper::CGlxBitmapDecoderWrapper()
                         :CActive( EPriorityLow )
		        {
		        TRACER("CGlxBitmapDecoderWrapper:: NewL ");
		        }		

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//

CGlxBitmapDecoderWrapper::~CGlxBitmapDecoderWrapper()
    {
    TRACER("CGlxBitmapDecoderWrapper:: ~CGlxBitmapDecoderWrapper ");
    iFs.Close();
    Cancel();
    if (iImageDecoder)
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    }

// ---------------------------------------------------------------------------
// ConstructL
// ---------------------------------------------------------------------------
void CGlxBitmapDecoderWrapper::ConstructL(MGlxBitmapDecoderObserver* aObserver)
    {
    TRACER("CGlxBitmapDecoderWrapper::ConstructL ");
    iObserver = aObserver;
    User::LeaveIfError(iFs.Connect());
    CActiveScheduler::Add( this );
    }

// ---------------------------------------------------------------------------
// DoDecodeImageL
// ---------------------------------------------------------------------------		

void CGlxBitmapDecoderWrapper::DoDecodeImageL(const TDesC & aSourceFileName,TInt aIndex)
    {
    TRACER("CGlxBitmapDecoderWrapper:: DoDecodeImageL ");
    iThumbnailIndex = aIndex;
    //Variable used to get the decoder type used
    TBool isExtDecoderUsed = ETrue;
    
#ifdef _DEBUG
    iDecodeProcessstartTime.HomeTime();
#endif                          

    if (iImageDecoder)
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    
    CImageDecoder::TOptions options = (CImageDecoder::TOptions)
            ( CImageDecoder::EOptionNoDither | CImageDecoder::EOptionAlwaysThread );

    // Use extended JPEG decoder
    TRAPD( err, iImageDecoder = CExtJpegDecoder::FileNewL(
            CExtJpegDecoder::EHwImplementation, iFs, aSourceFileName, options  ) );
    if ( KErrNone != err )
        {
        GLX_LOG_INFO( "DoDecodeImageL:: ESwImplementation" );
        TRAP(err,iImageDecoder = CExtJpegDecoder::FileNewL(
                CExtJpegDecoder::ESwImplementation, iFs, aSourceFileName, options  ) );
        if ( KErrNone != err )
            {
            GLX_LOG_INFO( "DoDecodeImageL:: CImageDecoder" );
            // Not a JPEG - use standard decoder
            iImageDecoder = CImageDecoder::FileNewL( iFs, aSourceFileName, options  );
            isExtDecoderUsed = EFalse;
            }
        }
#ifdef _DEBUG
        iStopTime.HomeTime();
        GLX_DEBUG1("=== DECODER CREATION ===");
        GLX_DEBUG2("Decoder Creation took <%d> us", 
                   (TInt)iStopTime.MicroSecondsFrom(iDecodeProcessstartTime).Int64());   
#endif                          
		
    TSize imageSize = iImageDecoder->FrameInfo().iOverallSizeInPixels;
    if(isExtDecoderUsed)
        {
        TUint16 orientation=0;
        //Read the orientation from the Exif header of the image if present
        TRAPD(error, orientation=GetOrientationL(aSourceFileName));
        if(KErrNone == error )
            {
            //Get the rotation angle and the flip status from orientation
            TInt rotAngle = 0;
            TBool flipStatus = EFalse;
            GetRotationParameters(orientation, rotAngle, flipStatus);
            //Set the parameters to the decoder
            CExtJpegDecoder* extDecoder = (CExtJpegDecoder*)iImageDecoder;
            extDecoder->SetRotationL(rotAngle);
            if(flipStatus)
                {
                extDecoder->SetMirroringL();
                }
            //Switch Image Height and width in case orientation > 4 as that 
            //corresponds to angles 180 and 270 degrees
            if (orientation > 4)
                {
                imageSize.SetSize(imageSize.iHeight,imageSize.iWidth);
                }
            }

        }
    iOriginalSize.iWidth = imageSize.iWidth;
    iOriginalSize.iHeight = imageSize.iHeight;

    if (iBitmap)
        {
        delete iBitmap;
        iBitmap = NULL;
        }
    DecodeImageL();
    }
// ---------------------------------------------------------------------------
// DecodeImageL
// ---------------------------------------------------------------------------
//
void CGlxBitmapDecoderWrapper::DecodeImageL()
    {
    TRACER("CGlxBitmapDecoderWrapper:: DecodeImageL ");
    TReal32 mFactor = 1;
    TReal32 mFactor1 = 1;
    TReal32 mFactor2 = 1;
    //Set Size according to level and state
    TReal32 width = iOriginalSize.iWidth;
    TReal32 height = iOriginalSize.iHeight;
    GLX_LOG_INFO1("DecodeImageL:width=%f", width);
    GLX_LOG_INFO1("DecodeImageL:height=%f",height);
    
    if ( KGlxDecodingThreshold < (width * height))
        {
        mFactor1 = TReal32(KGlxDecodingThreshold) / (width*height);
        GLX_LOG_INFO1("mFactor1 =%f",mFactor1);
        }
    
    if ( KGlxDecodingThresholdDimension < width || KGlxDecodingThresholdDimension < height)
        {
        mFactor2 = TReal32(KGlxDecodingThresholdDimension) / Max(width, height);
        GLX_LOG_INFO1("mFactor2 =%f",mFactor2);
        }

    mFactor = Min(mFactor1 , mFactor2);
    GLX_LOG_INFO1("Final mFactor =%f",mFactor);

    // create the destination bitmap
    if(!iBitmap)
        {
        TInt freeMemory = 0;
        HAL::Get( HALData::EMemoryRAMFree, freeMemory );
        width*=mFactor;
        height*=mFactor;
        TInt minmemorytodecode = KGlxDecodeBitmapFactor*width*height;     
        GLX_LOG_INFO2("DecodeImageL: after factoring width=%f, height=%f", width, height);
        GLX_LOG_INFO2("DecodeImageL:minmemorytodecode=%d, freememory=%d",
                minmemorytodecode, freeMemory);
        if(minmemorytodecode < (freeMemory - KGlxCriticalRAMForPhotos))
            {
            GLX_LOG_INFO("DecodeImageL:RAM available decoding image");

            iBitmap = new (ELeave) CFbsBitmap();
            iBitmap->Create( TSize(width,height),iImageDecoder->FrameInfo().iFrameDisplayMode );
#ifdef _DEBUG
            iStartTime.HomeTime(); // Get home time
#endif                          
            iImageDecoder->Convert( &iStatus, *iBitmap );
            }
        else
            {
            //case when sufficient memory is not available
            //request OOM FW to release the required memory
            GLX_LOG_INFO("DecodeImageL:insufficient RAM - request OOM");
            TInt err = OOMRequestFreeMemoryL(minmemorytodecode);
            if(err == KErrNoMemory)
                {
                //if OOM fails, release Photos Cache
                GLX_LOG_INFO("DecodeImageL:insufficient RAM - OOM failed - request Cache");
                MGlxCache* cacheManager = MGlxCache::InstanceL();
                cacheManager->ReleaseRAML(ETrue);            
                cacheManager->Close();
                //Try and release memory again
                err = OOMRequestFreeMemoryL(minmemorytodecode);
                }
            if(err != KErrNoMemory)
                {
                GLX_LOG_INFO("DecodeImageL:Sufficient RAM available");
                iBitmap = new (ELeave) CFbsBitmap();
                iBitmap->Create( TSize(width,height),iImageDecoder->FrameInfo().iFrameDisplayMode );
#ifdef _DEBUG
	            iStartTime.HomeTime(); // Get home time
#endif                          
                iImageDecoder->Convert( &iStatus, *iBitmap );
                }
            else
                {
                GLX_LOG_INFO("NOT ENOUGH MEMORY - Using the Fullscreen Thumbnail For Zoom");
                //release the file held by decoder immediately.
                iImageDecoder->Cancel();
                delete iImageDecoder;
                iImageDecoder = NULL;
                //Inform the client that there is no decode happened and there we take care 
                //of showing the fullscreen thumbnail.
                iObserver->HandleBitmapDecodedL(iThumbnailIndex,NULL);
                return;                
                }
            }

        SetActive();
        }
    }
// ---------------------------------------------------------------------------
// RunL
// ---------------------------------------------------------------------------
//
void CGlxBitmapDecoderWrapper::RunL()
    {
    TRACER("CGlxBitmapDecoderWrapper:: RunL ");
    if( iStatus == KErrNone )
        {
        iObserver->HandleBitmapDecodedL(iThumbnailIndex,iBitmap);
        iBitmap = NULL;

        //release the file held by decoder immediately.
        GLX_LOG_INFO( " CGlxBitmapDecoderWrapper::RunL:Decoding Finished" );
        iImageDecoder->Cancel();
        delete iImageDecoder;
        iImageDecoder = NULL;
#ifdef _DEBUG
        iStopTime.HomeTime();
        GLX_DEBUG1("=== IMAGE DECODE ===");
        GLX_DEBUG2("=>Image Decode Took took <%d> us", 
                       (TInt)iStopTime.MicroSecondsFrom(iStartTime).Int64());            
#endif                          

        }
    }
// ---------------------------------------------------------------------------
// DoCancel
// ---------------------------------------------------------------------------
//
void CGlxBitmapDecoderWrapper::DoCancel()
    {
    TRACER("CGlxBitmapDecoderWrapper:: DoCancel ");
    if(iImageDecoder)
        {
        GLX_LOG_INFO( " CGlxBitmapDecoderWrapper::DoCancel:Deleting" );
        iImageDecoder->Cancel();
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    if(iBitmap)
        {
        delete iBitmap;
        iBitmap = NULL;
        }
    }

// ---------------------------------------------------------------------------
// GetOrientationL
// ---------------------------------------------------------------------------
//
TUint16 CGlxBitmapDecoderWrapper::GetOrientationL(const TDesC& aFileName)
    {
    TRACER("CGlxBitmapDecoderWrapper:: GetOrientationL ");
    //Get Exif Metadata and the orientation tag from the file first
            RFile file;
            CleanupClosePushL(file);
            User::LeaveIfError(file.Open(iFs,
                    aFileName, EFileRead));
            TInt size;
            User::LeaveIfError(file.Size(size));
            if ( KGlxMaxExifSize < size )
                {
                size = KGlxMaxExifSize;
                }
            TUint16 orientation = 9;
            HBufC8* exifData = HBufC8::NewLC(size);
            TPtr8 ptr(exifData->Des());
            User::LeaveIfError(file.Read(ptr));
            CExifRead* exifReader = NULL;
            TRAPD(exifErr,exifReader = CExifRead::NewL(*exifData, CExifRead::ENoJpeg));
            if(exifErr == KErrNone)
                {
                CleanupStack::PushL(exifReader);

                TInt readErr = exifReader->GetOrientation(orientation);
                if(readErr != KErrNone)
                    {
                    orientation = 9;
                    }
                CleanupStack::PopAndDestroy(exifReader);
                }
            CleanupStack::PopAndDestroy(exifData);
            //Close and pop file Session
            CleanupStack::PopAndDestroy(&file);
            return orientation;
    
    }
// ---------------------------------------------------------------------------
// DoCancel
// ---------------------------------------------------------------------------
//
void CGlxBitmapDecoderWrapper::GetRotationParameters(TUint16 aOrientation, TInt& aRotAngle, TBool& aFlipStatus) 
    {
    TRACER("CGlxBitmapDecoderWrapper:: DoCancel ");
    //Get the orientation and set rotation on the decoder 
    //as well as update the original size
    aRotAngle =  0;
    aFlipStatus = EFalse;
    TInt isOrientationOdd = aOrientation%2;
    if(aOrientation>8)
        {
        return;
        }
    if(aOrientation >= 3 && aOrientation < 5)
        {
        aRotAngle = 180;
        }
    else if(aOrientation >= 5 && aOrientation < 7)
        {
        aRotAngle = 90;

        }
    else if(aOrientation >= 7 && aOrientation <= 8)
        {
        aRotAngle = 270;
        }
    if(aOrientation>4 )
        {
        if(isOrientationOdd )
            {
            aFlipStatus = ETrue;
            }
        }   

    }

// ---------------------------------------------------------------------------
// OOMRequestFreeMemoryL
// ---------------------------------------------------------------------------
//
TInt CGlxBitmapDecoderWrapper::OOMRequestFreeMemoryL( TInt aBytesRequested)
    {
    TRACER("CGlxBitmapDecoderWrapper::OOMRequestFreeMemoryL");
    GLX_LOG_INFO1("CGlxBitmapDecoderWrapper::OOMRequestFreeMemoryL() aBytesRequested=%d",
            aBytesRequested);
    ROomMonitorSession oomMonitor;
    User::LeaveIfError( oomMonitor.Connect() );
    // No leaving code after this point, so no need to use cleanup stack
    // for oomMonitor
    TInt errorCode = oomMonitor.RequestFreeMemory( aBytesRequested );
    GLX_LOG_INFO1("CGlxBitmapDecoderWrapper::OOMRequestFreeMemoryL(1) errorCode=%d",errorCode);
    if ( errorCode != KErrNone )
        {
        // try one more time 
        errorCode = oomMonitor.RequestFreeMemory( aBytesRequested );
        GLX_LOG_INFO1("CGlxBitmapDecoderWrapper::OOMRequestFreeMemoryL(2) errorCode=%d",errorCode);
        }
    oomMonitor.Close();
    return errorCode;
    }