photosgallery/viewframework/texturemanager/src/glxbitmapdecoderwrapper.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 21 Jun 2010 15:40:32 +0300
branchRCL_3
changeset 47 f9e827349359
parent 32 78ad99c24f08
permissions -rw-r--r--
Revision: 201023 Kit: 2010125

/*
* 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>
#include <e32math.h>
#include <apgcli.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;
    
    _LIT(KMimeJpeg,"image/jpeg");
    _LIT(KMimeJpg,"image/jpg");
    }

// ---------------------------------------------------------------------------
// 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::CGlxBitmapDecoderWrapper()");
    }		

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CGlxBitmapDecoderWrapper::~CGlxBitmapDecoderWrapper()
    {
    TRACER("CGlxBitmapDecoderWrapper::~CGlxBitmapDecoderWrapper()");
    iFs.Close();
    Cancel();
    if (iImageDecoder)
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    if (iImagePath)
        {
        delete iImagePath;
        iImagePath = 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()");
    GLX_LOG_URI("CGlxBitmapDecoderWrapper::DoDecodeImageL(%S)",
            &aSourceFileName);

    iThumbnailIndex = aIndex;

#ifdef _DEBUG
    iStartTime.HomeTime();
#endif                          

    if (iImageDecoder)
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }

    CImageDecoder::TOptions options =
            (CImageDecoder::TOptions) (CImageDecoder::EOptionNoDither
                    | CImageDecoder::EOptionAlwaysThread);

    // Use extended JPEG decoder
    GLX_DEBUG1("DoDecodeImageL:: EHwImplementation" );
    TRAPD( err, iImageDecoder = CExtJpegDecoder::FileNewL(
                    CExtJpegDecoder::EHwImplementation, iFs,
                    aSourceFileName, options ) );
    GLX_DEBUG2("DoDecodeImageL:: EHwImplementation (%d)", err);
    if (KErrNone != err)
        {
        TRAP(err,iImageDecoder = CExtJpegDecoder::FileNewL(
                        CExtJpegDecoder::ESwImplementation, iFs,
                        aSourceFileName, options ) );
        GLX_DEBUG2("DoDecodeImageL:: ESwImplementation (%d)", err);
        if (KErrNone != err)
            {
            GLX_DEBUG1("DoDecodeImageL::CImageDecoder");
            // Not a JPEG - use standard decoder
            iImageDecoder = CImageDecoder::FileNewL(iFs, aSourceFileName,
                    options);
            }
        }
#ifdef _DEBUG
    iStopTime.HomeTime();
    GLX_DEBUG2("*** Decoder Creation took <%d> us ***",
            (TInt)iStopTime.MicroSecondsFrom(iStartTime).Int64());
#endif                          

    TSize imageSize = iImageDecoder->FrameInfo().iOverallSizeInPixels;
    GLX_DEBUG3("GlxDecoderWrapper::DecodeImageL() - OverallSize: w=%d, h=%d",
            imageSize.iWidth, imageSize.iHeight);
    iOriginalSize.iWidth = imageSize.iWidth;
    iOriginalSize.iHeight = imageSize.iHeight;

    if (iBitmap)
        {
        delete iBitmap;
        iBitmap = NULL;
        }
    
    if (iImagePath)
        {
        delete iImagePath;
        iImagePath = NULL;
        }
    iImagePath = aSourceFileName.Alloc();
    
    DecodeImageL();
    }

// ---------------------------------------------------------------------------
// DecodeImageL
// ---------------------------------------------------------------------------
//
void CGlxBitmapDecoderWrapper::DecodeImageL()
    {
    TRACER("CGlxBitmapDecoderWrapper::DecodeImageL()");
    TReal32 mFactor = 1;
    TReal mFactor1 = 1;
    TReal32 mFactor2 = 1;
    //Set Size according to level and state
    TReal32 width = iOriginalSize.iWidth;
    TReal32 height = iOriginalSize.iHeight;

    if (KGlxDecodingThreshold < (width * height))
        {
        TReal tempFactor = TReal32(KGlxDecodingThreshold)
                / (width * height);
        User::LeaveIfError(Math::Sqrt(mFactor1, tempFactor));
        GLX_DEBUG2("DecodeImageL() - mFactor1 = %f", mFactor1);
        }

    if (KGlxDecodingThresholdDimension < width
            || KGlxDecodingThresholdDimension < height)
        {
        mFactor2 = TReal32(KGlxDecodingThresholdDimension) / Max(width,
                height);
        GLX_DEBUG2("DecodeImageL() - mFactor2 = %f", mFactor2);
        }

    mFactor = Min(TReal32(mFactor1), mFactor2);
    GLX_DEBUG2("DecodeImageL() - 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_DEBUG3("DecodeImageL: minmemorytodecode=%d, freememory=%d",
                minmemorytodecode, freeMemory);
        
        iTargetBitmapSize.iWidth = width;
        iTargetBitmapSize.iHeight = height;
        GLX_DEBUG3("DecodeImageL: iTargetBitmapSize w=%d, h=%d",
                iTargetBitmapSize.iWidth, iTargetBitmapSize.iHeight);
        __ASSERT_DEBUG(width > 0 && height > 0, Panic(EGlxPanicIllegalArgument));      

        if (minmemorytodecode < (freeMemory - KGlxCriticalRAMForPhotos))
            {
            GLX_DEBUG1("DecodeImageL:RAM available decoding image");            
            iBitmap = new (ELeave) CFbsBitmap();
            iBitmap->Create(ReCalculateSizeL(),
                    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_DEBUG1("DecodeImageL:insufficient RAM - request OOM");
            TInt err = OOMRequestFreeMemoryL(minmemorytodecode);
            if (err == KErrNoMemory)
                {
                //if OOM fails, release Photos Cache
                GLX_DEBUG1("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_DEBUG1("DecodeImageL:Sufficient RAM available");                
                iBitmap = new (ELeave) CFbsBitmap();
                iBitmap->Create(ReCalculateSizeL(),
                        iImageDecoder->FrameInfo().iFrameDisplayMode);
#ifdef _DEBUG
                iStartTime.HomeTime(); // Get home time
#endif                          
                iImageDecoder->Convert(&iStatus, *iBitmap);
                }
            else
                {
                GLX_DEBUG1("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_DEBUG1("CGlxBitmapDecoderWrapper::RunL:Decoding Finished");
        iImageDecoder->Cancel();
        delete iImageDecoder;
        iImageDecoder = NULL;
#ifdef _DEBUG
        iStopTime.HomeTime();
        GLX_DEBUG2("*** Image Decode took <%d> us ***", 
                       (TInt)iStopTime.MicroSecondsFrom(iStartTime).Int64());            
#endif                          

        }
    }

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

// ---------------------------------------------------------------------------
// 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;
    }

// -----------------------------------------------------------------------------
// DoesMimeTypeNeedsRecalculateL()
// -----------------------------------------------------------------------------
//
TBool CGlxBitmapDecoderWrapper::DoesMimeTypeNeedsRecalculateL()
    {
    TRACER("CGlxBitmapDecoderWrapper::DoesMimeTypeNeedsRecalculateL");
    RApaLsSession session;
    TDataType mimeType;
    TUid uid;

    User::LeaveIfError(session.Connect());
    CleanupClosePushL(session);
    User::LeaveIfError(session.AppForDocument(iImagePath->Des(), uid,
            mimeType));
    CleanupStack::PopAndDestroy(&session);

    if (mimeType.Des().Compare(KMimeJpeg) == 0 || mimeType.Des().Compare(
            KMimeJpg) == 0)
        {
        GLX_LOG_INFO("CGlxBitmapDecoderWrapper::DoesMimeTypeNeedsRecalculateL - jpeg");
        return EFalse;
        }
    else
        {
        GLX_LOG_INFO("CGlxHdmiSurfaceUpdater::DoesMimeTypeNeedsRecalculateL - non jpeg");
        return ETrue;
        }
    }

// -----------------------------------------------------------------------------
// ReCalculateSize 
// -----------------------------------------------------------------------------
TSize CGlxBitmapDecoderWrapper::ReCalculateSizeL()
    {
    TRACER("CGlxBitmapDecoderWrapper::ReCalculateSizeL()");
    if (DoesMimeTypeNeedsRecalculateL())
        {
        TSize fullFrameSize = iImageDecoder->FrameInfo().iOverallSizeInPixels;
        // calculate the reduction factor on what size we need
        TInt reductionFactor = iImageDecoder->ReductionFactor(fullFrameSize,
                iTargetBitmapSize);
        // get the reduced size onto destination size
        TSize destSize;
        User::LeaveIfError(iImageDecoder->ReducedSize(fullFrameSize,
                reductionFactor, destSize));
        GLX_LOG_INFO2("CGlxBitmapDecoderWrapper::ReCalculateSizeL() "
                        "destSize=%d, %d",destSize.iWidth,destSize.iHeight);
        return destSize;
        }
    else
        {
        return iTargetBitmapSize;
        }
    }