libpgf
6.11.42
PGF - Progressive Graphics File
|
PGF decoder. More...
#include <Decoder.h>
Classes | |
class | CMacroBlock |
A macro block is a decoding unit of fixed size (uncoded) More... | |
Public Member Functions | |
CDecoder (CPGFStream *stream, PGFPreHeader &preHeader, PGFHeader &header, PGFPostHeader &postHeader, UINT32 *&levelLength, bool useOMP=true) THROW_ | |
~CDecoder () | |
void | Partition (CSubband *band, int quantParam, int width, int height, int startPos, int pitch) THROW_ |
void | DecodeInterleaved (CWaveletTransform *wtChannel, int level, int quantParam) THROW_ |
UINT32 | GetEncodedHeaderLength () const |
void | SetStreamPosToStart () THROW_ |
void | SetStreamPosToData () THROW_ |
void | Skip (UINT64 offset) THROW_ |
void | DequantizeValue (CSubband *band, UINT32 bandPos, int quantParam) THROW_ |
UINT32 | ReadEncodedData (UINT8 *target, UINT32 len) const THROW_ |
void | DecodeBuffer () THROW_ |
Private Member Functions | |
void | ReadMacroBlock (CMacroBlock *block) THROW_ |
throws IOException | |
Private Attributes | |
CPGFStream * | m_stream |
input pgf stream | |
UINT64 | m_startPos |
stream position at the beginning of the PGF pre header | |
UINT64 | m_streamSizeEstimation |
estimation of stream size | |
UINT32 | m_encodedHeaderLength |
stream offset from startPos to the beginning of the data part (highest level) | |
CMacroBlock ** | m_macroBlocks |
array of macroblocks | |
int | m_currentBlockIndex |
index of current macro block | |
int | m_macroBlockLen |
array length | |
int | m_macroBlocksAvailable |
number of decoded macro blocks (including currently used macro block) | |
CMacroBlock * | m_currentBlock |
current macro block (used by main thread) |
CDecoder::CDecoder | ( | CPGFStream * | stream, |
PGFPreHeader & | preHeader, | ||
PGFHeader & | header, | ||
PGFPostHeader & | postHeader, | ||
UINT32 *& | levelLength, | ||
bool | useOMP = true |
||
) |
Constructor: Read pre-header, header, and levelLength at current stream position. It might throw an IOException.
stream | A PGF stream |
preHeader | [out] A PGF pre-header |
header | [out] A PGF header |
postHeader | [out] A PGF post-header |
levelLength | The location of the levelLength array. The array is allocated in this method. The caller has to delete this array. |
useOMP | If true, then the decoder will use multi-threading based on openMP |
Definition at line 65 of file Decoder.cpp.
: m_stream(stream) , m_startPos(0) , m_streamSizeEstimation(0) , m_encodedHeaderLength(0) , m_currentBlockIndex(0) , m_macroBlocksAvailable(0) #ifdef __PGFROISUPPORT__ , m_roi(false) #endif { ASSERT(m_stream); int count, expected; // set number of threads #ifdef LIBPGF_USE_OPENMP m_macroBlockLen = omp_get_num_procs(); #else m_macroBlockLen = 1; #endif if (useOMP && m_macroBlockLen > 1) { #ifdef LIBPGF_USE_OPENMP omp_set_num_threads(m_macroBlockLen); #endif // create macro block array m_macroBlocks = new CMacroBlock*[m_macroBlockLen]; for (int i=0; i < m_macroBlockLen; i++) m_macroBlocks[i] = new CMacroBlock(this); m_currentBlock = m_macroBlocks[m_currentBlockIndex]; } else { m_macroBlocks = 0; m_macroBlockLen = 1; // there is only one macro block m_currentBlock = new CMacroBlock(this); } // store current stream position m_startPos = m_stream->GetPos(); // read magic and version count = expected = MagicVersionSize; m_stream->Read(&count, &preHeader); if (count != expected) ReturnWithError(MissingData); // read header size if (preHeader.version & Version6) { // 32 bit header size since version 6 count = expected = 4; } else { count = expected = 2; } m_stream->Read(&count, ((UINT8*)&preHeader) + MagicVersionSize); if (count != expected) ReturnWithError(MissingData); // make sure the values are correct read preHeader.hSize = __VAL(preHeader.hSize); // check magic number if (memcmp(preHeader.magic, Magic, 3) != 0) { // error condition: wrong Magic number ReturnWithError(FormatCannotRead); } // read file header count = expected = (preHeader.hSize < HeaderSize) ? preHeader.hSize : HeaderSize; m_stream->Read(&count, &header); if (count != expected) ReturnWithError(MissingData); // make sure the values are correct read header.height = __VAL(UINT32(header.height)); header.width = __VAL(UINT32(header.width)); // be ready to read all versions including version 0 if (preHeader.version > 0) { #ifndef __PGFROISUPPORT__ // check ROI usage if (preHeader.version & PGFROI) ReturnWithError(FormatCannotRead); #endif int size = preHeader.hSize - HeaderSize; if (size > 0) { // read post header if (header.mode == ImageModeIndexedColor) { ASSERT((size_t)size >= ColorTableSize); // read color table count = expected = ColorTableSize; m_stream->Read(&count, postHeader.clut); if (count != expected) ReturnWithError(MissingData); size -= count; } if (size > 0) { // create user data memory block postHeader.userDataLen = size; postHeader.userData = new(std::nothrow) UINT8[postHeader.userDataLen]; if (!postHeader.userData) ReturnWithError(InsufficientMemory); // read user data count = expected = postHeader.userDataLen; m_stream->Read(&count, postHeader.userData); if (count != expected) ReturnWithError(MissingData); } } // create levelLength levelLength = new UINT32[header.nLevels]; // read levelLength count = expected = header.nLevels*WordBytes; m_stream->Read(&count, levelLength); if (count != expected) ReturnWithError(MissingData); #ifdef PGF_USE_BIG_ENDIAN // make sure the values are correct read for (int i=0; i < header.nLevels; i++) { levelLength[i] = __VAL(levelLength[i]); } #endif // compute the total size in bytes; keep attention: level length information is optional for (int i=0; i < header.nLevels; i++) { m_streamSizeEstimation += levelLength[i]; } } // store current stream position m_encodedHeaderLength = UINT32(m_stream->GetPos() - m_startPos); }
Destructor
Definition at line 199 of file Decoder.cpp.
{ if (m_macroBlocks) { for (int i=0; i < m_macroBlockLen; i++) delete m_macroBlocks[i]; delete[] m_macroBlocks; } else { delete m_currentBlock; } }
void CDecoder::DecodeBuffer | ( | ) |
Reads stream and decodes tile buffer It might throw an IOException.
Definition at line 462 of file Decoder.cpp.
{ ASSERT(m_macroBlocksAvailable <= 0); // macro block management if (m_macroBlockLen == 1) { ASSERT(m_currentBlock); ReadMacroBlock(m_currentBlock); m_currentBlock->BitplaneDecode(); m_macroBlocksAvailable = 1; } else { m_macroBlocksAvailable = 0; for (int i=0; i < m_macroBlockLen; i++) { // read sequentially several blocks try { ReadMacroBlock(m_macroBlocks[i]); m_macroBlocksAvailable++; } catch(IOException& ex) { if (ex.error == MissingData) { break; // no further data available } else { throw ex; } } } // decode in parallel #pragma omp parallel for default(shared) //no declared exceptions in next block for (int i=0; i < m_macroBlocksAvailable; i++) { m_macroBlocks[i]->BitplaneDecode(); } // prepare current macro block m_currentBlockIndex = 0; m_currentBlock = m_macroBlocks[m_currentBlockIndex]; } }
void CDecoder::DecodeInterleaved | ( | CWaveletTransform * | wtChannel, |
int | level, | ||
int | quantParam | ||
) |
Deccoding and dequantization of HL and LH subband (interleaved) using partitioning scheme. Partitioning scheme: The plane is partitioned in squares of side length InterBlockSize. It might throw an IOException.
wtChannel | A wavelet transform channel containing the HL and HL band |
level | Wavelet transform level |
quantParam | Dequantization value |
Definition at line 301 of file Decoder.cpp.
{ CSubband* hlBand = wtChannel->GetSubband(level, HL); CSubband* lhBand = wtChannel->GetSubband(level, LH); const div_t lhH = div(lhBand->GetHeight(), InterBlockSize); const div_t hlW = div(hlBand->GetWidth(), InterBlockSize); const int hlws = hlBand->GetWidth() - InterBlockSize; const int hlwr = hlBand->GetWidth() - hlW.rem; const int lhws = lhBand->GetWidth() - InterBlockSize; const int lhwr = lhBand->GetWidth() - hlW.rem; int hlPos, lhPos; int hlBase = 0, lhBase = 0, hlBase2, lhBase2; ASSERT(lhBand->GetWidth() >= hlBand->GetWidth()); ASSERT(hlBand->GetHeight() >= lhBand->GetHeight()); if (!hlBand->AllocMemory()) ReturnWithError(InsufficientMemory); if (!lhBand->AllocMemory()) ReturnWithError(InsufficientMemory); // correct quantParam with normalization factor quantParam -= level; if (quantParam < 0) quantParam = 0; // main height for (int i=0; i < lhH.quot; i++) { // main width hlBase2 = hlBase; lhBase2 = lhBase; for (int j=0; j < hlW.quot; j++) { hlPos = hlBase2; lhPos = lhBase2; for (int y=0; y < InterBlockSize; y++) { for (int x=0; x < InterBlockSize; x++) { DequantizeValue(hlBand, hlPos, quantParam); DequantizeValue(lhBand, lhPos, quantParam); hlPos++; lhPos++; } hlPos += hlws; lhPos += lhws; } hlBase2 += InterBlockSize; lhBase2 += InterBlockSize; } // rest of width hlPos = hlBase2; lhPos = lhBase2; for (int y=0; y < InterBlockSize; y++) { for (int x=0; x < hlW.rem; x++) { DequantizeValue(hlBand, hlPos, quantParam); DequantizeValue(lhBand, lhPos, quantParam); hlPos++; lhPos++; } // width difference between HL and LH if (lhBand->GetWidth() > hlBand->GetWidth()) { DequantizeValue(lhBand, lhPos, quantParam); } hlPos += hlwr; lhPos += lhwr; hlBase += hlBand->GetWidth(); lhBase += lhBand->GetWidth(); } } // main width hlBase2 = hlBase; lhBase2 = lhBase; for (int j=0; j < hlW.quot; j++) { // rest of height hlPos = hlBase2; lhPos = lhBase2; for (int y=0; y < lhH.rem; y++) { for (int x=0; x < InterBlockSize; x++) { DequantizeValue(hlBand, hlPos, quantParam); DequantizeValue(lhBand, lhPos, quantParam); hlPos++; lhPos++; } hlPos += hlws; lhPos += lhws; } hlBase2 += InterBlockSize; lhBase2 += InterBlockSize; } // rest of height hlPos = hlBase2; lhPos = lhBase2; for (int y=0; y < lhH.rem; y++) { // rest of width for (int x=0; x < hlW.rem; x++) { DequantizeValue(hlBand, hlPos, quantParam); DequantizeValue(lhBand, lhPos, quantParam); hlPos++; lhPos++; } // width difference between HL and LH if (lhBand->GetWidth() > hlBand->GetWidth()) { DequantizeValue(lhBand, lhPos, quantParam); } hlPos += hlwr; lhPos += lhwr; hlBase += hlBand->GetWidth(); } // height difference between HL and LH if (hlBand->GetHeight() > lhBand->GetHeight()) { // total width hlPos = hlBase; for (int j=0; j < hlBand->GetWidth(); j++) { DequantizeValue(hlBand, hlPos, quantParam); hlPos++; } } }
void CDecoder::DequantizeValue | ( | CSubband * | band, |
UINT32 | bandPos, | ||
int | quantParam | ||
) |
Dequantization of a single value at given position in subband. It might throw an IOException.
band | A subband |
bandPos | A valid position in subband band |
quantParam | The quantization parameter |
Dequantization of a single value at given position in subband. If encoded data is available, then stores dequantized band value into buffer m_value at position m_valuePos. Otherwise reads encoded data block and decodes it. It might throw an IOException.
band | A subband |
bandPos | A valid position in subband band |
quantParam | The quantization parameter |
Definition at line 430 of file Decoder.cpp.
{ ASSERT(m_currentBlock); if (m_currentBlock->IsCompletelyRead()) { // all data of current macro block has been read --> prepare next macro block DecodeTileBuffer(); } band->SetData(bandPos, m_currentBlock->m_value[m_currentBlock->m_valuePos] << quantParam); m_currentBlock->m_valuePos++; }
UINT32 CDecoder::GetEncodedHeaderLength | ( | ) | const [inline] |
Return the length of all encoded headers in bytes.
Definition at line 131 of file Decoder.h.
{ return m_encodedHeaderLength; }
void CDecoder::Partition | ( | CSubband * | band, |
int | quantParam, | ||
int | width, | ||
int | height, | ||
int | startPos, | ||
int | pitch | ||
) |
Unpartitions a rectangular region of a given subband. Partitioning scheme: The plane is partitioned in squares of side length LinBlockSize. Write wavelet coefficients into buffer. It might throw an IOException.
band | A subband |
quantParam | Dequantization value |
width | The width of the rectangle |
height | The height of the rectangle |
startPos | The buffer position of the top left corner of the rectangular region |
pitch | The number of bytes in row of the subband |
Definition at line 234 of file Decoder.cpp.
{ ASSERT(band); const div_t ww = div(width, LinBlockSize); const div_t hh = div(height, LinBlockSize); const int ws = pitch - LinBlockSize; const int wr = pitch - ww.rem; int pos, base = startPos, base2; // main height for (int i=0; i < hh.quot; i++) { // main width base2 = base; for (int j=0; j < ww.quot; j++) { pos = base2; for (int y=0; y < LinBlockSize; y++) { for (int x=0; x < LinBlockSize; x++) { DequantizeValue(band, pos, quantParam); pos++; } pos += ws; } base2 += LinBlockSize; } // rest of width pos = base2; for (int y=0; y < LinBlockSize; y++) { for (int x=0; x < ww.rem; x++) { DequantizeValue(band, pos, quantParam); pos++; } pos += wr; base += pitch; } } // main width base2 = base; for (int j=0; j < ww.quot; j++) { // rest of height pos = base2; for (int y=0; y < hh.rem; y++) { for (int x=0; x < LinBlockSize; x++) { DequantizeValue(band, pos, quantParam); pos++; } pos += ws; } base2 += LinBlockSize; } // rest of height pos = base2; for (int y=0; y < hh.rem; y++) { // rest of width for (int x=0; x < ww.rem; x++) { DequantizeValue(band, pos, quantParam); pos++; } pos += wr; } }
UINT32 CDecoder::ReadEncodedData | ( | UINT8 * | target, |
UINT32 | len | ||
) | const |
Copies data from the open stream to a target buffer. It might throw an IOException.
target | The target buffer |
len | The number of bytes to read |
Definition at line 214 of file Decoder.cpp.
void CDecoder::ReadMacroBlock | ( | CMacroBlock * | block | ) | [private] |
throws IOException
Definition at line 502 of file Decoder.cpp.
{ ASSERT(block); UINT16 wordLen; ROIBlockHeader h(BufferSize); int count, expected; #ifdef TRACE //UINT32 filePos = (UINT32)m_stream->GetPos(); //printf("DecodeBuffer: %d\n", filePos); #endif // read wordLen count = expected = sizeof(UINT16); m_stream->Read(&count, &wordLen); if (count != expected) ReturnWithError(MissingData); wordLen = __VAL(wordLen); if (wordLen > BufferSize) ReturnWithError(FormatCannotRead); #ifdef __PGFROISUPPORT__ // read ROIBlockHeader if (m_roi) { m_stream->Read(&count, &h.val); if (count != expected) ReturnWithError(MissingData); // convert ROIBlockHeader h.val = __VAL(h.val); } #endif // save header block->m_header = h; // read data count = expected = wordLen*WordBytes; m_stream->Read(&count, block->m_codeBuffer); if (count != expected) ReturnWithError(MissingData); #ifdef PGF_USE_BIG_ENDIAN // convert data count /= WordBytes; for (int i=0; i < count; i++) { block->m_codeBuffer[i] = __VAL(block->m_codeBuffer[i]); } #endif #ifdef __PGFROISUPPORT__ ASSERT(m_roi && h.rbh.bufferSize <= BufferSize || h.rbh.bufferSize == BufferSize); #else ASSERT(h.rbh.bufferSize == BufferSize); #endif }
void CDecoder::SetStreamPosToData | ( | ) | [inline] |
Reset stream position to beginning of data block
Definition at line 139 of file Decoder.h.
{ ASSERT(m_stream); m_stream->SetPos(FSFromStart, m_startPos + m_encodedHeaderLength); }
void CDecoder::SetStreamPosToStart | ( | ) | [inline] |
void CDecoder::Skip | ( | UINT64 | offset | ) |
Skip a given number of bytes in the open stream. It might throw an IOException.
Definition at line 417 of file Decoder.cpp.
CMacroBlock* CDecoder::m_currentBlock [private] |
int CDecoder::m_currentBlockIndex [private] |
UINT32 CDecoder::m_encodedHeaderLength [private] |
int CDecoder::m_macroBlockLen [private] |
CMacroBlock** CDecoder::m_macroBlocks [private] |
int CDecoder::m_macroBlocksAvailable [private] |
UINT64 CDecoder::m_startPos [private] |
CPGFStream* CDecoder::m_stream [private] |
UINT64 CDecoder::m_streamSizeEstimation [private] |