/* * The Progressive Graphics File; http://www.libpgf.org * * $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $ * $Revision: 229 $ * * This file Copyright (C) 2006 xeraina GmbH, Switzerland * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ ////////////////////////////////////////////////////////////////////// /// @file Encoder.h /// @brief PGF encoder class /// @author C. Stamm, R. Spuler #ifndef PGF_ENCODER_H #define PGF_ENCODER_H #include "PGFstream.h" #include "BitStream.h" #include "Subband.h" #include "WaveletTransform.h" ///////////////////////////////////////////////////////////////////// // Constants #define BufferLen (BufferSize/WordWidth) ///< number of words per buffer #define CodeBufferLen BufferSize ///< number of words in code buffer (CodeBufferLen > BufferLen) ///////////////////////////////////////////////////////////////////// /// PGF encoder class. /// @author C. Stamm /// @brief PGF encoder class CEncoder { ////////////////////////////////////////////////////////////////////// /// PGF encoder macro block class. /// @author C. Stamm, I. Bauersachs /// @brief A macro block is an encoding unit of fixed size (uncoded) class CMacroBlock { public: ////////////////////////////////////////////////////////////////////// /// Constructor: Initializes new macro block. /// @param encoder Pointer to outer class. CMacroBlock(CEncoder *encoder) #ifdef _MSC_VER #pragma warning( suppress : 4351 ) #endif : m_value() , m_codeBuffer() , m_header(0) , m_encoder(encoder) , m_sigFlagVector() { ASSERT(m_encoder); Init(-1); } ////////////////////////////////////////////////////////////////////// /// Reinitialzes this macro block (allows reusage). /// @param lastLevelIndex Level length directory index of last encoded level: [0, nLevels) void Init(int lastLevelIndex) { // initialize for reusage m_valuePos = 0; m_maxAbsValue = 0; m_codePos = 0; m_lastLevelIndex = lastLevelIndex; } ////////////////////////////////////////////////////////////////////// /// Encodes this macro block into internal code buffer. /// Several macro blocks can be encoded in parallel. /// Call CEncoder::WriteMacroBlock after this method. void BitplaneEncode(); DataT m_value[BufferSize]; ///< input buffer of values with index m_valuePos UINT32 m_codeBuffer[CodeBufferLen]; ///< output buffer for encoded bitstream ROIBlockHeader m_header; ///< block header UINT32 m_valuePos; ///< current buffer position UINT32 m_maxAbsValue; ///< maximum absolute coefficient in each buffer UINT32 m_codePos; ///< current position in encoded bitstream int m_lastLevelIndex; ///< index of last encoded level: [0, nLevels); used because a level-end can occur before a buffer is full private: UINT32 RLESigns(UINT32 codePos, UINT32* signBits, UINT32 signLen); UINT32 DecomposeBitplane(UINT32 bufferSize, UINT32 planeMask, UINT32 codePos, UINT32* sigBits, UINT32* refBits, UINT32* signBits, UINT32& signLen, UINT32& codeLen); UINT8 NumberOfBitplanes(); bool GetBitAtPos(UINT32 pos, UINT32 planeMask) const { return (abs(m_value[pos]) & planeMask) > 0; } CEncoder *m_encoder; // encoder instance bool m_sigFlagVector[BufferSize+1]; // see paper from Malvar, Fast Progressive Wavelet Coder }; public: ///////////////////////////////////////////////////////////////////// /// Write pre-header, header, post-Header, and levelLength. /// It might throw an IOException. /// @param stream A PGF stream /// @param preHeader A already filled in PGF pre-header /// @param header An already filled in PGF header /// @param postHeader [in] An already filled in PGF post-header (containing color table, user data, ...) /// @param userDataPos [out] File position of user data /// @param useOMP If true, then the encoder will use multi-threading based on openMP CEncoder(CPGFStream* stream, PGFPreHeader preHeader, PGFHeader header, const PGFPostHeader& postHeader, UINT64& userDataPos, bool useOMP); // throws IOException ///////////////////////////////////////////////////////////////////// /// Destructor ~CEncoder(); ///////////////////////////////////////////////////////////////////// /// Encoder favors speed over compression size void FavorSpeedOverSize() { m_favorSpeed = true; } ///////////////////////////////////////////////////////////////////// /// Pad buffer with zeros and encode buffer. /// It might throw an IOException. void Flush(); ///////////////////////////////////////////////////////////////////// /// Increase post-header size and write new size into stream. /// @param preHeader An already filled in PGF pre-header /// It might throw an IOException. void UpdatePostHeaderSize(PGFPreHeader preHeader); ///////////////////////////////////////////////////////////////////// /// Create level length data structure and write a place holder into stream. /// It might throw an IOException. /// @param levelLength A reference to an integer array, large enough to save the relative file positions of all PGF levels /// @return number of bytes written into stream UINT32 WriteLevelLength(UINT32*& levelLength); ///////////////////////////////////////////////////////////////////// /// Write new levelLength into stream. /// It might throw an IOException. /// @return Written image bytes. UINT32 UpdateLevelLength(); ///////////////////////////////////////////////////////////////////// /// Partitions a rectangular region of a given subband. /// Partitioning scheme: The plane is partitioned in squares of side length LinBlockSize. /// Write wavelet coefficients from subband into the input buffer of a macro block. /// It might throw an IOException. /// @param band A subband /// @param width The width of the rectangle /// @param height The height of the rectangle /// @param startPos The absolute subband position of the top left corner of the rectangular region /// @param pitch The number of bytes in row of the subband void Partition(CSubband* band, int width, int height, int startPos, int pitch); ///////////////////////////////////////////////////////////////////// /// Informs the encoder about the encoded level. /// @param currentLevel encoded level [0, nLevels) void SetEncodedLevel(int currentLevel) { ASSERT(currentLevel >= 0); m_currentBlock->m_lastLevelIndex = m_nLevels - currentLevel - 1; m_forceWriting = true; } ///////////////////////////////////////////////////////////////////// /// Write a single value into subband at given position. /// It might throw an IOException. /// @param band A subband /// @param bandPos A valid position in subband band void WriteValue(CSubband* band, int bandPos); ///////////////////////////////////////////////////////////////////// /// Compute stream length of header. /// @return header length INT64 ComputeHeaderLength() const { return m_levelLengthPos - m_startPosition; } ///////////////////////////////////////////////////////////////////// /// Compute stream length of encoded buffer. /// @return encoded buffer length INT64 ComputeBufferLength() const { return m_stream->GetPos() - m_bufferStartPos; } ///////////////////////////////////////////////////////////////////// /// Compute file offset between real and expected levelLength position. /// @return file offset INT64 ComputeOffset() const { return m_stream->GetPos() - m_levelLengthPos; } //////////////////////////////////////////////////////////////////// /// Resets stream position to beginning of PGF pre-header void SetStreamPosToStart() { ASSERT(m_stream); m_stream->SetPos(FSFromStart, m_startPosition); } ///////////////////////////////////////////////////////////////////// /// Save current stream position as beginning of current level. void SetBufferStartPos() { m_bufferStartPos = m_stream->GetPos(); } #ifdef __PGFROISUPPORT__ ///////////////////////////////////////////////////////////////////// /// Encodes tile buffer and writes it into stream /// It might throw an IOException. void EncodeTileBuffer() { ASSERT(m_currentBlock && m_currentBlock->m_valuePos >= 0 && m_currentBlock->m_valuePos <= BufferSize); EncodeBuffer(ROIBlockHeader(m_currentBlock->m_valuePos, true)); } ///////////////////////////////////////////////////////////////////// /// Enables region of interest (ROI) status. void SetROI() { m_roi = true; } #endif #ifdef TRACE void DumpBuffer() const; #endif private: void EncodeBuffer(ROIBlockHeader h); // throws IOException void WriteMacroBlock(CMacroBlock* block); // throws IOException CPGFStream *m_stream; ///< output PMF stream UINT64 m_startPosition; ///< stream position of PGF start (PreHeader) UINT64 m_levelLengthPos; ///< stream position of Metadata UINT64 m_bufferStartPos; ///< stream position of encoded buffer CMacroBlock **m_macroBlocks; ///< array of macroblocks int m_macroBlockLen; ///< array length int m_lastMacroBlock; ///< array index of the last created macro block CMacroBlock *m_currentBlock; ///< current macro block (used by main thread) UINT32* m_levelLength; ///< temporary saves the level index int m_currLevelIndex; ///< counts where (=index) to save next value UINT8 m_nLevels; ///< number of levels bool m_favorSpeed; ///< favor speed over size bool m_forceWriting; ///< all macro blocks have to be written into the stream #ifdef __PGFROISUPPORT__ bool m_roi; ///< true: ensures region of interest (ROI) encoding #endif }; #endif //PGF_ENCODER