diff -r 000000000000 -r 469c91dae73b imagingmodules/jp2kcodec/Src/JP2KEntropyDecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imagingmodules/jp2kcodec/Src/JP2KEntropyDecoder.cpp Thu Dec 17 09:22:31 2009 +0200 @@ -0,0 +1,1857 @@ +/* +* 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: Entropy decoder functionality.. +* +*/ + + +// INCLUDE FILES +#include "JP2KCodeBlock.h" +#include "JP2KTileInfo.h" +#include "JP2KImageInfo.h" +#include "JP2KEntropyDecoder.h" + +// EXTERNAL DATA STRUCTURES + +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS + +// Mq decoder state information, all of the 47 states contain +// the probability estimate of LPS in hexadecimal, the next +// mps state index, the next lps state index and the flag +// indicating a mps switch. +const TUint32 KMqQeStates[KNumberOriginalMQEntries] = {0x5601,0x3401,0x1801,0x0ac1,0x0521,0x0221,0x5601, + 0x5401,0x4801,0x3801,0x3001,0x2401,0x1c01,0x1601, + 0x5601,0x5401,0x5101,0x4801,0x3801,0x3401,0x3001, + 0x2801,0x2401,0x2201,0x1c01,0x1801,0x1601,0x1401, + 0x1201,0x1101,0x0ac1,0x09c1,0x08a1,0x0521,0x0441, + 0x02a1,0x0221,0x0141,0x0111,0x0085,0x0049,0x0025, + 0x0015,0x0009,0x0005,0x0001,0x5601}; + +const TInt32 KMqMpsStates[KNumberOriginalMQEntries] = {1,2,3,4,5,38,7,8,9,10,11,12,13,29,15,16,17,18,19, + 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35, + 36,37,38,39,40,41,42,43,44,45,45,46}; + +const TInt32 KMqLpsStates[KNumberOriginalMQEntries] = {1,6,9,12,29,33,6,14,14,14,17,18,20,21,14,14,15,16, + 17,18,19,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,46}; + +const TInt32 KMqSwitchFlagStates[KNumberOriginalMQEntries] = {1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0}; + +// MQCoder initial states +const TInt32 KMqInitStates[KNumberContexts] = {46,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +// MACROS + +// LOCAL CONSTANTS AND MACROS + +// MODULE DATA STRUCTURES + +// LOCAL FUNCTION PROTOTYPES + +// FORWARD DECLARATIONS + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// J2KEntropyStream::ReadByteFromStream +// Read a byte from the input stream +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TUint8 J2KEntropyStream::ReadByteFromStream() + { + if ( iPosition < iNumBytes ) + { + return ( TUint8 )iBuffer[iPosition++]; + } + else + { + // 0xFF to represent EOF + return ( 0xFF ); + } + } + +// ----------------------------------------------------------------------------- +// J2KEntropyStream::ReadBitFromStream +// Read a bit from the input stream +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TUint8 J2KEntropyStream::ReadBitFromStream() + { + if ( iTinyBufferPos == 0 ) + { + // Input the byte buffer + iTinyBuffer = ReadByteFromStream(); + + if ( iDelayedFF ) + { + iTinyBufferPos = 7; + } + else + { + iTinyBufferPos = 8; + } + + if ( iTinyBuffer != 0xFF ) // No bit-stuffing needed + { + iDelayedFF = 0; + } + else // We need to do bit stuffing on next byte + { + iDelayedFF = 1; + } + } + + return (TUint8)( ( iTinyBuffer >> ( --iTinyBufferPos ) ) & 0x01 ); + } + +// ----------------------------------------------------------------------------- +// J2KEntropyStream::CheckPrediction +// Check a prediction termination for raw coding +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TEntropyErrorState J2KEntropyStream::CheckPrediction() + { + // Error resilient sequence in last byte + TInt32 errorResSeq = 0; + + // If tiny buffer is empty and equal to 0xFF, + // get the next byte for error resilience marker + if ( iTinyBufferPos == 0 && iTinyBuffer == 0xFF ) + { + iTinyBuffer = ReadByteFromStream(); + iTinyBufferPos = 7; + } + + // Search for the error resilience marker + if ( iTinyBufferPos > 0 ) + { + // Get the error resilience sequence + errorResSeq = iTinyBuffer & ( ( 1 << iTinyBufferPos ) - 1 ); + + // Compare the read error resilience marker to the constant 01010101 byte + if ( errorResSeq != ( KErrorResilienceTermination >> ( 8 - iTinyBufferPos ) ) ) + { + return EEntropyCodingError; + } + } + + // If we are not at the end of this stream, + // next byte should be smaller than 0x80. + if ( iPosition < iNumBytes ) + { + if ( iTinyBuffer == 0xFF && iTinyBufferPos == 1 ) + { + if ( ReadByteFromStream() >= 0x80 ) + { + return EEntropyCodingError; + } + } + else + { + if ( ReadByteFromStream() != 0xFF ) + { + return EEntropyCodingError; + } + } + } + + // No error detected + return ENoError; + } + +// ----------------------------------------------------------------------------- +// J2KEntropyStream::ResetInputStream +// Reset the input stream +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KEntropyStream::ResetInputStream() + { + // Initialize the stream parameters. Note that stream->position is not reset here, + // it is reset only when the stream is created for the first time. + iTinyBuffer = 0; + iTinyBufferPos = 0; + iDelayedFF = 0; + } + +// ============================ MEMBER FUNCTIONS =============================== + +// Destructor +J2KMQCoder::~J2KMQCoder() + { + iOriginalStates.ResetAndDestroy(); + iContextList.ResetAndDestroy(); + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::MqByteIn +// Read a byte from the input stream +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::MqByteIn() + { + if ( !iMarker ) + { + if ( iB == 0xff ) + { + iB = iInputStream.ReadByteFromStream(); + + if ( iB > 0x8f ) + { + iMarker = 1; + iCT = 8; + } + else + { + iC += 0xFE00 - ( iB << 9 ); + iCT = 7; + } + } + else + { + iB = iInputStream.ReadByteFromStream(); + iC += 0xFF00 - ( iB << 8 ); + iCT = 8; + } + } + else + { + iCT = 8; + } + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::MqDecodeSymbol +// Decode the symbol +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TUint8 J2KMQCoder::MqDecodeSymbol( TInt32 aContextIndex ) + { + // Set the current context to point to the right place in the context list + iCurrentContext = iContextList[aContextIndex]; + iCurrentState = iCurrentContext->iState; + + iA -= iCurrentState->iQe; + + // Decision returned ( i.e. decoded symbol ) + TInt32 decision = 0; + if ( ( iC >> 16 ) < iA ) // Chigh >= A + { + MpsExchange( decision ); + } + else // lps exchange + { + LpsExchange( decision ); + } + + // Return decision + return (TUint8)decision; + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::MqInitDecoder +// Initialize the MQCoder +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::MqInitDecoder() + { + iMarker = 0; + iB = iInputStream.ReadByteFromStream(); + + // Software conventions decoder initialization + iC = ( iB ^ 0xFF ) << 16; + MqByteIn(); + + iC <<= 7; + iCT -= 7; + iA = 0x8000; + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::MqCheckPrediction +// Check the prediction termination +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +TEntropyErrorState J2KMQCoder::MqCheckPrediction() + { + // If no marker was found, B should be == 0xFF and counter zero, + // otherwise there is an error + if ( !iMarker && ( iCT != 0 || iB != 0xFF ) ) + { + return EEntropyCodingError; + } + + // If counter CT is 1, no need to check any further + if ( iCT == 1 ) + { + return ENoError; + } + + // If counter CT is zero, then next byte must be larger than 0x8F, if the terminating + // marker has not been reached yet + if ( iCT == 0 ) + { + if ( !iMarker ) + { + // Get next byte and check that it is larger than 0x8F + iB = iInputStream.ReadByteFromStream(); + if ( iB <= 0x8F ) + { + return EEntropyCodingError; + } + } + // Set the counter back to 8 + iCT = 8; + } + + // Number of bits that where added in the termination process + // Compute the number of bits, k for error resilience information + TUint32 k = (TUint32)( iCT - 1 ); + + // Check for a coded LPS. + TUint32 q = 0x8000 >> k; + + // Check that we can decode an LPS interval of probability 'q' + iA -= q; + if ( ( iC >> 16 ) < iA ) // software convention + { + // MPS interval was decoded, thus error occured + return EEntropyCodingError; + } + + // Check for coded LPS interval. + iA = q; + + do // Renormalization + { + if ( iCT == 0 ) + { + MqByteIn(); + } + + iA <<= 1; + iC <<= 1; + iCT--; + + } while ( iA < 0x8000 ); + + // No error was found + return ENoError; + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::ResetMqContexts +// Reset the MQCoder context list to the original state +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::ResetMqContexts() + { + // Reset all context states to initial states and set the mps + // of every context to 0. + for ( TInt32 i = KNumberContexts - 1; i >= 0; i-- ) + { + iContextList[i]->iState = iOriginalStates[KMqInitStates[i]]; + iContextList[i]->iMPS = 0; + } + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::ResetMQDecoder +// Initialze MQCoder and reset the context +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::ResetMQDecoder( TInt32 aSegmentLength ) + { + // Reset all contexts ( states and mps ) + ResetMqContexts(); + iInputStream.ResetInputStream(); + iInputStream.iPosition = 0; + iInputStream.iNumBytes = aSegmentLength; + MqInitDecoder(); + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::InitializeOrigMqTable +// Initialize MQCoder original states table +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::InitializeOrigMqTable() + { + for ( TUint8 i = 0; i < KNumberOriginalMQEntries; i++ ) + { + iOriginalStates[i]->iQe = KMqQeStates[i]; + iOriginalStates[i]->iNextMPS = iOriginalStates[KMqMpsStates[i]]; + iOriginalStates[i]->iNextLPS = iOriginalStates[KMqLpsStates[i]]; + iOriginalStates[i]->iSwitchFlag = KMqSwitchFlagStates[i]; + } + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::ReNormalize +// Renormalize +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::ReNormalize() + { + do + { + if ( iCT == 0 ) + { + MqByteIn(); + } + + iA <<= 1; + iC <<= 1; + --iCT; + } while ( !( iA & 0x8000 ) ); + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::MpsExchange +// MPS exchange +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::MpsExchange( TInt32& aD ) + { + aD = iCurrentContext->iMPS; + if ( !( iA & 0x8000 ) ) + { + if ( iA < iCurrentState->iQe ) + { + aD ^= 1; + if ( iCurrentState->iSwitchFlag ) + { + iCurrentContext->iMPS ^= 1; + } + + iCurrentContext->iState = iCurrentState->iNextLPS; + } + else + { + iCurrentContext->iState = iCurrentState->iNextMPS; + } + + ReNormalize(); + } + } + +// ----------------------------------------------------------------------------- +// J2KMQCoder::LpsExchange +// LPS exchange +// ( other items were commented in a header ). +// ----------------------------------------------------------------------------- +// +void J2KMQCoder::LpsExchange( TInt32& aD ) + { + iC -= iA << 16; + aD = iCurrentContext->iMPS; + if ( iA < iCurrentState->iQe ) + { + iCurrentContext->iState = iCurrentState->iNextMPS; + } + else + { + aD ^= 1; + if ( iCurrentState->iSwitchFlag ) + { + iCurrentContext->iMPS ^= 1; + } + + iCurrentContext->iState = iCurrentState->iNextLPS; + } + iA = iCurrentState->iQe; + ReNormalize( ); + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CJ2kEntropyDecoder* CJ2kEntropyDecoder::NewL( CJ2kImageInfo& aImageInfo ) + { + CJ2kEntropyDecoder *self = new ( ELeave ) CJ2kEntropyDecoder; + + CleanupStack::PushL( self ); + self->ConstructL( aImageInfo ); + CleanupStack::Pop(); + + return self; + } + +// Destructor +CJ2kEntropyDecoder::~CJ2kEntropyDecoder() + { + delete iMRLutBuf; + iMRLutBuf = 0; + + delete iSCLutBuf; + iSCLutBuf = 0; + + delete iZcLutLL; + iZcLutLL = 0; + + delete iZcLutHL; + iZcLutHL = 0; + + delete iZcLutHH; + iZcLutHH = 0; + + TJ2kUtils::Free2DArray( iData ); + User::Free( iStates ); + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::SetNewSizeL +// Set the size of internal buffer and other control data +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::SetNewSizeL( const TSize& aSize ) + { + if ( aSize.iWidth <= iCurrentSize.iWidth && + aSize.iHeight <= iCurrentSize.iHeight ) + { + return; + } + else + { + iCurrentSize = aSize; + + TJ2kUtils::Free2DArray( iData ); + iData = 0; + iData = TJ2kUtils::Alloc2DArrayL( iCurrentSize.iHeight, iCurrentSize.iWidth ); + + iMaxBlockWidth = (TUint8)( iCurrentSize.iWidth ); + + // We can compute some parameters for entropy decoding here not to compute them for every pass!!! + iBlockDataWidth = iMaxBlockWidth; + iStateWidth = iMaxBlockWidth + 2; + iStateSize = ( iCurrentSize.iHeight + 2 ) * ( iCurrentSize.iWidth + 2 ); + iDataSamplesPerStripe = iBlockDataWidth * KStripeHeight; + iStateSamplesPerStripe = iStateWidth * KStripeHeight; + + TInt16* ptrTemp = STATIC_CAST( TInt16*, User::ReAlloc( iStates, iStateSize * sizeof( TInt16 ) ) ); + if ( !ptrTemp ) + { + User::Leave( KErrNoMemory ); + } + iStates = ptrTemp; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::SetCurrentZCLUT +// Set the current pointer to point to the right LUT depending on the current subband +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::SetCurrentZCLUT( TUint8 aBandIndex ) + { + if ( aBandIndex == 1 ) + { + // For HL band + iCurrentZcLutPtr = (TUint8*)iZcLutHL->Des().Ptr(); + } + else if ( aBandIndex == 3 ) + { + // For HH band + iCurrentZcLutPtr = (TUint8*)iZcLutHH->Des().Ptr(); + } + else + { + // For LL and LH band + iCurrentZcLutPtr = (TUint8*)iZcLutLL->Des().Ptr(); + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::DecodeCodeblock +// Decode the coded codeblock +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::DecodeCodeblock( CJ2kCodeBlock& aCodeblock, TUint8 aCblkStyle, + TUint8 aMagBits ) + { + TInt32 startBitplane = 0; // The bitplane where coding starts + TInt32 endBitplane = 0; // The last coded bitplane + TInt32 terminationLength = 0; + TUint8 tempPassIndex = 0; + TUint8 passIndex = 0; + + iMQDecoder.iInputStream.iBuffer = CONST_CAST( TUint8*, aCodeblock.Data() ); + TSize codeBlockSize = aCodeblock.CodeBlockCanvas().Size(); + + iVerticalCausalContextUsed = ( ( aCblkStyle & EVerticalStripe ) != 0 ); + iResetContexts = ( ( aCblkStyle & EResetContext ) != 0 ); + iPredictableTerminationUsed = ( ( aCblkStyle & EPredictableTermination ) != 0 ); + TUint8 terminateEachPass = ( ( aCblkStyle & ETermination ) != 0 ); + TUint8 segmentationSymbolsUsed = ( ( aCblkStyle & ESegmentationSymbols ) != 0 ); + TUint8 arithmeticBypass = ( ( aCblkStyle & EArithmeticBypass ) != 0 ); + aCodeblock.ResetPassIndex(); + + + // Initialize the stream and the mq coder for this code block: + // also set mq coder's stream to point to aCodeblock's stream + if ( !arithmeticBypass && !terminateEachPass ) // No termination + { + iMQDecoder.ResetMQDecoder( aCodeblock.DataLength() ); + } + else + { + // Compute the length of the first terminated segment. If we are + // terminating on each pass, terminated lengths are equal to + // codeblock lengths. On the other hand if we are using arithmetic + // bypass ( without terminating each pass ), the first termination length + // is the codeblock lengths summed up to the point where we have last AC + // pass before first raw coding pass. + + if ( terminateEachPass ) + { + terminationLength = aCodeblock.CblkLength( (TUint16)passIndex++ ); + } + else // AC bypass without termination on each pass + { + // Loop adding codeblock lengths until enough passes have been consumed + while ( ( tempPassIndex < KFirstBypassTermIndex ) && ( passIndex <= aCodeblock.LastPass() ) ) + { + tempPassIndex = (TUint8)( tempPassIndex + aCodeblock.PassesPerSegment( passIndex ) ); + terminationLength = (TUint32)( terminationLength + aCodeblock.CblkLength( passIndex++ ) ); + } + } + + // Now initialize the iMQDecoder with the right terminated length + iMQDecoder.ResetMQDecoder( terminationLength ); + } + + // Initialize data array + for ( TInt i = codeBlockSize.iHeight - 1; i >= 0; i-- ) + { + Mem::FillZ( iData[i], codeBlockSize.iWidth * sizeof( TPrecInt ) ); + } + + // Initialize iStates array + Mem::FillZ( iStates, iStateSize * sizeof( TInt16 ) ); + + // Compute different bitplanes; empty bitplanes tells how many bitplanes are + // empty in this codeblock compared to the whole subband, iStartBitplane gives + // the index of the first bitplane to be coded for this block and iEndBitplane + // is the index of the last bitplane coded for this codeblock. + + // Compute coded block's magnitude bits + aMagBits = (TUint8)( aMagBits - aCodeblock.EmptyBitplanes() ); + startBitplane = ( KImplementationPrecision - 2 ) - aCodeblock.EmptyBitplanes(); + endBitplane = startBitplane - aMagBits; + + // Compute the number of stripes for this codeblock + iNumStripes = (TUint16)( ( codeBlockSize.iHeight + KStripeHeight - 1 ) / KStripeHeight ); + iBlockWidth = codeBlockSize.iWidth; + + // Compute the last stripe's height once, + // so that we don't have to compute it for all passes! + iLastStripeHeight = codeBlockSize.iHeight - ( iNumStripes - 1 ) * KStripeHeight; + + iCurrentBitplane = (TUint8)( startBitplane ); + + // First do only the normalization pass + iTerminateThisPass = ( terminateEachPass || ( iCurrentBitplane == endBitplane ) ); + + CleanupPass( segmentationSymbolsUsed ); + + aCodeblock.IncrementPassIndex(); + + iCurrentBitplane--; + + // Then repeat the three passes: significance, refinement and normalization + // for the remaining bitplanes. + while ( aCodeblock.PassIndex() <= aCodeblock.LastPass() ) + { + // Significance pass, terminate only if terminating after each pass + iTerminateThisPass = terminateEachPass; + + if ( ( arithmeticBypass == 0 ) || ( aCodeblock.PassIndex() < KFirstLazyPassIndex ) ) + { + if ( terminateEachPass ) // if last pass was terminated, initialize MQ-coder + { + // Update the number of available TUint8s for this terminated sequence + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex++ ); + iMQDecoder.MqInitDecoder(); + } + + SignificancePass(); + } + else + { + // if we are here, then the previous pass was terminated + if ( terminateEachPass ) + { + // Update the number of available bytes for this terminated sequence + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex++ ); + } + else // AC bypass without termination on each pass + { + // Here we have two cases: + // 1. If this codeblock length is for this pass only, then for the terminated length + // we have to add the next pass codeblock length also. + // 2. This codeblock length is for both this pass ( significance ) and the next pass + // ( refinement ). Terminated length is equal to the CblkLength[iPassIndex]. + if ( aCodeblock.PassesPerSegment( passIndex ) == 2 ) + { + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex++ ); + } + else + { + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex ) + + aCodeblock.CblkLength( (TUint16)( passIndex + 1 ) ); + passIndex += 2; + } + } + iMQDecoder.iInputStream.ResetInputStream(); + LazySignificancePass(); + } + + aCodeblock.IncrementPassIndex(); + if ( aCodeblock.PassIndex() > aCodeblock.LastPass() ) + { + // We have fully decoded this codeblock + return; + } + + // Magnitude refinement pass, terminate if raw coding or termination after each pass + iTerminateThisPass = ( terminateEachPass || ( arithmeticBypass && ( aCodeblock.PassIndex() > + KFirstLazyPassIndex ) ) ); + + if ( arithmeticBypass == 0 || ( aCodeblock.PassIndex() < KFirstLazyPassIndex ) ) + { + if ( terminateEachPass ) // if previous pass was terminated, initialize MQ-coder + { + // Update the number of available bytes for this terminated sequence + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex++ ); + iMQDecoder.MqInitDecoder(); + } + + RefinementPass(); + } + else + { + if ( terminateEachPass ) // if previous pass was terminated + { + // Update the number of available bytes for this terminated sequence + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex++ ); + iMQDecoder.iInputStream.ResetInputStream(); + } + + LazyRefinementPass(); + } + + aCodeblock.IncrementPassIndex(); + if ( aCodeblock.PassIndex() > aCodeblock.LastPass() ) + { + // We have fully decoded this codeblock + return; + } + + // Cleanup pass, terminate if coding raw, termination after each pass, last bitplane + // before starting raw coding or last bitplane in this codeblock. + iTerminateThisPass = ( terminateEachPass || ( iCurrentBitplane == endBitplane ) || + ( arithmeticBypass && ( aCodeblock.PassIndex() >= KFirstLazyPassIndex ) ) ); + + // If last ( AC ) pass was terminated, initialize MQ-coder + if ( terminateEachPass || ( arithmeticBypass && ( aCodeblock.PassIndex() > KFirstLazyPassIndex ) ) ) + { + // Update the number of available bytes for this terminated sequence + iMQDecoder.iInputStream.iNumBytes += aCodeblock.CblkLength( passIndex++ ); + iMQDecoder.MqInitDecoder(); + } + + CleanupPass( segmentationSymbolsUsed ); + + aCodeblock.IncrementPassIndex(); + if ( aCodeblock.PassIndex() > aCodeblock.LastPass() ) + { + // We have fully decoded this codeblock + return; + } + + // move onto next bitplane + if ( iCurrentBitplane == 0 ) // This might happen with 16-bit and ROI + { + // We have fully decoded this codeblock + return; + } + + iCurrentBitplane--; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::ConstructL( CJ2kImageInfo& aImageInfo ) + { + iCurrentSize = aImageInfo.MaxBlockSize(); + + for ( TUint16 i = 0; i < KNumberContexts; i++ ) + { + J2KEntropyContexts *context = new ( ELeave ) J2KEntropyContexts; + CleanupStack::PushL( context ); + User::LeaveIfError( iMQDecoder.iContextList.Append( context ) ); + CleanupStack::Pop(1); + } + + for ( TUint16 ii = 0; ii < KNumberOriginalMQEntries; ii++ ) + { + J2KEntropyStates *state = new ( ELeave ) J2KEntropyStates; + CleanupStack::PushL( state ); + User::LeaveIfError( iMQDecoder.iOriginalStates.Append( state ) ); + CleanupStack::Pop(1); + } + + // Allocate memory for the SC Look up table + iSCLutBuf = HBufC8::NewL( KLutSize ); + iSCLut = CONST_CAST( TUint8*, iSCLutBuf->Des().Ptr() ); + + // Allocate memory for the MR Look up table + iMRLutBuf = HBufC8::NewL( KLutSize ); + iMRLut = CONST_CAST( TUint8*, iMRLutBuf->Des().Ptr() ); + + // Allocate memory for the Zero coding Look up table + iZcLutLL = HBufC8::NewL( ( 1 << KZcLutBits ) ); + iZcLutHL = HBufC8::NewL( ( 1 << KZcLutBits ) ); + iZcLutHH = HBufC8::NewL( ( 1 << KZcLutBits ) ); + + iData = TJ2kUtils::Alloc2DArrayL( iCurrentSize.iHeight, iCurrentSize.iWidth ); + + iMaxBlockWidth = (TUint16)( iCurrentSize.iWidth ); + + // We can compute some parameters for entropy decoding here not to compute them for every pass!!! + iBlockDataWidth = iMaxBlockWidth; + iStateWidth = iMaxBlockWidth + 2; + iStateSize = ( iCurrentSize.iHeight + 2 ) * ( iCurrentSize.iWidth + 2 ); + iDataSamplesPerStripe = iBlockDataWidth * KStripeHeight; + iStateSamplesPerStripe = iStateWidth * KStripeHeight; + + iStates = STATIC_CAST( TInt16*, User::AllocL( iStateSize * sizeof( TInt16 ) ) ); + + // Initialization of the MQ tables needed since + // the original table could not be used as it was constant! + iMQDecoder.InitializeOrigMqTable(); + + iMaxBitDepth = 0; + for ( TUint16 iii = 0; iii < aImageInfo.NumOfComponents(); ++iii ) + { + iMaxBitDepth = Max( iMaxBitDepth, aImageInfo.DepthOfComponent( iii ) ); + } + + // Initialize ZC lookup table + InitializeZCLut(); + + // Initialize SC/MR lookup table + InitializeScMrLut(); + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::InitializeZCLut +// Initialize ZC lookup table +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::InitializeZCLut() + { + // Create pointers for all the ZC LUT's + TUint8* iZcLutLLPtr = CONST_CAST( TUint8*, iZcLutLL->Des().Ptr() ); + TUint8* iZcLutHLPtr = CONST_CAST( TUint8*, iZcLutHL->Des().Ptr() ); + TUint8* iZcLutHHPtr = CONST_CAST( TUint8*, iZcLutHH->Des().Ptr() ); + + TInt32 ctxt = 0; + TUint16 sh = 0; // horizontal sum + TUint16 sv = 0; // vertical sum + TUint16 sd = 0; // diagonal sum + + for ( TUint16 i = 0; i <= KZcMask; i++ ) + { + sh = (TUint16)( ( ( i >> KPositionRight ) & 1 ) + ( ( i >> KPositionLeft ) & 1 ) ); + sv = (TUint16)( ( ( i >> KPositionDown ) & 1 ) + ( ( i >> KPositionUp ) & 1 ) ); + sd = (TUint16)( ( ( i >> KPositionUpperLeft ) & 1 ) + ( ( i >> KPositionUpperRight ) & 1 ) + + ( ( i >> KPositionLowerLeft ) & 1 ) + ( ( i >> KPositionLowerRight ) & 1 ) ); + + if ( sh == 2 ) + { + ctxt = 10; + } + else if ( sh == 1 ) + { + if ( sv ) + { + ctxt = 9; + } + else if ( sd ) + { + ctxt = 8; + } + else + { + ctxt = 7; + } + } + else + { + if ( sv ) + { + ctxt = 4 + sv; + } + else + { + ctxt = 2 + ( ( sd > 2 ) ? 2 : sd ); + } + } + + iZcLutLLPtr[i] = (TUint8) ctxt; + + + if ( sv == 2 ) + { + ctxt = 10; + } + else if ( sv == 1 ) + { + if ( sh ) + { + ctxt = 9; + } + else if ( sd ) + { + ctxt = 8; + } + else + { + ctxt = 7; + } + } + else + { + if ( sh ) + { + ctxt = 4 + sh; + } + else + { + ctxt = 2 + ( ( sd > 2 ) ? 2 : sd ); + } + } + + iZcLutHLPtr[i] = (TUint8) ctxt; + + if ( sd >= 3 ) + { + ctxt = 10; + } + else if ( sd == 2 ) + { + if ( ( sv + sh ) >= 1 ) + { + ctxt = 9; + } + else + { + ctxt = 8; + } + } + else if ( sd == 1 ) + { + ctxt = 5 + ( ( ( sv + sh ) > 2 ) ? 2 : ( sv + sh ) ); + } + else + { + ctxt = 2 + ( ( ( sv + sh ) > 2 ) ? 2 : ( sv + sh ) ); + } + + iZcLutHHPtr[i] = (TUint8) ctxt; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::InitializeScMrLut +// Initialize SC/MR lookup table +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::InitializeScMrLut() + { + TInt32 ctxt = 0; + TInt32 vpos = 0; // vert + + TInt32 vneg = 0; // vert - + TInt32 hpos = 0; // hor + + TInt32 hneg = 0; // hor - + TInt32 hc = 0; // horizontal contribution + TInt32 vc = 0; // vertical contribution + TInt16 predict = 0; // the xor bit for differentiating states. ( positioned at the 6th bit ) + + for ( TUint8 i = 0; i < 16; i++ ) + { + vpos = i & 1; + vneg = ( i >> 1 ) & 1; + hpos = ( i >> 2 ) & 1; + hneg = ( i >> 3 ) & 1; + hc = hpos - hneg; + vc = vpos - vneg; + predict = 0; + if ( hc < 0 ) + { + predict = 1; + hc = -hc; + vc = -vc; + } + if ( hc == 0 ) + { + if ( vc < 0 ) + { + predict = 1; + vc = -vc; + } + ctxt = 11 + vc; + } + else + { + ctxt = 14 + vc; + } + + iSCLut[i] = (TUint8) ( ctxt | ( predict << KPredictionBit ) ); + } + iMRLut[0] = 16; + iMRLut[1] = 17; + iMRLut[2] = 18; + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::GetCausal +// Get the casual +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::GetCausal( TPrecInt*& aDataCol, TInt16*& aStateCol ) + { + TInt32 vpos = 0; + TInt32 vneg = 0; + TUint16 state = 0; + TInt16 causalityMask = 0; + + aDataCol--; + for ( TInt32 col = iStateWidth; col > 0; col-- ) + { + state = *aStateCol; + vpos = 0; + vneg = 0; + if ( ( ( state >> KPositionDown ) & 1 ) == 1 ) + { + if ( ( ( state >> KPositionUp ) & 1 ) == 1 ) + { + if ( col < iStateWidth ) + { + if ( *aDataCol >= 0 ) + { + vneg = 1; + } + else + { + vpos = 1; + } + } + } + else + { + vpos = 1; + vneg = 1; + } + } + causalityMask = (TInt16)( ~( ( KStateDown| KStateLowerLeft | KStateLowerRight ) | + ( vneg << KPositionVerNeg ) | ( vpos << KPositionVerPos ) ) ); + + ( *aStateCol ) &= causalityMask; + aDataCol++; + aStateCol++; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::DecodeSignificance +// Decode the significance bit +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::DecodeSignificance( TPrecInt*& aDataValue, TInt16*& aStateValue, TPrecInt aMask ) + { + TUint32 state = *aStateValue; + TInt32 context = state & KZcMask; + if ( ( state & KStateSignificant ) == 0 && context > 0 ) + { + if ( iMQDecoder.MqDecodeSymbol( iCurrentZcLutPtr[context] ) != 0 ) + { + TUint32 ctxt = iSCLut[( state >> KScShift ) & KScLutMask]; + TInt32 symbol = iMQDecoder.MqDecodeSymbol( ( ctxt & KScLutMask ) ) ^ ( ( ctxt >> KPredictionBit ) & 1 ); + *aDataValue = ( symbol << KSignShift ) | aMask; + *aStateValue |= KStateSignificant | KStateVisited; + UpdateSignificance( aStateValue, symbol ); + } + else + { + ( *aStateValue ) |= KStateVisited; + } + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::DecodeRawSignificance +// Decode the lazy significance bit +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::DecodeRawSignificance( TPrecInt*& aDataValue, TInt16*& aStateValue, TPrecInt aMask ) + { + TInt32 state = *aStateValue; + if ( ( state & KStateSignificant ) == 0 && ( state & KZcMask ) > 0 ) + { + if ( iMQDecoder.iInputStream.ReadBitFromStream() ) + { + TInt32 symbol = iMQDecoder.iInputStream.ReadBitFromStream(); + *aDataValue = ( symbol << KSignShift ) | aMask; + *aStateValue |= KStateSignificant | KStateVisited; + UpdateSignificance( aStateValue, symbol ); + } + else + { + ( *aStateValue ) |= KStateVisited; + } + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::DecodeRefinement +// Decode the refinement bit +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::DecodeRefinement( TPrecInt*& aDataValue, TInt16*& aStateValue, + TPrecInt aMask, TInt32 aResetMask ) + { + TInt32 state = *aStateValue; + if ( ( state & ( KStateSignificant | KStateVisited ) ) == KStateSignificant ) + { + TInt16 mrContext = (TInt16)( state & KStatePreviousMR ); + TInt32 ctxt = 0; + if ( mrContext ) + { + ctxt = 2; + } + else + { + if ( ( state & KZcMask ) == 0 ) + { + ctxt = 0; + } + else + { + ctxt = 1; + } + } + TInt32 symbol = iMQDecoder.MqDecodeSymbol( iMRLut[ctxt] ); + ( *aDataValue ) &= aResetMask; + ( *aDataValue ) |= ( symbol << iCurrentBitplane ) | aMask; + ( *aStateValue ) |= KStatePreviousMR; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::DecodeRawRefinement +// Decode the lazy refinement bit +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::DecodeRawRefinement( TPrecInt*& aDataValue, TInt16*& aStateValue, + TPrecInt aMask, TInt32 aResetMask ) + { + if ( ( ( *aStateValue ) & ( KStateSignificant | KStateVisited ) ) == KStateSignificant ) + { + TInt32 symbol = iMQDecoder.iInputStream.ReadBitFromStream(); + ( *aDataValue ) &= aResetMask; + ( *aDataValue ) |= ( symbol << iCurrentBitplane ) | aMask; + ( *aStateValue ) |= KStatePreviousMR; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::DecodeNormalization +// Perform the normalization +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::DecodeNormalization( TPrecInt*& aDataValue, TInt16*& aStateValue, + TPrecInt aMask, TInt32& aZCValue ) + { + TUint32 state = *aStateValue; + if ( state < (TUint32)KStateVisited ) + { + TInt32 symbol = 0; + TUint32 ctxt = 0; + if ( aZCValue == 1 ) + { + ( *aStateValue ) &= ~KStateVisited; + if ( iMQDecoder.MqDecodeSymbol( iCurrentZcLutPtr[state & KZcMask] ) != 0 ) + { + ctxt = iSCLut[( state >> KScShift ) & KScLutMask]; + symbol = iMQDecoder.MqDecodeSymbol( ( ctxt & KScLutMask ) ) ^( ( ctxt >> KPredictionBit ) & 1 ); + ( *aDataValue ) = ( symbol << KSignShift ) | aMask; + ( *aStateValue ) |= KStateSignificant; + UpdateSignificance( aStateValue, symbol ); + aZCValue = 1; + } + } + else + { + ctxt = iSCLut[( state >> KScShift ) & KScLutMask]; + symbol = iMQDecoder.MqDecodeSymbol( ( ctxt & KScLutMask ) ) ^ ( ( ctxt >> KPredictionBit ) & 1 ); + ( *aDataValue ) = ( symbol << KSignShift ) | aMask; + ( *aStateValue ) |= KStateSignificant; \ + UpdateSignificance( aStateValue, symbol ); + aZCValue = 1; + } + } + else + { + ( *aStateValue ) &= ( ~KStateVisited ); + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::UpdateSignificance +// Update the significance +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::UpdateSignificance( TInt16*& aStateValue, TInt32 aSymbol ) + { + TInt16* u = ( aStateValue ) - ( iStateWidth ); + TInt16* d = ( aStateValue ) + ( iStateWidth ); + u[-1] |= KStateLowerRight; + u[1] |= KStateLowerLeft; + d[-1] |= KStateUpperRight; + d[1] |= KStateUpperLeft; + + if ( aSymbol != 0 ) + { + aStateValue[-1] |= KStateRight | KStateHorNegative; + aStateValue[1] |= KStateLeft | KStateHorNegative; + *d |= KStateUp | KStateVerNegative; + *u |= KStateDown | KStateVerNegative; + } + else + { + aStateValue[-1] |= KStateRight | KStateHorPositive; + aStateValue[1] |= KStateLeft | KStateHorPositive; + *d |= KStateUp | KStateVerPositive; + *u |= KStateDown | KStateVerPositive; + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::SignificancePass +// Perform the significance pass +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::SignificancePass() + { + // Mask for the current bitplane is actually also an approximation of the + // lower bitplanes, i.e. mask might be 00001100 for the fourth bitplane instead + // of 00001000, thus the data will be increased by the current bitplane and + // half of the sum of the lower bitplanes. + TPrecInt mask = ( 1 << iCurrentBitplane ) | ( 1 << ( iCurrentBitplane - 1 ) ); + + TPrecInt* dataRow = &( iData[0][0] ); + TInt16* stateRow = CONST_CAST( TInt16*, GetFirstStateRow( ) ); + + TPrecInt* dataCol = 0; + TPrecInt* dataValue = 0; + TInt16* stateCol = 0; + TInt16* stateValue = 0; + + // Column index in the stripe + TInt32 col = 0; + TInt32 row = 0; + + // Code stripe by stripe + for ( TInt32 s = iNumStripes - 1; s > 0; s-- ) + { + // If using stripe causal context formation, reset necessary bits + // in state of first line in next stripe ( not on last + // stripe ). + if ( iVerticalCausalContextUsed ) + { + dataCol = dataRow + 2 * iBlockDataWidth; + stateCol = stateRow + iStateSamplesPerStripe - iStateWidth - 1; + GetCausal( dataCol, stateCol ); + } + + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + stateValue = stateCol; + dataValue = dataCol; + + for ( row = KStripeHeight; row > 0; row-- ) + { + DecodeSignificance( dataValue, stateValue, mask ); + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + } + } + + dataRow += iDataSamplesPerStripe; + stateRow += iStateSamplesPerStripe; + } + + // Deal with the last stripe separately + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + stateValue = stateCol; + dataValue = dataCol; + + for ( row = iLastStripeHeight; row > 0; row-- ) + { + DecodeSignificance( dataValue, stateValue, mask ); + if ( row > 1 ) + { + dataValue += iBlockDataWidth; + } + stateValue += iStateWidth; + } + } + + // If there is predictable termination, check for errors + if ( iTerminateThisPass && iPredictableTerminationUsed ) + { + iErrorState = iMQDecoder.MqCheckPrediction(); + } + + // Reset the MQ context states if we need to + if ( iResetContexts ) + { + iMQDecoder.ResetMqContexts(); + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::LazySignificancePass +// Perform the lazy significance pass +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::LazySignificancePass() + { + // Mask for the current bitplane + TPrecInt mask = ( 1 << iCurrentBitplane ) | ( 1 << ( iCurrentBitplane - 1 ) ); + + TPrecInt* dataRow = &( iData[0][0] ); + TInt16* stateRow = CONST_CAST( TInt16*, GetFirstStateRow() ); + TPrecInt* dataCol = 0; + TPrecInt* dataValue = 0; + TInt16* stateCol = 0; + TInt16* stateValue = 0; + + // Column index in the stripe + TInt32 col = 0; + TInt32 row = 0; + + for ( TInt32 s = iNumStripes - 1; s > 0; s-- ) + { + // If using stripe causal context formation, reset necessary bits + // in state of first line in next stripe ( not on last + // stripe ). + if ( iVerticalCausalContextUsed ) + { + dataCol = dataRow + 2 * iBlockDataWidth; + stateCol = stateRow + iStateSamplesPerStripe - iStateWidth - 1; + GetCausal( dataCol, stateCol ); + } + + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + stateValue = stateCol; + dataValue = dataCol; + + for ( row = KStripeHeight; row > 0; row-- ) + { + DecodeRawSignificance( dataValue, stateValue, mask ); + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + } + } + dataRow += iDataSamplesPerStripe; + stateRow += iStateSamplesPerStripe; + } + + // Deal with the last stripe separately + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Line index + TInt32 l = 0; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + stateValue = stateCol; + dataValue = dataCol; + + l = iLastStripeHeight; + DecodeRawSignificance( dataValue, stateValue, mask ); + if ( --l <= 0 ) + { + continue; //lint !e960 Continue is OK, no need to go end of for. + } + + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + DecodeRawSignificance( dataValue, stateValue, mask ); + if ( --l <= 0 ) + { + continue; //lint !e960 Continue is OK, no need to go end of for. + } + + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + DecodeRawSignificance( dataValue, stateValue, mask ); + if ( --l <= 0 ) + { + continue; //lint !e960 Continue is OK, no need to go end of for. + } + + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + DecodeRawSignificance( dataValue, stateValue, mask ); + + } + + // If there is predictable termination, check for errors + if ( iTerminateThisPass && iPredictableTerminationUsed ) + { + iErrorState = iMQDecoder.iInputStream.CheckPrediction(); + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::RefinementPass +// Perform the refinement pass +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::RefinementPass() + { + // To reset the effects of the approximation done in significance and + // normalization passes we have the resetmask. + TInt32 resetMask = ( -1 ) << ( iCurrentBitplane + 1 ); + TUint32 mask = ( ( TUint32 )( 1 << iCurrentBitplane ) ) >> 1; + + TPrecInt* dataRow = &( iData[0][0] ); + TInt16* stateRow = CONST_CAST( TInt16*, GetFirstStateRow() ); + + TPrecInt* dataCol = 0; + TPrecInt* dataValue = 0; + TInt16* stateCol = 0; + TInt16* stateValue = 0; + + // Column index in the stripe + TInt32 col = 0; + TInt32 row = 0; + + // Code stripe by stripe + for ( TInt32 s = iNumStripes - 1; s > 0; s-- ) + { + // If using stripe causal context formation, reset necessary bits + // in state of first line in next stripe ( not on last + // stripe ). + if ( iVerticalCausalContextUsed ) + { + dataCol = dataRow + 2 * iBlockDataWidth; + stateCol = stateRow + iStateSamplesPerStripe - iStateWidth - 1; + GetCausal( dataCol, stateCol ); + } + + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + dataValue = dataCol; + stateValue = stateCol; + + for ( row = KStripeHeight; row > 0; row-- ) + { + DecodeRefinement( dataValue, stateValue, mask, resetMask ); + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + } + } + dataRow += iDataSamplesPerStripe; + stateRow += iStateSamplesPerStripe; + } + + // Deal with the last stripe separately + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in the last stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + dataValue = dataCol; + stateValue = stateCol; + + for ( row = iLastStripeHeight; row > 0; row-- ) + { + DecodeRefinement( dataValue, stateValue, mask, resetMask ); + if ( row > 1 ) + { + dataValue += iBlockDataWidth; + } + stateValue += iStateWidth; + } + } + + // If there is predictable termination, check for errors + if ( iTerminateThisPass && iPredictableTerminationUsed ) + { + iErrorState = iMQDecoder.MqCheckPrediction(); + } + + // Reset the MQ context states if we need to + if ( iResetContexts ) + { + iMQDecoder.ResetMqContexts(); + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::LazyRefinementPass +// Perform the lazy refinement pass +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::LazyRefinementPass() + { + TInt32 resetMask = ( -1 ) << ( iCurrentBitplane + 1 ); + TUint32 mask = ( ( TUint32 )( 1 << iCurrentBitplane ) ) >> 1; + TPrecInt* dataRow = &( iData[0][0] ); + TInt16* stateRow = CONST_CAST( TInt16*, GetFirstStateRow() ); + TPrecInt* dataCol = 0; + TPrecInt* dataValue = 0; + TInt16* stateCol = 0; + TInt16* stateValue = 0; + + // Column index in the stripe + TInt32 col = 0; + TInt32 row = 0; + + // Code stripe by stripe + for ( TInt32 s = iNumStripes - 1; s > 0; s-- ) + { + // If using stripe causal context formation, reset necessary bits + // in state of first line in next stripe ( not on last + // stripe ). + if ( iVerticalCausalContextUsed ) + { + dataCol = dataRow + 2 * iBlockDataWidth; + stateCol = stateRow + iStateSamplesPerStripe - iStateWidth - 1; + GetCausal( dataCol, stateCol ); + } + + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + dataValue = dataCol; + stateValue = stateCol; + for ( row = KStripeHeight; row > 0; row-- ) + { + DecodeRawRefinement( dataValue, stateValue, mask, resetMask ); + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + } + } + dataRow += iDataSamplesPerStripe; + stateRow += iStateSamplesPerStripe; + } + + // Deal with the last stripe separately + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + dataValue = dataCol; + stateValue = stateCol; + + for ( row = iLastStripeHeight; row > 0; row-- ) + { + DecodeRawRefinement( dataValue, stateValue, mask, resetMask ); + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + } + stateValue = stateCol; + dataValue = dataCol; + } + + // If there is predictable termination, check for errors + if ( iTerminateThisPass && iPredictableTerminationUsed ) + { + iErrorState = iMQDecoder.iInputStream.CheckPrediction(); + } + + // Because this is always terminated, reset stream + iMQDecoder.iInputStream.ResetInputStream(); + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::CleanupPass +// Perform the cleanup pass +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +void CJ2kEntropyDecoder::CleanupPass( TUint8 aSegSymbols ) + { + TInt32 zcCoding = 0; + + // Symbol to be coded + TInt32 symbol = 0; + + TPrecInt mask = ( 1 << iCurrentBitplane ) | ( 1 << ( iCurrentBitplane - 1 ) ); + + TPrecInt* dataRow = &( iData[0][0] ); + TInt16* stateRow = CONST_CAST( TInt16*, GetFirstStateRow() ); + TPrecInt* dataCol = 0; + TPrecInt* dataValue = 0; + TInt16* stateCol = 0; + TInt16* stateValue = 0; + + // Column index in the stripe + TInt32 col = 0; + TInt32 row = 0; + + // Code stripe by stripe + for ( TInt32 s = iNumStripes - 1; s > 0; s-- ) + { + // If using stripe causal context formation, reset necessary bits + // in state of first line in next stripe + if ( iVerticalCausalContextUsed ) + { + dataCol = dataRow + 2 * iBlockDataWidth; + stateCol = stateRow + iStateSamplesPerStripe - iStateWidth - 1; + GetCausal( dataCol, stateCol ); + } + + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + for ( col = iBlockWidth; col > 0; col--, dataCol++, stateCol++ ) + { + stateValue = stateCol; + dataValue = dataCol; + + // If sample is insignificant and not yet visited in the + // current bitplane, then apply the normalization pass + if ( ( *stateValue == 0 ) && + ( stateValue += iStateWidth, ( *stateValue ) == 0 ) && //lint !e960 Comma is OK. + ( stateValue += iStateWidth, ( *stateValue ) == 0 ) && //lint !e960 Comma is OK. + ( stateValue += iStateWidth, ( *stateValue ) == 0 ) ) //lint !e960 Comma is OK. + { + // Use RLC + if ( iMQDecoder.MqDecodeSymbol( KRlcContext ) != 0 ) //some sample( s ) not zero + { + // Decode the symbol most significant bit first + symbol = (TUint8)( iMQDecoder.MqDecodeSymbol( KUniformContext ) << 1 ); // MSB + symbol |= (TUint8)( iMQDecoder.MqDecodeSymbol( KUniformContext ) & 0x01 ); // LSB + + // Update data and state pointers + stateValue = stateCol + symbol * iStateWidth; + dataValue = dataCol + symbol * iBlockDataWidth; + + // Set zcCoding flag to zero + zcCoding = 0; + row = KStripeHeight - symbol; + } + else // All samples zero + { + // Move to next column + continue; //lint !e960 Continue is OK, no need to go end of for. + } + } + else // No RLC used + { + stateValue = stateCol; + + // Set zcCoding flag to one + zcCoding = 1; + row = KStripeHeight; + } + + for ( ; row > 0; row-- ) + { + DecodeNormalization( dataValue, stateValue, mask, zcCoding ); + dataValue += iBlockDataWidth; + stateValue += iStateWidth; + } + } + dataRow += iDataSamplesPerStripe; + stateRow += iStateSamplesPerStripe; + } + + // Deal with last stripe separately + // Scan column by column in each stripe + dataCol = dataRow; + stateCol = stateRow; + + // Scan column by column in each stripe + for ( col = iBlockWidth; col > 0; col--, stateCol++, dataCol++ ) + { + stateValue = stateCol; + dataValue = dataCol; + + // If sample is insignificant and not yet visited in the + // current bitplane, then apply the normalization pass + if( ( iLastStripeHeight == KStripeHeight ) && ( *stateValue ==0 ) && + ( stateValue += iStateWidth, ( *stateValue ) == 0 ) && //lint !e960 Comma is OK. + ( stateValue += iStateWidth, ( *stateValue ) == 0 ) && //lint !e960 Comma is OK. + ( stateValue += iStateWidth, ( *stateValue ) == 0 ) ) //lint !e960 Comma is OK. + { + // Use RLC: + if ( iMQDecoder.MqDecodeSymbol( KRlcContext ) != 0 ) //some sample( s ) not zero + { + // Decode the symbol most significant bit first + symbol = ( TUint8 )( iMQDecoder.MqDecodeSymbol( KUniformContext ) << 1 ); // MSB + symbol |= ( TUint8 )( iMQDecoder.MqDecodeSymbol( KUniformContext ) & 0x01 ); // LSB + + // Update data and state pointers + stateValue = stateCol + symbol * iStateWidth; + dataValue = dataCol + symbol * iBlockDataWidth; + + // Set zcCoding flag to zero + zcCoding = 0; + row = KStripeHeight - symbol; + } + else // All samples zero + { + // Move to next column + continue; //lint !e960 Continue is OK, no need to go end of for. + } + } + else // No RLC used + { + row = iLastStripeHeight; + stateValue = stateCol; + + // Set zcCoding flag to one + zcCoding = 1; + } + + for ( ; row > 0; row-- ) + { + DecodeNormalization( dataValue, stateValue, mask, zcCoding ); + if ( row > 1 ) + { + dataValue += iBlockDataWidth; + } + stateValue += iStateWidth; + } + } + + // Decode a segment marker if we need to + if ( aSegSymbols ) + { + symbol = (TUint8)( iMQDecoder.MqDecodeSymbol( KUniformContext ) << 3 ); + symbol |= (TUint8)( iMQDecoder.MqDecodeSymbol( KUniformContext ) << 2 ); + symbol |= (TUint8)( iMQDecoder.MqDecodeSymbol( KUniformContext ) << 1 ); + symbol |= (TUint8)( iMQDecoder.MqDecodeSymbol( KUniformContext ) ); + + if ( symbol != KSegmentationMarker ) + { + iErrorState = EEntropyCodingError; + } + } + + // If there is predictable termination, check for errors + if ( iTerminateThisPass && iPredictableTerminationUsed ) + { + iErrorState = iMQDecoder.MqCheckPrediction(); + } + + // Reset the MQ context states if we need to + if ( iResetContexts ) + { + iMQDecoder.ResetMqContexts(); + } + } + +// ----------------------------------------------------------------------------- +// CJ2kEntropyDecoder::GetFirstStateRow +// Get the first state row +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +// +const TInt16* CJ2kEntropyDecoder::GetFirstStateRow() const + { + return iStates + ( iStateWidth + 1 ); + } +