imagingmodules/jp2kcodec/Src/JP2KSubband.cpp
changeset 0 469c91dae73b
child 4 3993b8f65362
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/imagingmodules/jp2kcodec/Src/JP2KSubband.cpp	Thu Dec 17 09:22:31 2009 +0200
@@ -0,0 +1,661 @@
+/*
+* 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;
+    }