satdump/plugins/xrit_support/DecompWT/CWTCoder.cpp

228 lines
5.9 KiB
C++
Raw Permalink Normal View History

/*
* 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.
*/
#include "CDataField.h"
#include "CBuffer.h"
#include "CWBlock.h"
#include "CACCoder.h"
#include "CVLCCoder.h"
#include "CWTCoder.h"
namespace COMP
{
void CWTCoder::CodeBufferBlock(const unsigned int i_Bs)
{
COMP_TRYTHIS
unsigned int bX, bY;
// Write header
m_Buf.write_marker(c_MarkerHEADER);
m_Buf.real_write(m_Param.m_BitsPerPixel, 4);
m_Buf.real_write(m_Image.GetW(), 16);
m_Buf.real_write(m_Image.GetH(), 16);
m_Buf.real_write(m_Param.m_nWTlevels - 3, 2);
m_Buf.real_write(m_Param.m_PredMode - CWTParams::e_None, 2);
m_Buf.real_write(i_Bs >> 5, 2);
m_Buf.real_write(m_Param.m_RestartInterval, 16);
m_Buf.real_write(m_Param.m_nLossyBitPlanes, 4);
m_Buf.real_write(0, 2); // Pad bits
m_Buf.write_marker(c_MarkerDATA);
// Computing the number of blocks along each dimension
unsigned int nbW = m_Image.GetW() / i_Bs;
const unsigned int rW = m_Image.GetW() % i_Bs;
if (rW)
nbW++;
unsigned int nbH = m_Image.GetH() / i_Bs;
const unsigned int rH = m_Image.GetH() % i_Bs;
if (rH)
nbH++;
Assert(nbW > 0 && nbH > 0, Util::CParamException());
// Start arithmetic coder
CACCoder ac(m_Buf);
ac.Start();
// VLC coder object creation
CVLCCoder coder(ac);
// Wavelet block object creation
CWBlock wblk(i_Bs, i_Bs);
// block loops
unsigned int nbBlock = 0;
unsigned int markerNum = 0;
bool bACStopped = false;
for (bY = 0; bY < nbH; bY++)
{
const unsigned int nH = bY == (nbH - 1) && rH ? rH : i_Bs;
for (bX = 0; bX < nbW; bX++)
{
const unsigned int nW = bX == (nbW - 1) && rW ? rW : i_Bs;
// Copy image block to CWBlock with line and column padding
wblk.GetAndPad(m_Image, bX * i_Bs, bY * i_Bs, nW, nH);
// Perform the forward m_nWTlevels iterations of 2D S(+P) transform
switch (m_Param.m_PredMode)
{
case CWTParams::e_None:
wblk.IterateSt(true, m_Param.m_nWTlevels);
break;
case CWTParams::e_PredA:
wblk.IterateSptA(true, m_Param.m_nWTlevels);
break;
case CWTParams::e_PredB:
wblk.IterateSptB(true, m_Param.m_nWTlevels);
break;
case CWTParams::e_PredC:
wblk.IterateSptC(true, m_Param.m_nWTlevels);
break;
default:
Assert(0, Util::CParamException())
}
// code the S+P coefs
coder.Code(wblk, m_Param.m_nWTlevels, m_Param.m_nLossyBitPlanes);
nbBlock++;
if (m_Param.m_RestartInterval && nbBlock == m_Param.m_RestartInterval)
{
// Output a restart marker
nbBlock = 0;
ac.Stop();
m_Buf.write_marker(c_MarkerRESTART | (markerNum & 0xF));
markerNum++;
if (bX < (nbW - 1) || bY < (nbH - 1))
ac.Start();
else
bACStopped = true;
// Reset VLC decoder state (models probabilities)
coder.Reset();
}
}
}
// Stop the arithmetic coding
if (!bACStopped)
ac.Stop();
// Write the Footer marker
m_Buf.write_marker(c_MarkerFOOTER);
COMP_CATCHTHIS
}
void CWTCoder::CodeBufferFull(void)
{
COMP_TRYTHIS
// Write header
m_Buf.write_marker(c_MarkerHEADER);
m_Buf.real_write(m_Param.m_BitsPerPixel, 4);
m_Buf.real_write(m_Image.GetW(), 16);
m_Buf.real_write(m_Image.GetH(), 16);
m_Buf.real_write(m_Param.m_nWTlevels - 3, 2);
m_Buf.real_write(m_Param.m_PredMode - CWTParams::e_None, 2);
m_Buf.real_write(3, 2); // Full block
m_Buf.real_write(m_Param.m_RestartInterval, 16);
m_Buf.real_write(m_Param.m_nLossyBitPlanes, 4);
m_Buf.real_write(0, 2); // Pad bits
m_Buf.write_marker(c_MarkerDATA);
// Start arithmetic coder
CACCoder ac(m_Buf);
ac.Start();
// Compute the Wavelet block size to allow m_nWTlevels S+P iterations
int bW = m_Image.GetW();
int bH = m_Image.GetH();
const int iteS = 1U << m_Param.m_nWTlevels;
bW = (bW + iteS - 1) & (-iteS);
bH = (bH + iteS - 1) & (-iteS);
// Wavelet block object creation
CWBlock wblk(bW, bH);
// Copy image to CWBlock with line and column padding
wblk.GetAndPad(m_Image, 0, 0, m_Image.GetW(), m_Image.GetH());
// Perform the forward m_nWTlevels iterations of 2D S(+P) transform
switch (m_Param.m_PredMode)
{
case CWTParams::e_None:
wblk.IterateSt(true, m_Param.m_nWTlevels);
break;
case CWTParams::e_PredA:
wblk.IterateSptA(true, m_Param.m_nWTlevels);
break;
case CWTParams::e_PredB:
wblk.IterateSptB(true, m_Param.m_nWTlevels);
break;
case CWTParams::e_PredC:
wblk.IterateSptC(true, m_Param.m_nWTlevels);
break;
default:
Assert(0, Util::CParamException())
}
// VLC coder object creation
CVLCCoder coder(ac);
// code the S+P coefs
coder.Code(wblk, m_Param.m_nWTlevels, m_Param.m_nLossyBitPlanes);
// Stop Arithmetic coding
ac.Stop();
// Write the Footer marker
m_Buf.write_marker(c_MarkerFOOTER);
COMP_CATCHTHIS
}
void CWTCoder::CodeBuffer(void)
{
COMP_TRYTHIS
switch (m_Param.m_BlockMode)
{
case CWTParams::e_16x16Block:
Assert(m_Param.m_nWTlevels <= 4, Util::CParamException());
CodeBufferBlock(16U);
break;
case CWTParams::e_32x32Block:
Assert(m_Param.m_nWTlevels <= 5, Util::CParamException());
CodeBufferBlock(32U);
break;
case CWTParams::e_64x64Block:
// Assert not really needed...
Assert(m_Param.m_nWTlevels <= 6, Util::CParamException());
CodeBufferBlock(64U);
break;
case CWTParams::e_FullWidth:
CodeBufferFull();
break;
default:
Assert(0, Util::CParamException())
}
m_Buf.close();
COMP_CATCHTHIS
}
} // end namespace