mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
417 lines
12 KiB
C++
417 lines
12 KiB
C++
/*
|
|
* Copyright 2011-2019, European Organisation for the Exploitation of Meteorological Satellites (EUMETSAT)
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
//:Ignore
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FileName: CVLCDecoder.cpp
|
|
//
|
|
// Date Created: 15/01/1999
|
|
//
|
|
// Author: Youssef Ouaghli
|
|
//
|
|
// Description: CVLCDecoder class definition.
|
|
//
|
|
// Last Modified: $Dmae: 1999/08/26 15:41:08 $
|
|
//
|
|
// RCS Id: $Id: CVLCDecoder.cpp,v 1.47 1999/08/26 15:41:08 youag Exp $
|
|
//
|
|
// $Rma: CVLCDecoder.cpp,v $
|
|
// Revision 1.47 1999/08/26 15:41:08 youag
|
|
// New context: (PrevContext + PrevSymbol) / 2 instead of PrevSymbol
|
|
//
|
|
// Revision 1.46 1999/06/01 14:30:48 youag
|
|
// Small change
|
|
//
|
|
// Revision 1.45 1999/05/27 11:05:59 youag
|
|
// Removing un-needed parameters in CodeQuadrantDC()/DecodeQuadrantDC functions
|
|
//
|
|
// Revision 1.44 1999/05/21 15:34:35 youag
|
|
// Replacing speed_nb_bits() by speed_csize()
|
|
//
|
|
// Revision 1.43 1999/05/21 14:45:01 youag
|
|
// CVLCCoder & CVLCDecoder bad param testing done
|
|
//
|
|
// Revision 1.42 1999/05/21 10:28:39 youag
|
|
// Computing/Getting WT bloc max coef inside CVLCCoder::Code()/CVLCDecoder::Decode()
|
|
// to avoid possible trap with the interface
|
|
//
|
|
// Revision 1.41 1999/05/20 13:59:21 youag
|
|
// Coding DC quadrant coefs using DPCM
|
|
//
|
|
// Revision 1.40 1999/05/20 13:19:43 youag
|
|
// Correcting coding/decoding of DC quadrant when nbBit is zero
|
|
//
|
|
// Revision 1.39 1999/05/20 13:03:29 youag
|
|
// Coding/Decoding the DC quadrant as a separate case
|
|
//
|
|
// Revision 1.38 1999/05/20 12:28:19 youag
|
|
// Added Assert in CVLCCoder::CodeQuadrant for better testing of the class
|
|
//
|
|
// Revision 1.37 1999/05/18 12:20:20 youag
|
|
// Renaming ac, m_Ac into ad, m_Ad for CACDecoder class
|
|
//
|
|
// Revision 1.36 1999/05/11 16:08:51 youag
|
|
// Removing CVLCCodec::m_Mod optimization beacause of strange effect
|
|
// during decompression on ALPHA (execution time is doubled)
|
|
//
|
|
// Revision 1.35 1999/05/11 15:54:54 youag
|
|
// CVLCCodec::m_Mod is now an array of pointers. to minimize number of
|
|
// assembly lines needed to initialize parameter of CACCoder:;CodeSymbol function
|
|
//
|
|
// Revision 1.34 1999/05/10 12:04:58 youag
|
|
// Testing if AC interval rescaling is needed before calling the function
|
|
//
|
|
// Revision 1.33 1999/05/10 11:40:01 youag
|
|
// Cleaning code from unused member functions
|
|
//
|
|
// Revision 1.32 1999/05/07 14:08:32 youag
|
|
// Reduce number of inline functions in order to promote code expansion of
|
|
// important inline functions
|
|
//
|
|
// Revision 1.31 1999/05/07 10:53:43 youag
|
|
// Checking for CWBuffer size expansion at each 4 bytes
|
|
//
|
|
// Revision 1.30 1999/05/06 15:42:32 youag
|
|
// Reducing use of const & param because of poor assembly code
|
|
//
|
|
// Revision 1.29 1999/04/26 13:32:28 youag
|
|
// Avoiding second test of coding the MPS by using two
|
|
// CACModel::Update{Mps/Lps} functions
|
|
//
|
|
// Revision 1.28 1999/04/20 16:27:39 youag
|
|
// loop indexes test optimization
|
|
//
|
|
// Revision 1.27 1999/04/20 10:47:01 youag
|
|
// Testing some loop indexes against 0:
|
|
// Replacing for (i=0 ; i<N ; i++) by for (i=N ; i!=0 ; i--)
|
|
//
|
|
// Revision 1.26 1999/04/20 09:59:14 youag
|
|
// Using *pointer++ optimization in CWBlock:: GetAndPad & Put methods
|
|
//
|
|
// Revision 1.25 1999/04/16 11:52:20 youag
|
|
// Using pointer instead of CWBlock::CGet(x, y) or CWBlock(x, y)
|
|
// Performances are improved one ALPHA, equal on INTEL
|
|
//
|
|
// Revision 1.24 1999/04/14 17:24:13 youag
|
|
// Optimization
|
|
//
|
|
// Revision 1.23 1999/04/14 14:12:52 youag
|
|
// Improving CACDecoder performance and cleaning WTConst.h
|
|
//
|
|
// Revision 1.22 1999/04/14 12:01:02 youag
|
|
// Optimizing CWBlock
|
|
// Resolving bug in S+P with predictor C and quadrant size == 4
|
|
//
|
|
// Revision 1.21 1999/04/13 11:47:09 youag
|
|
// Computing max WT coef per quadrant for improved CR
|
|
//
|
|
// Revision 1.20 1999/04/12 17:56:44 youag
|
|
// Optimization of AC
|
|
// Avoiding 0xFF byte stuffing in WT header
|
|
//
|
|
// Revision 1.19 1999/04/06 14:55:06 youag
|
|
// Improving error detection
|
|
//
|
|
// Revision 1.18 1999/03/29 15:31:24 youag
|
|
// Resolving bug in coefs refinement after lossy decoding
|
|
//
|
|
// Revision 1.17 1999/03/29 10:25:13 youag
|
|
// Resolving bug in lossy mode
|
|
//
|
|
// Revision 1.16 1999/03/25 16:44:33 youag
|
|
// Small optimization for lossless case
|
|
//
|
|
// Revision 1.15 1999/03/22 09:27:23 youag
|
|
// Removing SPIHT modules
|
|
//
|
|
// Revision 1.14 1999/03/05 17:24:02 youag
|
|
// Implementing bit plane based lossy codec with VLC
|
|
//
|
|
// Revision 1.13 1999/03/04 18:29:37 youag
|
|
// Introducing bit plane based lossy codec
|
|
//
|
|
// Revision 1.12 1999/03/01 12:35:35 youag
|
|
// Better detection of errors during decoding.
|
|
// nSPIHTLevels is now interpreted as the number of least significant bit
|
|
// planes that must not be coded hierarchically.
|
|
//
|
|
// Revision 1.11 1999/02/25 12:20:37 youag
|
|
// Small changes and testing
|
|
//
|
|
// Revision 1.10 1999/02/24 16:22:59 youag
|
|
// Improving block coding by using variable nb bits per S+P coef instead of fixed one
|
|
//
|
|
// Revision 1.9 1999/02/19 12:14:47 youag
|
|
// SPIHT now uses group of four pixels / trees as in Said and Pearlman code
|
|
//
|
|
// Revision 1.8 1999/02/09 17:31:59 youag
|
|
// Small changes and tests
|
|
//
|
|
// Revision 1.7 1999/02/08 18:09:09 youag
|
|
// Handling Number of SPIHT levels parameter
|
|
//
|
|
// Revision 1.6 1999/02/08 14:51:51 youag
|
|
// VLC coding/decoding of last SPIHT bit planes operational
|
|
//
|
|
// Revision 1.5 1999/02/05 17:56:29 youag
|
|
// Added VLC coding for last SPIHT bit planes
|
|
//
|
|
// Revision 1.4 1999/02/04 18:00:22 youag
|
|
// Changes to make sources clearer
|
|
//
|
|
// Revision 1.3 1999/01/29 11:45:13 youag
|
|
// Modifying CBuffer for faster 1 bit read/write
|
|
//
|
|
// Revision 1.2 1999/01/28 18:10:31 youag
|
|
// Debuging VLC coding/decoding
|
|
//
|
|
// Revision 1.1 1999/01/27 11:09:13 youag
|
|
// Reduce use of inline functions
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//:End Ignore
|
|
|
|
#include "CVLCDecoder.h"
|
|
|
|
namespace COMP
|
|
{
|
|
|
|
bool CVLCDecoder::DecodeQuadrantDC(CWBlock &o_Wblk,
|
|
const unsigned int i_W, const unsigned int i_H,
|
|
const unsigned int /*i_Quadrant*/)
|
|
{
|
|
COMP_TRYTHIS
|
|
unsigned int nbBit = m_Ad.DecodeBits(m_NbBitNbBitCoef);
|
|
if (nbBit > m_NbBitCoef)
|
|
return false;
|
|
if (nbBit)
|
|
{
|
|
m_Mod = m_Models[nbBit++];
|
|
if (!m_Mod[0].IsInitialized())
|
|
for (unsigned int i = 0; i <= nbBit; i++)
|
|
m_Mod[i].Initialize(nbBit + 1);
|
|
|
|
int oldCoef = 1UL << (nbBit - 2);
|
|
unsigned int context = nbBit;
|
|
int *p = o_Wblk.GetData()[0];
|
|
const unsigned int w = o_Wblk.GetW();
|
|
for (int i = i_H; i > 0; i--, p += w)
|
|
{
|
|
for (unsigned int j = i_W; j; j--)
|
|
{
|
|
int c;
|
|
|
|
context = (context + DecodeCoef(context, c)) >> 1;
|
|
*p++ = (oldCoef += c);
|
|
}
|
|
if (--i)
|
|
{
|
|
p += w;
|
|
for (unsigned int j = i_W; j; j--)
|
|
{
|
|
int c;
|
|
|
|
context = (context + DecodeCoef(context, c)) >> 1;
|
|
*--p = (oldCoef += c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = i_H - 1; i >= 0; i--)
|
|
{
|
|
int *p = o_Wblk.GetData()[i];
|
|
for (unsigned int j = i_W; j; j--)
|
|
*p++ = 0;
|
|
}
|
|
}
|
|
return true;
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
bool CVLCDecoder::DecodeQuadrant(CWBlock &o_Wblk,
|
|
const unsigned int i_X, const unsigned int i_Y,
|
|
const unsigned int i_W, const unsigned int i_H,
|
|
const unsigned int i_Level, const unsigned int i_Quadrant)
|
|
{
|
|
COMP_TRYTHIS
|
|
unsigned int nbBit = m_Ad.DecodeBits(m_NbBitNbBitCoef);
|
|
if (nbBit > m_NbBitCoef)
|
|
return false;
|
|
const unsigned int coefShift = i_Level >= m_NbLossyBitPlane
|
|
? 0
|
|
: m_NbLossyBitPlane - i_Level - (i_Quadrant > m_NbLossyQuadrant ? 1 : 0);
|
|
if (nbBit > coefShift)
|
|
{
|
|
nbBit -= coefShift;
|
|
m_Mod = m_Models[nbBit - 1];
|
|
if (!m_Mod[0].IsInitialized())
|
|
for (unsigned int i = 0; i <= nbBit; i++)
|
|
m_Mod[i].Initialize(nbBit + 1);
|
|
|
|
unsigned int context = nbBit;
|
|
int *p = o_Wblk.GetData()[i_Y] + i_X;
|
|
const unsigned int w = o_Wblk.GetW();
|
|
if (!coefShift)
|
|
for (int i = i_H; i > 0; i--, p += w)
|
|
{
|
|
for (unsigned int j = i_W; j; j--)
|
|
context = (context + DecodeCoef(context, *p++)) >> 1;
|
|
if (--i)
|
|
{
|
|
p += w;
|
|
for (unsigned int j = i_W; j; j--)
|
|
context = (context + DecodeCoef(context, *--p)) >> 1;
|
|
}
|
|
}
|
|
else
|
|
for (int i = i_H; i > 0; i--, p += w)
|
|
{
|
|
for (unsigned int j = i_W; j; j--)
|
|
{
|
|
int c;
|
|
|
|
context = (context + DecodeCoef(context, c)) >> 1;
|
|
*p++ = c << coefShift;
|
|
}
|
|
if (--i)
|
|
{
|
|
p += w;
|
|
for (unsigned int j = i_W; j; j--)
|
|
{
|
|
int c;
|
|
|
|
context = (context + DecodeCoef(context, c)) >> 1;
|
|
*--p = c << coefShift;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const unsigned int endY = i_Y + i_H;
|
|
for (unsigned int i = i_Y; i < endY; i++)
|
|
{
|
|
int *p = o_Wblk.GetData()[i] + i_X;
|
|
for (unsigned int j = i_W; j; j--)
|
|
*p++ = 0;
|
|
}
|
|
}
|
|
return true;
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
void CVLCDecoder::RefineLossyQuadrant(CWBlock &o_Wblk,
|
|
const unsigned int i_X, const unsigned int i_Y,
|
|
const unsigned int i_W, const unsigned int i_H,
|
|
const unsigned int i_Level, const unsigned int i_Quadrant)
|
|
{
|
|
COMP_TRYTHIS_SPEED
|
|
if (m_NbLossyBitPlane > (i_Level + 1 + (i_Quadrant > m_NbLossyQuadrant ? 1 : 0)))
|
|
{
|
|
const int cT = (1L << (m_NbLossyBitPlane - i_Level -
|
|
(i_Quadrant > m_NbLossyQuadrant ? 2 : 1))) -
|
|
1;
|
|
const unsigned int endY = i_Y + i_H;
|
|
for (unsigned int i = i_Y; i < endY; i++)
|
|
{
|
|
int *p = o_Wblk.GetData()[i] + i_X;
|
|
for (unsigned int j = i_W; j; j--, p++)
|
|
{
|
|
int c;
|
|
|
|
if ((c = *p))
|
|
{
|
|
if (c > 0)
|
|
*p |= cT;
|
|
else
|
|
*p = -(-c | cT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
COMP_CATCHTHIS_SPEED
|
|
}
|
|
|
|
void CVLCDecoder::RefineLossy(CWBlock &o_Wblk)
|
|
{
|
|
COMP_TRYTHIS
|
|
unsigned int w = o_Wblk.GetW() >> m_NbIteWt;
|
|
unsigned int h = o_Wblk.GetH() >> m_NbIteWt;
|
|
unsigned int m = m_NbIteWt;
|
|
unsigned int q = m_NbIteWt * 3 - 1;
|
|
|
|
for (unsigned int k = 0; k < m_NbIteWt; k++, w <<= 1, h <<= 1, m--)
|
|
{
|
|
RefineLossyQuadrant(o_Wblk, w, 0, w, h, m, q--);
|
|
RefineLossyQuadrant(o_Wblk, 0, h, w, h, m, q--);
|
|
RefineLossyQuadrant(o_Wblk, w, h, w, h, m - 1, q--);
|
|
}
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
bool CVLCDecoder::Decode(CWBlock &o_Wblk, const unsigned int i_NbIteWt, const unsigned int i_NbLossyBp)
|
|
{
|
|
COMP_TRYTHIS
|
|
// Get the wavelet block max coef amplitude in number of bits
|
|
const unsigned int nbBit = m_Ad.DecodeBits(5);
|
|
// To make sure CACDecoder::DecodeBits() will not fail
|
|
if (nbBit > (c_ACNbBits - 2))
|
|
return false;
|
|
if (nbBit)
|
|
{
|
|
static const unsigned int bitPlanes[16] = {0, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4};
|
|
static const unsigned int quadrants[16] = {0, 0, 0, 2, 3, 0, 2, 3, 5, 6, 0, 2, 3, 5, 6, 9};
|
|
|
|
Assert(i_NbLossyBp < 16, Util::CParamException());
|
|
unsigned int w = o_Wblk.GetW() >> i_NbIteWt;
|
|
unsigned int h = o_Wblk.GetH() >> i_NbIteWt;
|
|
// Check the block dimension against the number of wavelet transform iteration
|
|
Assert((w << i_NbIteWt) == o_Wblk.GetW() || (h << i_NbIteWt) == o_Wblk.GetH(), Util::CParamException());
|
|
unsigned int m = i_NbIteWt;
|
|
unsigned int q = i_NbIteWt * 3;
|
|
m_NbBitCoef = nbBit;
|
|
m_NbBitNbBitCoef = speed_csize(nbBit);
|
|
m_NbIteWt = i_NbIteWt;
|
|
m_NbLossyBitPlane = bitPlanes[i_NbLossyBp];
|
|
m_NbLossyQuadrant = quadrants[i_NbLossyBp];
|
|
|
|
if (!DecodeQuadrantDC(o_Wblk, w, h, q--))
|
|
return false;
|
|
for (unsigned int k = 0; k < i_NbIteWt; k++, w <<= 1, h <<= 1, m--)
|
|
{
|
|
if (!DecodeQuadrant(o_Wblk, w, 0, w, h, m, q--))
|
|
return false;
|
|
if (!DecodeQuadrant(o_Wblk, 0, h, w, h, m, q--))
|
|
return false;
|
|
if (!DecodeQuadrant(o_Wblk, w, h, w, h, m - 1, q--))
|
|
return false;
|
|
}
|
|
|
|
if (i_NbLossyBp > 1)
|
|
RefineLossy(o_Wblk);
|
|
}
|
|
else
|
|
o_Wblk.Zero(); // nbBit == 0
|
|
|
|
return true;
|
|
COMP_CATCHTHIS
|
|
}
|
|
|
|
} // namespace COMP
|