imagingmodules/jp2kcodec/Src/JP2KSubband.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:22:31 +0200
changeset 0 469c91dae73b
child 4 3993b8f65362
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2003, 2004 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:  JP2KSubband class used to collect the subband related
*                information such as list of packets and list of subbands.
*
*/


// INCLUDE FILES
#include <icl/imagecodec.h>
#include "JP2KImageUtils.h"
#include "JP2KFormat.h"
#include "JP2KStreamReader.h"
#include "JP2KTileInfo.h"
#include "JP2KImageInfo.h"
#include "JP2KCodec.h"
#include "JP2KPacket.h"
#include "JP2KSubband.h"
#include "JP2KComponentInfo.h"

// EXTERNAL DATA STRUCTURES

// EXTERNAL FUNCTION PROTOTYPES  

// CONSTANTS

// MACROS

// LOCAL CONSTANTS AND MACROS

// MODULE DATA STRUCTURES

// LOCAL FUNCTION PROTOTYPES

// FORWARD DECLARATIONS

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

// Destructor
CJ2kSubband::~CJ2kSubband()
    {
    iPacketList.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::BuildSubbandTreeL
// Static method to set up the tree structure of the DWT subbands.
// ( other items were commented in a header ).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubband::BuildSubbandTreeL( TUint8 aMaxLevel, CJ2kComponentInfo& aComponent )
    {
    CJ2kSubband *root = CJ2kSubbandLL::NewLC();
    root->iLevel = 0;

    // The root subband, LLO, original image
    root->iResLevel = (TUint8)( aMaxLevel + 1 ); 
    root->iSubbandCanvas = aComponent.ComponentCanvas();
    root->iHighPassFirst = TPoint( root->iSubbandCanvas.iTl.iX % 2,
                                   root->iSubbandCanvas.iTl.iY % 2 );
    CJ2kSubband *start = root;
    CJ2kSubband *tmpLL = 0;
    CJ2kSubband *tmpHL = 0;
    CJ2kSubband *tmpLH = 0;
    CJ2kSubband *tmpHH = 0;

    for ( TUint8 index = 1; index <= aMaxLevel; ++index )
        {
        // Must be built in the following order - LL, HL, LH, and HH
        // where all of them share the same parent - next lower LL
        // but only the LL subband can be further sub-divided into
        // lower resolution subband
        // create LL subband
        TUint8 highPassFirstX = (TUint8)( start->iHighPassFirst.iX );
        TUint8 highPassFirstY = (TUint8)( start->iHighPassFirst.iY );

        tmpLL = CJ2kSubbandLL::NewLC();
        tmpLL->iLevel = index;
        tmpLL->iResLevel = (TUint8)( aMaxLevel - index + 1 );

        tmpLL->iSubbandCanvas.iTl = TPoint( (TUint32)( start->iSubbandCanvas.iTl.iX + 1 ) >> 1,
                                            (TUint32)( start->iSubbandCanvas.iTl.iY + 1 ) >> 1 );

        tmpLL->iSubbandCanvas.SetWidth( ( start->iSubbandCanvas.Width() + ( 1-highPassFirstX ) ) / 2 );

        tmpLL->iSubbandCanvas.SetHeight( ( start->iSubbandCanvas.Height() + ( 1-highPassFirstY ) ) / 2 );

        tmpLL->iHighPassFirst = TPoint( tmpLL->iSubbandCanvas.iTl.iX % 2,
                                        tmpLL->iSubbandCanvas.iTl.iY % 2 );
        start->AddChildL( tmpLL );
        CleanupStack::Pop();

        // Create HL subband
        tmpHL = CJ2kSubbandNLL::NewLC();
        tmpHL->iType = EBandHL;
        tmpHL->iLevel = index;
        tmpHL->iGain  = 1;
        tmpHL->iResLevel = tmpLL->iResLevel;
        tmpHL->iSubbandCanvas.iTl = TPoint( (TUint32)start->iSubbandCanvas.iTl.iX >> 1,
                                            (TUint32)( start->iSubbandCanvas.iTl.iY + 1 ) >> 1 );
        tmpHL->iSubbandCanvas.SetWidth( ( start->iSubbandCanvas.Width() + highPassFirstX ) / 2 );
        tmpHL->iSubbandCanvas.SetHeight( tmpLL->iSubbandCanvas.Height() );
        tmpHL->iSubbandOrigin.iX = start->iSubbandOrigin.iX + ( ( start->iSubbandCanvas.Width() + ( 1-highPassFirstX ) ) / 2 );
        tmpHL->iSubbandOrigin.iY = start->iSubbandOrigin.iY;
        start->AddChildL( tmpHL );
        CleanupStack::Pop();

        // Create LH subband
        tmpLH = CJ2kSubbandNLL::NewLC();
        tmpLH->iType = EBandLH;
        tmpLH->iLevel = index;
        tmpLH->iGain  = 1;
        tmpLH->iResLevel = tmpLL->iResLevel;
        tmpLH->iSubbandCanvas.iTl = TPoint( (TUint32)( start->iSubbandCanvas.iTl.iX + 1 ) >> 1,
                                           (TUint32)start->iSubbandCanvas.iTl.iY >> 1 );
        tmpLH->iSubbandCanvas.SetWidth( tmpLL->iSubbandCanvas.Width() );

        tmpLH->iSubbandCanvas.SetHeight( ( start->iSubbandCanvas.Height() + highPassFirstY ) / 2 );
        tmpLH->iSubbandOrigin.iX = start->iSubbandOrigin.iX;

        tmpLH->iSubbandOrigin.iY = start->iSubbandOrigin.iY + ( ( start->iSubbandCanvas.Height() + ( 1-highPassFirstY ) ) / 2 );
        start->AddChildL( tmpLH );
        CleanupStack::Pop();

        // Create HH subband
        tmpHH = CJ2kSubbandNLL::NewLC();
        tmpHH->iType = EBandHH;
        tmpHH->iLevel = index;
        tmpHH->iGain  = 2;
        tmpHH->iResLevel = tmpLL->iResLevel;
        tmpHH->iSubbandCanvas.iTl = TPoint( ( TUint32 )start->iSubbandCanvas.iTl.iX >> 1,
                                           ( TUint32 )start->iSubbandCanvas.iTl.iY >> 1 );
        tmpHH->iSubbandCanvas.SetWidth( tmpHL->iSubbandCanvas.Width() );
        tmpHH->iSubbandCanvas.SetHeight( tmpLH->iSubbandCanvas.Height() );
        tmpHH->iSubbandOrigin.iX = tmpHL->iSubbandOrigin.iX;
        tmpHH->iSubbandOrigin.iY = tmpLH->iSubbandOrigin.iY;
        start->AddChildL( tmpHH );
        CleanupStack::Pop();

        start = start->ChildAt( EBandLL );
        }

    // The lowest resolution must be 0, so reset
    // the resolution of NLL from 1 to 0.
    start->iResLevel = 0;

    CleanupStack::Pop();
    return root;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::BuildPacketsL
// Build the possible packets that may be in the subband
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSubband::BuildPacketsL( CJ2kComponentInfo& aComponent, HBufC8 *aPrecinctSiz, TUint16 aLayer )
    {
    CJ2kSubband *subband = 0;
    CJ2kPacket  *packet = 0;
    TUint16 packetIndex = 0;
    TUint16 xIndex = 0;
    TUint16 yIndex = 0;
    TInt    denom = 0;
    TInt    ppx = 0;
    TInt    ppy = 0;
    TInt    ppxL = 0;
    TInt    ppyL = 0;
    TInt32  trx0 = 0;
    TInt32  try0 = 0;
    TInt32  trx1 = 0;
    TInt32  try1 = 0;
    TInt32  n = 0;
    TInt32  m = 0;
    TInt32  nOrig = 0;
    TInt32  mOrig = 0;
    TInt32  xCoord = 0;
    TInt32  yCoord = 0;
    TInt32  numOfPackets = 0;
    TInt32  tmpX = 0;
    TInt32  tmpY = 0;
    TSize   cblkSize( 0, 0 );
    TSize   tmpSize( 0, 0 );

    const TSize &compSize = aComponent.CodeBlockSize();
    TInt  compSizeLogWidth = TJ2kUtils::Log2( compSize.iWidth );
    TInt  compSizeLogHeight = TJ2kUtils::Log2( compSize.iHeight );

    for ( TUint8 resLevel = 0; resLevel <= aComponent.Levels(); ++resLevel )
        {
        subband = SubbandAt( resLevel );
        numOfPackets = aComponent.NumOfPackets( resLevel );
        if ( numOfPackets )
            {
            do
                {
                for ( packetIndex = 0; packetIndex < numOfPackets; ++packetIndex )
                    {
                    CJ2kPacket *packet = new ( ELeave ) CJ2kPacket( aLayer );   //lint !e578  must be declared also earlier.
                    CleanupStack::PushL( packet );
                    
                    User::LeaveIfError( subband->iPacketList.Append( packet ) );
                    CleanupStack::Pop( 1 );

                    if ( subband->iType == EBandLL || subband->iType == EBandHL )
                        {
                        subband->iPacketList[packetIndex]->BuildInclusiveInfoL();
                        }
                    }
                subband = subband->NextSubbandRaster();
                } while ( subband );

            // Set to the default
            ppx = ppy = 15;

            if ( aPrecinctSiz )
                {
                ppxL = ( *aPrecinctSiz )[resLevel] & 0x0f;
                ppyL = ( ( *aPrecinctSiz )[resLevel] & 0xf0 ) >> 4;
                }
            else
                {
                ppxL = ppyL = 15;
                }

            if ( ppxL != 15 || ppyL != 15 )
                {
                ppx = ( resLevel ) ? ppxL - 1 : ppxL;
                ppy = ( resLevel ) ? ppyL - 1 : ppyL;
                cblkSize.iWidth = ( compSizeLogWidth < ppx ) ? compSize.iWidth : 1 << ppx;
                cblkSize.iHeight = ( compSizeLogHeight < ppy ) ? compSize.iHeight : 1 << ppy;
                }
            else
                {
                cblkSize = compSize;
                }

            denom = 1 << ( aComponent.Levels() - resLevel );

            trx0 = TJ2kUtils::Ceil( aComponent.ComponentCanvas().iTl.iX, denom );
            try0 = TJ2kUtils::Ceil( aComponent.ComponentCanvas().iTl.iY, denom );
            trx1 = TJ2kUtils::Ceil( aComponent.ComponentCanvas().iBr.iX, denom );
            try1 = TJ2kUtils::Ceil( aComponent.ComponentCanvas().iBr.iY, denom );

            nOrig = ( trx0 / (  1 << ppxL  ) ) * ( 1 << ppxL );
            mOrig = ( try0 / (  1 << ppyL  ) ) * ( 1 << ppyL );

            // First subband at this resolution level
            // at r = 0, it will be nLL
            // at r > 0, it will be ( n-r+1 )HL

            tmpSize = aComponent.PrecinctSizeAt( resLevel );
            tmpX = 1 << ppx;
            tmpY = 1 << ppy;
            subband = SubbandAt( resLevel ); 
            do
                {
                if ( subband->SubbandCanvasSize().iWidth > 0 &&
                    subband->SubbandCanvasSize().iHeight > 0 )
                    {
                    n = nOrig;
                    m = mOrig;

                    if ( subband->iType != EBandLL )
                        {
                        n /= 2;
                        m /= 2;
                        }

                    yCoord = m;
                    for ( yIndex = 0; yIndex < tmpSize.iHeight; ++yIndex )
                        {
                        xCoord = n;
                        for ( xIndex = 0; xIndex < tmpSize.iWidth; ++xIndex )
                            {
                            // Reuse the variables trx0, trx1, try0, try1
                            trx0 = Max( subband->SubbandCanvas().iTl.iX, xCoord );
                            try0 = Max( subband->SubbandCanvas().iTl.iY, yCoord );
                            trx1 = Min( xCoord + tmpX, subband->SubbandCanvas().iBr.iX ) - trx0;
                            try1 = Min( yCoord + tmpY, subband->SubbandCanvas().iBr.iY ) - try0;

                            if ( trx1 > 0 && try1 > 0 )
                                {
                                packetIndex = ( TUint16 )( yIndex * tmpSize.iWidth + xIndex );
                                packet = subband->iPacketList[packetIndex];
                                packet->SetPacketCanvas( trx0, try0, trx1, try1 );
                                packet->SetNumOfBlocks( cblkSize );
                                packet->BuildCodeBlocksL( xCoord, yCoord, cblkSize );
                                }
                            xCoord += tmpX;
                            } // end of xIndex
                        yCoord += tmpY;
                        } // end of yIndex
                    } // precinct size is greater than 0
                subband = subband->NextSubbandRaster();
                } while ( subband );
            } // num of packets is greater than 0
        } // end of resolution level
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::LRCPProgressionL
// At each subband, parse the bitstream with LRCP progression order
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TUint8 CJ2kSubband::LRCPProgressionL( CJ2kTileInfo& aTile, CJ2kComponentInfo& aComponent )
    {
    TUint8  incomplete = EFalse;
    TUint16 marker = 0;
    const TJ2kStreamReader& reader = aTile.StreamReader();
    while ( iLastPacket < iPacketList.Count() )
        {       
        if ( aTile.IsPOC() )
            {
            marker = PtrReadUtil::ReadBigEndianUint16( reader.iPtr );
            if ( marker == KSOT || marker == KEOC )
                {
                break;   //lint !e960    Break is OK.
                }
            }

        incomplete = iPacketList[iLastPacket]->ReadPacketHeaderL( aTile, aComponent, *this );
        if ( incomplete )
            {
            // Underflow
            break;   //lint !e960    Break is OK.
            }
        if ( iPacketList[iLastPacket]->IsBodyIncomplete() )
            {
            incomplete = iPacketList[iLastPacket]->ReadPacketBodyL( aTile, aComponent, *this );
            if ( incomplete )
                {
                // Underflow
                break;   //lint !e960    Break is OK.
                }
            }
        iPacketList[iLastPacket]->ResetInternalFlags();
        ++iLastPacket;
        }

    if ( !incomplete && iLastPacket == iPacketList.Count() )
        {
        // Reset it back to 0 for the next layer
        iLastPacket = 0;
        }

    return incomplete;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::RPCLProgressionL
// At each subband, parse the bitstream with RPCL progression order
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TUint8 CJ2kSubband::RPCLProgressionL( CJ2kTileInfo& aTile, CJ2kComponentInfo& aComponent )
    {
    TUint8  incomplete = EFalse;
    TUint16 numOfLayers = aTile.NumOfLayersPOC();
    TUint16 marker = 0;
    const TJ2kStreamReader& reader = aTile.StreamReader();
    while ( aTile.LastLayerProcessed() < numOfLayers )
        {
        if ( iPacketList.Count() )
            {
            if ( aTile.IsPOC() )
                {
                marker = PtrReadUtil::ReadBigEndianUint16( reader.iPtr );
                if ( marker == KSOT || marker == KEOC )
                    {
                    break;   //lint !e960    Break is OK.
                    }
                }

            incomplete = iPacketList[iLastPacket]->ReadPacketHeaderL( aTile, aComponent, *this );
            if ( incomplete )
                {
                // Underflow
                break;   //lint !e960    Break is OK.
                }
            if ( iPacketList[iLastPacket]->IsBodyIncomplete() )
                {
                incomplete = iPacketList[iLastPacket]->ReadPacketBodyL( aTile, aComponent, *this );
                if ( incomplete )
                    {
                    // Underflow
                    break;   //lint !e960    Break is OK.
                    }
                }
            iPacketList[iLastPacket]->ResetInternalFlags();
            }
        aTile.IncrementLastLayerProcessed();
        }

    if ( !incomplete && aTile.LastLayerProcessed() == numOfLayers )
        {
        aTile.ResetLastLayerProcessed();
        ++iLastPacket;
        if ( iLastPacket == iPacketList.Count() )
            {
            iLastPacket = 0;
            }
        }
    return incomplete;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::CPRLProgressionL
// At each subband, parse the bitstream with CPRL progression order.
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TUint8 CJ2kSubband::CPRLProgressionL( CJ2kTileInfo& aTile, CJ2kComponentInfo& aComponent )
    {
    TUint8  incomplete = EFalse;
    TUint16 numOfLayers = aTile.NumOfLayersPOC();
    TUint16 marker = 0;
    const TJ2kStreamReader& reader = aTile.StreamReader();
    while ( aTile.LastLayerProcessed() < numOfLayers )
        {
        if ( iPacketList.Count() )
            {
            if ( aTile.IsPOC() )
                {
                marker = PtrReadUtil::ReadBigEndianUint16( reader.iPtr );
                if ( marker == KSOT || marker == KEOC )
                    {
                    break;   //lint !e960    Break is OK.
                    }
                }

            incomplete = iPacketList[iLastPacket]->ReadPacketHeaderL( aTile, aComponent, *this );
            if ( incomplete )
                {
                // Underflow
                break;   //lint !e960    Break is OK.
                }
            if ( iPacketList[iLastPacket]->IsBodyIncomplete() )
                {
                incomplete = iPacketList[iLastPacket]->ReadPacketBodyL( aTile, aComponent, *this );
                if ( incomplete )
                    {
                    // Underflow
                    break;   //lint !e960    Break is OK.
                    }
                }
            iPacketList[iLastPacket]->ResetInternalFlags();
            }
        aTile.IncrementLastLayerProcessed();
        }

    if ( !incomplete && aTile.LastLayerProcessed() == numOfLayers )
        {
        aTile.ResetLastLayerProcessed();
        ++iLastPacket;
        if ( iLastPacket == iPacketList.Count() )
            {
            iLastPacket = 0;
            }
        }
    return incomplete;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::ChildAt
// Get the child subband at specific index
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubband::ChildAt( TInt /*aBand*/ )
    {
    return 0;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::NextSubbandRaster
// Get the sibling subband
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubband::NextSubbandRaster()
    {
    return 0;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::SubbandAt
// Get the subband at specific resolution level
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubband::SubbandAt( TUint8 /*aResLevel*/ )
    {
    return 0;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::AddChildL
// Add the child subband into the list of child subbands ( No-op )
// -----------------------------------------------------------------------------
//
void CJ2kSubband::AddChildL( CJ2kSubband* /*aChild*/ )
    {    }

// -----------------------------------------------------------------------------
// CJ2kSubband::SubbandTreeIndex
// Get the subband tree index
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
TUint16 CJ2kSubband::SubbandTreeIndex() const
    {
    TUint16 bandIndex = 0;
    if ( iResLevel )
        {
        bandIndex = ( TUint16 )( ( iResLevel - 1 ) * 3 + iType );
        }

    return bandIndex;
    }

// -----------------------------------------------------------------------------
// CJ2kSubband::CJ2kSubband
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CJ2kSubband::CJ2kSubband() : 
    iPacketList( 1 )
    {
    }

// -----------------------------------------------------------------------------
// CJ2kSubbandLL::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CJ2kSubbandLL* CJ2kSubbandLL::NewLC()
    {
    CJ2kSubbandLL* self = new ( ELeave ) CJ2kSubbandLL();

    CleanupStack::PushL( self );
    self->iType = EBandLL;

    return self;
    }
    
// Destructor
CJ2kSubbandLL::~CJ2kSubbandLL()
    {
    iChildList.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CJ2kSubbandLL::ChildAt
// Get the child subband at specific index
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubbandLL::ChildAt( TInt aBand )
    {
    if ( iChildList.Count() > 0 )
        {
        return iChildList[aBand];
        }

    return 0;
    }

// -----------------------------------------------------------------------------
// CJ2kSubbandLL::SubbandAt
// Get the subband at specific resolution level
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubbandLL::SubbandAt( TUint8 aResLevel )
    {
    if ( iResLevel > aResLevel )
        {
        return ChildAt( EBandLL )->SubbandAt( aResLevel );
        }
    if ( iResLevel == 0 && aResLevel == 0 )
        {
        return this;
        }
    else
        {
        return Parent()->ChildAt( EBandHL );
        }
    }

// -----------------------------------------------------------------------------
// CJ2kSubbandLL::AddChildL
// Add the child subband into the list of child subbands
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CJ2kSubbandLL::AddChildL( CJ2kSubband* aChild )
    {
    aChild->SetParent( this );
    User::LeaveIfError( iChildList.Append( aChild ) );
    }

// -----------------------------------------------------------------------------
// CJ2kSubbandNLL::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CJ2kSubbandNLL* CJ2kSubbandNLL::NewLC()
    {
    CJ2kSubbandNLL* self = new ( ELeave ) CJ2kSubbandNLL();
    CleanupStack::PushL( self );
    return self;
    }

// Destructor
CJ2kSubbandNLL::~CJ2kSubbandNLL()
    { 
    }

// -----------------------------------------------------------------------------
// CJ2kSubbandNLL::NextSubbandRaster
// Get the sibling subband
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
CJ2kSubband* CJ2kSubbandNLL::NextSubbandRaster()
    {
    CJ2kSubband *nextSubband = 0;
    switch ( iType )
        {
        case EBandHL:
            {
            nextSubband = Parent()->ChildAt( EBandLH );
            break;
            }
        case EBandLH:
            {
            nextSubband = Parent()->ChildAt( EBandHH );
            break;
            }
        default:
            {
            break;
            }
        }

    return nextSubband;
    }