Index: configure.ac =================================================================== --- configure.ac (revision 44) +++ configure.ac (revision 48) @@ -6,10 +6,10 @@ dnl The current version of the interface. If interfaces has been dnl added removed changed bump this -INTERFACE_CURRENT=3 +INTERFACE_CURRENT=4 dnl If the source has been changed bump this -INTERFACE_REVISION=3 +INTERFACE_REVISION=5 dnl If any interfaces has been added since last release, bump this dnl If any interfaces has been removed, set this to 0 @@ -24,7 +24,7 @@ AC_SUBST(PACKAGE_RELEASE) -AM_INIT_AUTOMAKE(libpgf,6.11.24) +AM_INIT_AUTOMAKE(libpgf,6.11.32) AC_PROG_LIBTOOL AM_CONFIG_HEADER( config.h ) AC_PROG_CXX Index: include/PGFimage.h =================================================================== --- include/PGFimage.h (revision 44) +++ include/PGFimage.h (revision 48) @@ -117,8 +117,9 @@ ////////////////////////////////////////////////////////////////////// /// After you've written a PGF image, you can call this method followed by GetBitmap/GetYUV /// to get a quick reconstruction (coded -> decoded image). + /// It might throw an IOException. /// @param level The image level of the resulting image in the internal image buffer. - void Reconstruct(int level = 0); + void Reconstruct(int level = 0) THROW_; ////////////////////////////////////////////////////////////////////// /// Get image data in interleaved format: (ordering of RGB data is BGR[A]) @@ -397,7 +398,7 @@ ////////////////////////////////////////////////////////////////////// /// Return bits per channel. /// @return Bits per channel - BYTE ChannelDepth() const { return DataTSize*8; } + BYTE ChannelDepth() const { return (m_preHeader.version & PGF32) ? 32 : 16; } ////////////////////////////////////////////////////////////////////// /// Return image width of channel 0 at given level in pixels. Index: include/PGFplatform.h =================================================================== --- include/PGFplatform.h (revision 44) +++ include/PGFplatform.h (revision 48) @@ -235,7 +235,7 @@ #define NoError ERROR_SUCCESS // no error #define AppError 0x20000000 // all application error messages must be larger than this value #define InsufficientMemory 0x20000001 // memory allocation wasn't successfull -#define EndOfMemory 0x20000002 // like end-of-file (EOF) for memory stream +#define InvalidStreamPos 0x20000002 // invalid memory stream position #define EscapePressed 0x20000003 // user break by ESC #define WrongVersion 0x20000004 // wrong pgf version #define FormatCannotRead 0x20000005 // wrong data file format @@ -499,7 +499,7 @@ #define NoError 0x0000 #define AppError 0x2000 // all application error messages must be larger than this value #define InsufficientMemory 0x2001 // memory allocation wasn't successfull -#define EndOfMemory 0x2002 // like end-of-file (EOF) for memory stream +#define InvalidStreamPos 0x2002 // invalid memory stream position #define EscapePressed 0x2003 // user break by ESC #define WrongVersion 0x2004 // wrong pgf version #define FormatCannotRead 0x2005 // wrong data file format @@ -608,5 +608,30 @@ #endif //PGF_USE_BIG_ENDIAN +// OpenMP rules (inspired from libraw project) +// NOTE: Use LIBPGF_DISABLE_OPENMP to disable OpenMP support in whole libpgf +#ifndef LIBPGF_DISABLE_OPENMP +#if defined (_OPENMP) +# if defined (WIN32) +# if defined (_MSC_VER) && (_MSC_VER >= 1500) +// VS2008 SP1 and VS2010+ : OpenMP works OK +# define LIBPGF_USE_OPENMP +# elif defined (__INTEL_COMPILER) && (__INTEL_COMPILER >=910) +// untested on 9.x and 10.x, Intel documentation claims OpenMP 2.5 support in 9.1 +# define LIBPGF_USE_OPENMP +# else +# undef LIBPGF_USE_OPENMP +# endif +// Not Win32 +# elif (defined(__APPLE__) || defined(__MACOSX__)) && defined(_REENTRANT) +# undef LIBPGF_USE_OPENMP +# else +# define LIBPGF_USE_OPENMP +# endif +#endif // defined (_OPENMP) +#endif // ifndef LIBPGF_DISABLE_OPENMP +#ifdef LIBPGF_USE_OPENMP +#include +#endif #endif //PGF_PGFPLATFORM_H Index: include/PGFtypes.h =================================================================== --- include/PGFtypes.h (revision 44) +++ include/PGFtypes.h (revision 48) @@ -45,8 +45,9 @@ // Version 6: modified data structure PGFPreHeader: hSize (header size) is now a UINT32 instead of a UINT16 (backward compatibility assured) // //------------------------------------------------------------------------------- -#define PGFCodecVersion "6.11.24" // Major number +#define PGFCodecVersion "6.11.32" // Major number // Minor number: Year (2) Week (2) +#define PGFCodecVersionID 0x061132 // Codec version ID to use for API check in client implementation //------------------------------------------------------------------------------- // Image constants @@ -60,16 +61,16 @@ #define ColorTableLen 256 // size of color lookup table (clut) // version flags #define Version2 2 // data structure PGFHeader of major version 2 -#ifdef __PGF32SUPPORT__ - #define PGF32 4 // 32 bit values are used -> allows at maximum 31 bits -#else - #define PGF32 0 // 16 bit values are used -> allows at maximum 15 bits -#endif +#define PGF32 4 // 32 bit values are used -> allows at maximum 31 bits, otherwise 16 bit values are used -> allows at maximum 15 bits #define PGFROI 8 // supports Regions Of Interest #define Version5 16 // new coding scheme since major version 5 #define Version6 32 // new HeaderSize: 32 bits instead of 16 bits // version numbers -#define PGFVersion (Version2 | Version5 | Version6 | PGF32) // current standard version +#ifdef __PGF32SUPPORT__ +#define PGFVersion (Version2 | PGF32 | Version5 | Version6) // current standard version +#else +#define PGFVersion (Version2 | Version5 | Version6) // current standard version +#endif //------------------------------------------------------------------------------- // Coder constants Index: include/PGFstream.h =================================================================== --- include/PGFstream.h (revision 44) +++ include/PGFstream.h (revision 48) @@ -30,6 +30,7 @@ #define PGF_STREAM_H #include "PGFtypes.h" +#include ///////////////////////////////////////////////////////////////////// /// Abstract stream base class. @@ -104,9 +105,10 @@ /// @brief Memory stream class class CPGFMemoryStream : public CPGFStream { protected: - UINT8 *m_buffer, *m_pos; // buffer start address and current buffer address - size_t m_size; // buffer size - bool m_allocated; // indicates a new allocated buffer + UINT8 *m_buffer, *m_pos;// buffer start address and current buffer address + UINT8 *m_eos; // end of stream (first address beyond written area) + size_t m_size; // buffer size + bool m_allocated; // indicates a new allocated buffer public: /// Constructor @@ -124,15 +126,15 @@ virtual ~CPGFMemoryStream() { m_pos = 0; if (m_allocated) { - // the memory buffer has been allocated inside of CPGFMemoryStream constructor + // the memory buffer has been allocated inside of CPMFmemoryStream constructor delete[] m_buffer; m_buffer = 0; } } virtual void Write(int *count, void *buffer) THROW_; // throws IOException - virtual void Read(int *count, void *buffer) THROW_; // throws IOException + virtual void Read(int *count, void *buffer); virtual void SetPos(short posMode, INT64 posOff) THROW_; // throws IOException - virtual UINT64 GetPos() const THROW_; // throws IOException + virtual UINT64 GetPos() const { ASSERT(IsValid()); return m_pos - m_buffer; } virtual bool IsValid() const { return m_buffer != 0; } /// @return Memory size @@ -141,6 +143,10 @@ const UINT8* GetBuffer() const { return m_buffer; } /// @return Memory buffer UINT8* GetBuffer() { return m_buffer; } + /// @return relative position of end of stream (= stream length) + UINT64 GetEOS() const { ASSERT(IsValid()); return m_eos - m_buffer; } + /// @param length Stream length (= relative position of end of stream) + void SetEOS(UINT64 length) { ASSERT(IsValid()); m_eos = m_buffer + length; } }; ///////////////////////////////////////////////////////////////////// Index: PGFCodec.sln =================================================================== --- PGFCodec.sln (revision 44) +++ PGFCodec.sln (revision 48) @@ -4,14 +4,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PGFCodec", "PGFCodec.vcproj", "{5B490780-D7B3-4997-95E3-E9617E474649}" EndProject Global - GlobalSection(TeamFoundationVersionControl) = preSolution - SccNumberOfProjects = 2 - SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} - SccTeamFoundationServer = https://tfs.imvs.technik.fhnw.ch:18443/tfs/UpgradedCollection - SccLocalPath0 = . - SccProjectUniqueName1 = PGFCodec.vcproj - SccLocalPath1 = . - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Pocket PC 2003 (ARMV4) = Debug|Pocket PC 2003 (ARMV4) Debug|Win32 = Debug|Win32 @@ -19,9 +11,15 @@ Debug16|Pocket PC 2003 (ARMV4) = Debug16|Pocket PC 2003 (ARMV4) Debug16|Win32 = Debug16|Win32 Debug16|Windows Mobile 6 Professional SDK (ARMV4I) = Debug16|Windows Mobile 6 Professional SDK (ARMV4I) + Debug16OMP|Pocket PC 2003 (ARMV4) = Debug16OMP|Pocket PC 2003 (ARMV4) + Debug16OMP|Win32 = Debug16OMP|Win32 + Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I) = Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I) DebugMFC|Pocket PC 2003 (ARMV4) = DebugMFC|Pocket PC 2003 (ARMV4) DebugMFC|Win32 = DebugMFC|Win32 DebugMFC|Windows Mobile 6 Professional SDK (ARMV4I) = DebugMFC|Windows Mobile 6 Professional SDK (ARMV4I) + DebugOMP|Pocket PC 2003 (ARMV4) = DebugOMP|Pocket PC 2003 (ARMV4) + DebugOMP|Win32 = DebugOMP|Win32 + DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I) = DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I) Release|Pocket PC 2003 (ARMV4) = Release|Pocket PC 2003 (ARMV4) Release|Win32 = Release|Win32 Release|Windows Mobile 6 Professional SDK (ARMV4I) = Release|Windows Mobile 6 Professional SDK (ARMV4I) @@ -34,6 +32,9 @@ ReleaseMFC|Pocket PC 2003 (ARMV4) = ReleaseMFC|Pocket PC 2003 (ARMV4) ReleaseMFC|Win32 = ReleaseMFC|Win32 ReleaseMFC|Windows Mobile 6 Professional SDK (ARMV4I) = ReleaseMFC|Windows Mobile 6 Professional SDK (ARMV4I) + ReleaseOMP BE|Pocket PC 2003 (ARMV4) = ReleaseOMP BE|Pocket PC 2003 (ARMV4) + ReleaseOMP BE|Win32 = ReleaseOMP BE|Win32 + ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I) = ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I) ReleaseOMP|Pocket PC 2003 (ARMV4) = ReleaseOMP|Pocket PC 2003 (ARMV4) ReleaseOMP|Win32 = ReleaseOMP|Win32 ReleaseOMP|Windows Mobile 6 Professional SDK (ARMV4I) = ReleaseOMP|Windows Mobile 6 Professional SDK (ARMV4I) @@ -51,12 +52,28 @@ {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16|Win32.Build.0 = Debug16|Win32 {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Debug16|Windows Mobile 6 Professional SDK (ARMV4I) {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Debug16|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Pocket PC 2003 (ARMV4).ActiveCfg = Debug16OMP|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Pocket PC 2003 (ARMV4).Build.0 = Debug16OMP|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Pocket PC 2003 (ARMV4).Deploy.0 = Debug16OMP|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Win32.ActiveCfg = Debug16OMP|Win32 + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Win32.Build.0 = Debug16OMP|Win32 + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = Debug16OMP|Windows Mobile 6 Professional SDK (ARMV4I) {5B490780-D7B3-4997-95E3-E9617E474649}.DebugMFC|Pocket PC 2003 (ARMV4).ActiveCfg = DebugMFC|Pocket PC 2003 (ARMV4) {5B490780-D7B3-4997-95E3-E9617E474649}.DebugMFC|Pocket PC 2003 (ARMV4).Build.0 = DebugMFC|Pocket PC 2003 (ARMV4) {5B490780-D7B3-4997-95E3-E9617E474649}.DebugMFC|Win32.ActiveCfg = DebugMFC|Win32 {5B490780-D7B3-4997-95E3-E9617E474649}.DebugMFC|Win32.Build.0 = DebugMFC|Win32 {5B490780-D7B3-4997-95E3-E9617E474649}.DebugMFC|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = DebugMFC|Windows Mobile 6 Professional SDK (ARMV4I) {5B490780-D7B3-4997-95E3-E9617E474649}.DebugMFC|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = DebugMFC|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Pocket PC 2003 (ARMV4).ActiveCfg = DebugOMP|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Pocket PC 2003 (ARMV4).Build.0 = DebugOMP|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Pocket PC 2003 (ARMV4).Deploy.0 = DebugOMP|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Win32.ActiveCfg = DebugOMP|Win32 + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Win32.Build.0 = DebugOMP|Win32 + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = DebugOMP|Windows Mobile 6 Professional SDK (ARMV4I) {5B490780-D7B3-4997-95E3-E9617E474649}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|Pocket PC 2003 (ARMV4) {5B490780-D7B3-4997-95E3-E9617E474649}.Release|Pocket PC 2003 (ARMV4).Build.0 = Release|Pocket PC 2003 (ARMV4) {5B490780-D7B3-4997-95E3-E9617E474649}.Release|Win32.ActiveCfg = Release|Win32 @@ -83,6 +100,14 @@ {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseMFC|Win32.Build.0 = ReleaseMFC|Win32 {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseMFC|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = ReleaseMFC|Windows Mobile 6 Professional SDK (ARMV4I) {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseMFC|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = ReleaseMFC|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Pocket PC 2003 (ARMV4).ActiveCfg = ReleaseOMP BE|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Pocket PC 2003 (ARMV4).Build.0 = ReleaseOMP BE|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Pocket PC 2003 (ARMV4).Deploy.0 = ReleaseOMP BE|Pocket PC 2003 (ARMV4) + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Win32.ActiveCfg = ReleaseOMP BE|Win32 + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Win32.Build.0 = ReleaseOMP BE|Win32 + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I) + {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I).Deploy.0 = ReleaseOMP BE|Windows Mobile 6 Professional SDK (ARMV4I) {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP|Pocket PC 2003 (ARMV4).ActiveCfg = ReleaseOMP|Pocket PC 2003 (ARMV4) {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP|Pocket PC 2003 (ARMV4).Build.0 = ReleaseOMP|Pocket PC 2003 (ARMV4) {5B490780-D7B3-4997-95E3-E9617E474649}.ReleaseOMP|Pocket PC 2003 (ARMV4).Deploy.0 = ReleaseOMP|Pocket PC 2003 (ARMV4) Index: doc/Doxyfile.in =================================================================== --- doc/Doxyfile.in (revision 44) +++ doc/Doxyfile.in (revision 48) @@ -31,7 +31,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 6.11.24 +PROJECT_NUMBER = 6.11.32 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer Index: src/Subband.cpp =================================================================== --- src/Subband.cpp (revision 44) +++ src/Subband.cpp (revision 48) @@ -81,14 +81,14 @@ if (m_data) { if (oldSize >= m_size) { - return false; + return true; } else { delete[] m_data; - m_data = new DataT[m_size]; + m_data = new(std::nothrow) DataT[m_size]; return (m_data != 0); } } else { - m_data = new DataT[m_size]; + m_data = new(std::nothrow) DataT[m_size]; return (m_data != 0); } } @@ -168,14 +168,10 @@ /// Write wavelet coefficients into buffer. /// It might throw an IOException. /// @param encoder An encoder instance -/// @param quant A quantization value (linear scalar quantization) /// @param tile True if just a rectangular region is extracted, false if the entire subband is extracted. /// @param tileX Tile index in x-direction /// @param tileY Tile index in y-direction -void CSubband::ExtractTile(CEncoder& encoder, int quant, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) THROW_ { - // quantize subband - if (tileX == 0 && tileY == 0) Quantize(quant); - +void CSubband::ExtractTile(CEncoder& encoder, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) THROW_ { #ifdef __PGFROISUPPORT__ if (tile) { // compute tile position and size @@ -202,7 +198,7 @@ /// @param tileY Tile index in y-direction void CSubband::PlaceTile(CDecoder& decoder, int quantParam, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) THROW_ { // allocate memory - AllocMemory(); + if (!AllocMemory()) ReturnWithError(InsufficientMemory); // correct quantParam with normalization factor if (m_orientation == LL) { Index: src/Encoder.cpp =================================================================== --- src/Encoder.cpp (revision 44) +++ src/Encoder.cpp (revision 48) @@ -27,7 +27,6 @@ /// @author C. Stamm, R. Spuler #include "Encoder.h" -#include #ifdef TRACE #include #endif @@ -68,9 +67,9 @@ : m_stream(stream) , m_startPosition(0) , m_currLevelIndex(0) +, m_nLevels(header.nLevels) , m_favorSpeed(false) , m_forceWriting(false) -, m_nLevels(header.nLevels) #ifdef __PGFROISUPPORT__ , m_roi(false) #endif @@ -80,15 +79,16 @@ int count; // set number of threads -#ifdef _OPENMP +#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); @@ -96,6 +96,7 @@ m_currentBlock = m_macroBlocks[m_lastMacroBlock++]; } else { m_macroBlocks = 0; + m_macroBlockLen = 1; m_currentBlock = new CMacroBlock(this); } @@ -128,7 +129,6 @@ // renew levelLength delete[] levelLength; levelLength = new UINT32[m_nLevels]; - if (!levelLength) ReturnWithError(InsufficientMemory); for (UINT8 l = 0; l < m_nLevels; l++) levelLength[l] = 0; m_levelLength = levelLength; @@ -279,6 +279,68 @@ } ///////////////////////////////////////////////////////////////////// +// Encode buffer and write data into stream. +// h contains buffer size and flag indicating end of tile. +// Encoding scheme: (16 bits) [ ROI ] data +// ROI ::= (15 bits) (1 bit) +// It might throw an IOException. +void CEncoder::EncodeBuffer(ROIBlockHeader h) THROW_ { + ASSERT(m_currentBlock); +#ifdef __PGFROISUPPORT__ + ASSERT(m_roi && h.rbh.bufferSize <= BufferSize || h.rbh.bufferSize == BufferSize); +#else + ASSERT(h.rbh.bufferSize == BufferSize); +#endif + m_currentBlock->m_header = h; + + // macro block management + if (m_macroBlockLen == 1) { + m_currentBlock->BitplaneEncode(); + WriteMacroBlock(m_currentBlock); + } else { + // save last level index + int lastLevelIndex = m_currentBlock->m_lastLevelIndex; + + if (m_forceWriting || m_lastMacroBlock == m_macroBlockLen) { + // encode macro blocks + /* + volatile OSError error = NoError; + #pragma omp parallel for ordered default(shared) + for (int i=0; i < m_lastMacroBlock; i++) { + if (error == NoError) { + m_macroBlocks[i]->BitplaneEncode(); + #pragma omp ordered + { + try { + WriteMacroBlock(m_macroBlocks[i]); + } catch (IOException& e) { + error = e.error; + } + delete m_macroBlocks[i]; m_macroBlocks[i] = 0; + } + } + } + if (error != NoError) ReturnWithError(error); + */ + #pragma omp parallel for default(shared) //no declared exceptions in next block + for (int i=0; i < m_lastMacroBlock; i++) { + m_macroBlocks[i]->BitplaneEncode(); + } + for (int i=0; i < m_lastMacroBlock; i++) { + WriteMacroBlock(m_macroBlocks[i]); + } + + // prepare for next round + m_forceWriting = false; + m_lastMacroBlock = 0; + } + // re-initialize macro block + m_currentBlock = m_macroBlocks[m_lastMacroBlock++]; + m_currentBlock->Init(lastLevelIndex); + } +} + +///////////////////////////////////////////////////////////////////// // Write encoded macro block into stream. // It might throw an IOException. void CEncoder::WriteMacroBlock(CMacroBlock* block) THROW_ { @@ -308,7 +370,7 @@ // convert data for (int i=0; i < wordLen; i++) { - m_codeBuffer[i] = __VAL(m_codeBuffer[i]); + block->m_codeBuffer[i] = __VAL(block->m_codeBuffer[i]); } #else // write wordLen @@ -343,68 +405,6 @@ block->m_maxAbsValue = 0; } -///////////////////////////////////////////////////////////////////// -// Encode buffer and write data into stream. -// h contains buffer size and flag indicating end of tile. -// Encoding scheme: (16 bits) [ ROI ] data -// ROI ::= (15 bits) (1 bit) -// It might throw an IOException. -void CEncoder::EncodeBuffer(ROIBlockHeader h) THROW_ { - ASSERT(m_currentBlock); -#ifdef __PGFROISUPPORT__ - ASSERT(m_roi && h.rbh.bufferSize <= BufferSize || h.rbh.bufferSize == BufferSize); -#else - ASSERT(h.rbh.bufferSize == BufferSize); -#endif - m_currentBlock->m_header = h; - - // macro block management - if (m_macroBlockLen == 1) { - m_currentBlock->BitplaneEncode(); - WriteMacroBlock(m_currentBlock); - } else { - // save last level index - int lastLevelIndex = m_currentBlock->m_lastLevelIndex; - - if (m_forceWriting || m_lastMacroBlock == m_macroBlockLen) { - // encode macro blocks - /* - volatile OSError error = NoError; - #pragma omp parallel for ordered default(shared) - for (int i=0; i < m_lastMacroBlock; i++) { - if (error == NoError) { - m_macroBlocks[i]->BitplaneEncode(); - #pragma omp ordered - { - try { - WriteMacroBlock(m_macroBlocks[i]); - } catch (IOException& e) { - error = e.error; - } - delete m_macroBlocks[i]; m_macroBlocks[i] = 0; - } - } - } - if (error != NoError) ReturnWithError(error); - */ - #pragma omp parallel for default(shared) //no declared exceptions in next block - for (int i=0; i < m_lastMacroBlock; i++) { - m_macroBlocks[i]->BitplaneEncode(); - } - for (int i=0; i < m_lastMacroBlock; i++) { - WriteMacroBlock(m_macroBlocks[i]); - } - - // prepare for next round - m_forceWriting = false; - m_lastMacroBlock = 0; - } - // re-initialize macro block - m_currentBlock = m_macroBlocks[m_lastMacroBlock++]; - m_currentBlock->Init(lastLevelIndex); - } -} - //////////////////////////////////////////////////////// // Encode buffer of given size using bit plane coding. // A buffer contains bufferLen UINT32 values, thus, bufferSize bits per bit plane. Index: src/PGFimage.cpp =================================================================== --- src/PGFimage.cpp (revision 44) +++ src/PGFimage.cpp (revision 48) @@ -62,12 +62,12 @@ , m_favorSpeedOverSize(false) , m_useOMPinEncoder(true) , m_useOMPinDecoder(true) -, m_cb(0) -, m_cbArg(0) #ifdef __PGFROISUPPORT__ , m_levelwise(true) , m_streamReinitialized(false) #endif +, m_cb(0) +, m_cbArg(0) { // init preHeader @@ -103,7 +103,7 @@ Close(); for (int i=0; i < m_header.channels; i++) { - delete m_wtChannel[i]; m_wtChannel[i]=0; + delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel m_channel[i] = 0; } delete[] m_postHeader.userData; m_postHeader.userData = 0; m_postHeader.userDataLen = 0; @@ -127,8 +127,6 @@ ASSERT(stream); m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, m_useOMPinDecoder); - if (!m_decoder) ReturnWithError(InsufficientMemory); - ASSERT(m_decoder); if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead); @@ -175,7 +173,6 @@ // init wavelet subbands for (int i=0; i < m_header.channels; i++) { m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels); - if (!m_wtChannel[i]) ReturnWithError(InsufficientMemory); } } else { // very small image: we don't use DWT and encoding @@ -311,8 +308,9 @@ ////////////////////////////////////////////////////////////////////// /// After you've written a PGF image, you can call this method followed by GetBitmap/GetYUV /// to get a quick reconstruction (coded -> decoded image). +/// It might throw an IOException. /// @param level The image level of the resulting image in the internal image buffer. -void CPGFImage::Reconstruct(int level /*= 0*/) { +void CPGFImage::Reconstruct(int level /*= 0*/) THROW_ { if (m_header.nLevels == 0) { // image didn't use wavelet transform if (level == 0) { @@ -342,7 +340,7 @@ m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant); // inverse transform from m_wtChannel to m_channel - m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]); + if (!m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i])) ReturnWithError(InsufficientMemory); ASSERT(m_channel[i]); } @@ -408,12 +406,17 @@ m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant); } + volatile OSError error = NoError; // volatile prevents optimizations #pragma omp parallel for default(shared) for (int i=0; i < m_header.channels; i++) { // inverse transform from m_wtChannel to m_channel - m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]); + if (error == NoError) { + OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]); + if (err != NoError) error = err; + } ASSERT(m_channel[i]); } + if (error != NoError) ReturnWithError(error); // set new level: must be done before refresh callback m_currentLevel--; @@ -502,12 +505,17 @@ } } + volatile OSError error = NoError; // volatile prevents optimizations #pragma omp parallel for default(shared) for (int i=0; i < m_header.channels; i++) { // inverse transform from m_wtChannel to m_channel - m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]); + if (error == NoError) { + OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]); + if (err != NoError) error = err; + } ASSERT(m_channel[i]); } + if (error != NoError) ReturnWithError(error); // set new level: must be done before refresh callback m_currentLevel--; @@ -821,7 +829,6 @@ void CPGFImage::SetHeader(const PGFHeader& header, BYTE flags /*=0*/, UINT8* userData /*= 0*/, UINT32 userDataLength /*= 0*/) THROW_ { ASSERT(!m_decoder); // current image must be closed ASSERT(header.quality <= MaxQuality); - int i; // init state #ifdef __PGFROISUPPORT__ @@ -870,22 +877,30 @@ m_preHeader.hSize += ColorTableSize; } if (userDataLength && userData) { - m_postHeader.userData = new UINT8[userDataLength]; + m_postHeader.userData = new(std::nothrow) UINT8[userDataLength]; + if (!m_postHeader.userData) ReturnWithError(InsufficientMemory); m_postHeader.userDataLen = userDataLength; memcpy(m_postHeader.userData, userData, userDataLength); m_preHeader.hSize += userDataLength; } // allocate channels - for (i=0; i < m_header.channels; i++) { + for (int i=0; i < m_header.channels; i++) { // set current width and height m_width[i] = m_header.width; m_height[i] = m_header.height; // allocate channels ASSERT(!m_channel[i]); - m_channel[i] = new DataT[m_header.width*m_header.height]; - if (!m_channel[i]) ReturnWithError(InsufficientMemory); + m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height]; + if (!m_channel[i]) { + if (i) i--; + while(i) { + delete[] m_channel[i]; m_channel[i] = 0; + i--; + } + ReturnWithError(InsufficientMemory); + } } } @@ -911,7 +926,7 @@ ASSERT(m_channel[i]); // copy m_channel to temp int size = m_height[i]*m_width[i]; - temp = new DataT[size]; + temp = new(std::nothrow) DataT[size]; if (temp) { memcpy(temp, m_channel[i], size*DataTSize); delete m_wtChannel[i]; // also deletes m_channel @@ -919,16 +934,15 @@ error = InsufficientMemory; } } - if (temp) m_channel[i] = temp; - m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]); - if (m_wtChannel[i]) { + if (error == NoError) { + if (temp) m_channel[i] = temp; + m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]); + // wavelet subband decomposition - for (int l=0; l < m_header.nLevels; l++) { - m_wtChannel[i]->ForwardTransform(l); + for (int l=0; error == NoError && l < m_header.nLevels; l++) { + OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant); + if (err != NoError) error = err; } - } else { - delete temp; - error = InsufficientMemory; } } } @@ -1011,14 +1025,14 @@ if (m_currentLevel == m_header.nLevels) { // last level also has LL band ASSERT(nTiles == 1); - m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder, m_quant); + m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder); m_encoder->EncodeTileBuffer(); } for (UINT32 tileY=0; tileY < nTiles; tileY++) { for (UINT32 tileX=0; tileX < nTiles; tileX++) { - m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, m_quant, true, tileX, tileY); - m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, m_quant, true, tileX, tileY); - m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, m_quant, true, tileX, tileY); + m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY); + m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY); + m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY); if (i == lastChannel && tileY == lastTile && tileX == lastTile) { // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level. m_encoder->SetEncodedLevel(--m_currentLevel); @@ -1034,12 +1048,12 @@ ASSERT(m_wtChannel[i]); if (m_currentLevel == m_header.nLevels) { // last level also has LL band - m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder, m_quant); + m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder); } //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4 - m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, m_quant); // since version 5 - m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, m_quant); // since version 5 - m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, m_quant); + m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5 + m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5 + m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder); } // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level. @@ -1193,6 +1207,7 @@ //case ImageModeDuotone: case ImageModeLabColor: case ImageModeRGB12: + case ImageModeRGB16: case ImageModeRGBA: return true; } @@ -1200,7 +1215,6 @@ if (size >= 3) { switch(mode) { case ImageModeGray16: - case ImageModeRGB16: case ImageModeRGB48: case ImageModeLab48: case ImageModeCMYK64: @@ -1657,7 +1671,8 @@ // create temporary output buffer targetBuff = buff; - buff = buffStart = new UINT8[pitch*h]; + buff = buffStart = new(std::nothrow) UINT8[pitch*h]; + if (!buff) ReturnWithError(InsufficientMemory); } #endif Index: src/Subband.h =================================================================== --- src/Subband.h (revision 44) +++ src/Subband.h (revision 48) @@ -69,7 +69,7 @@ /// @param tile True if just a rectangular region is extracted, false if the entire subband is extracted. /// @param tileX Tile index in x-direction /// @param tileY Tile index in y-direction - void ExtractTile(CEncoder& encoder, int quant, bool tile = false, UINT32 tileX = 0, UINT32 tileY = 0) THROW_; + void ExtractTile(CEncoder& encoder, bool tile = false, UINT32 tileX = 0, UINT32 tileY = 0) THROW_; ///////////////////////////////////////////////////////////////////// /// Decoding and dequantization of this subband. Index: src/WaveletTransform.cpp =================================================================== --- src/WaveletTransform.cpp (revision 44) +++ src/WaveletTransform.cpp (revision 48) @@ -81,7 +81,9 @@ // high pass filter at even positions: 1/4(-2, 4, -2) // low pass filter at odd positions: 1/8(-1, 2, 6, 2, -1) // @param level A wavelet transform pyramid level (>= 0 && < Levels()) -void CWaveletTransform::ForwardTransform(int level) { +// @param quant A quantization value (linear scalar quantization) +// @return error in case of a memory allocation problem +OSError CWaveletTransform::ForwardTransform(int level, int quant) { ASSERT(level >= 0 && level < m_nLevels - 1); const int destLevel = level + 1; ASSERT(m_subband[destLevel]); @@ -94,7 +96,7 @@ // Allocate memory for next transform level for (i=0; i < NSubbands; i++) { - m_subband[destLevel][i].AllocMemory(); + if (!m_subband[destLevel][i].AllocMemory()) return InsufficientMemory; } if (height >= FilterHeight) { @@ -157,8 +159,20 @@ } } + if (quant > 0) { + // subband quantization (without LL) + for (i=1; i < NSubbands; i++) { + m_subband[destLevel][i].Quantize(quant); + } + // LL subband quantization + if (destLevel == m_nLevels - 1) { + m_subband[destLevel][LL].Quantize(quant); + } + } + // free source band srcBand->FreeMemory(); + return NoError; } ////////////////////////////////////////////////////////////// @@ -229,7 +243,8 @@ // @param w [out] A pointer to the returned width of subband LL (in pixels) // @param h [out] A pointer to the returned height of subband LL (in pixels) // @param data [out] A pointer to the returned array of image data -void CWaveletTransform::InverseTransform(int srcLevel, UINT32* w, UINT32* h, DataT** data) { +// @return error in case of a memory allocation problem +OSError CWaveletTransform::InverseTransform(int srcLevel, UINT32* w, UINT32* h, DataT** data) { ASSERT(srcLevel > 0 && srcLevel < m_nLevels); const int destLevel = srcLevel - 1; ASSERT(m_subband[destLevel]); @@ -239,7 +254,7 @@ UINT32 row0, row1, row2, row3, i, k, origin = 0; // allocate memory for the results of the inverse transform - destBand->AllocMemory(); + if (!destBand->AllocMemory()) return InsufficientMemory; DataT* dest = destBand->GetBuffer(); #ifdef __PGFROISUPPORT__ @@ -361,9 +376,8 @@ // return info *w = destWidth; *h = destHeight; -// *w = width; -// *h = height; *data = dest; + return NoError; } ////////////////////////////////////////////////////////////////////// Index: src/Encoder.h =================================================================== --- src/Encoder.h (revision 44) +++ src/Encoder.h (revision 48) @@ -49,14 +49,33 @@ /// @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) - : m_encoder(encoder) - , m_header(0) + : m_header(0) + , m_encoder(encoder) { 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[BufferSize]; // output buffer for encoded bitstream @@ -66,13 +85,6 @@ 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 - void Init(int lastLevelIndex) { // initialize for reusage - m_valuePos = 0; - m_maxAbsValue = 0; - m_codePos = 0; - m_lastLevelIndex = lastLevelIndex; - } - void BitplaneEncode(); // several macro blocks can be encoded in parallel 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); Index: src/Decoder.cpp =================================================================== --- src/Decoder.cpp (revision 44) +++ src/Decoder.cpp (revision 48) @@ -27,7 +27,6 @@ /// @author C. Stamm, R. Spuler #include "Decoder.h" -#include #ifdef TRACE #include #endif @@ -65,10 +64,10 @@ CDecoder::CDecoder(CPGFStream* stream, PGFPreHeader& preHeader, PGFHeader& header, PGFPostHeader& postHeader, UINT32*& levelLength, bool useOMP /*= true*/) THROW_ : m_stream(stream) , m_startPos(0) -, m_encodedHeaderLength(0) , m_streamSizeEstimation(0) -, m_macroBlocksAvailable(0) +, m_encodedHeaderLength(0) , m_currentBlockIndex(0) +, m_macroBlocksAvailable(0) #ifdef __PGFROISUPPORT__ , m_roi(false) #endif @@ -78,21 +77,25 @@ int count, expected; // set number of threads -#ifdef _OPENMP +#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_currentBlock = new CMacroBlock(this); + m_macroBlockLen = 1; // there is only one macro block + m_currentBlock = new CMacroBlock(this); } // store current stream position @@ -143,7 +146,7 @@ if (size > 0) { // read post header if (header.mode == ImageModeIndexedColor) { - ASSERT(size >= ColorTableSize); + ASSERT((size_t)size >= ColorTableSize); // read color table count = expected = ColorTableSize; m_stream->Read(&count, postHeader.clut); @@ -154,7 +157,8 @@ if (size > 0) { // create user data memory block postHeader.userDataLen = size; - postHeader.userData = new UINT8[postHeader.userDataLen]; + postHeader.userData = new(std::nothrow) UINT8[postHeader.userDataLen]; + if (!postHeader.userData) ReturnWithError(InsufficientMemory); // read user data count = expected = postHeader.userDataLen; @@ -165,7 +169,6 @@ // create levelLength levelLength = new UINT32[header.nLevels]; - if (!levelLength) ReturnWithError(InsufficientMemory); // read levelLength count = expected = header.nLevels*WordBytes; @@ -309,8 +312,8 @@ ASSERT(lhBand->GetWidth() >= hlBand->GetWidth()); ASSERT(hlBand->GetHeight() >= lhBand->GetHeight()); - hlBand->AllocMemory(); - lhBand->AllocMemory(); + if (!hlBand->AllocMemory()) ReturnWithError(InsufficientMemory); + if (!lhBand->AllocMemory()) ReturnWithError(InsufficientMemory); // correct quantParam with normalization factor quantParam -= level; @@ -418,28 +421,81 @@ /// 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 buffer and decodes it. +/// Otherwise reads encoded data block and decodes it. +/// It might throw an IOException. /// @param band A subband /// @param bandPos A valid position in subband band /// @param quantParam The quantization parameter -void CDecoder::DequantizeValue(CSubband* band, UINT32 bandPos, int quantParam) { - if (!m_macroBlocksAvailable) { - DecodeBuffer(); - ASSERT(m_currentBlock); - ASSERT(m_currentBlock->m_valuePos == 0); - ASSERT(m_macroBlocksAvailable); +void CDecoder::DequantizeValue(CSubband* band, UINT32 bandPos, int quantParam) THROW_ { + 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++; - if (m_currentBlock->m_valuePos == BufferSize) { - // current block has been read - m_macroBlocksAvailable--; - if (m_macroBlocksAvailable) - m_currentBlock = m_macroBlocks[++m_currentBlockIndex]; +} + +////////////////////////////////////////////////////////////////////// +// Read next group of blocks from stream and decodes them into macro blocks +// It might throw an IOException. +void CDecoder::DecodeTileBuffer() THROW_ { + // current block has been read --> prepare next current block + m_macroBlocksAvailable--; + + if (m_macroBlocksAvailable > 0) { + m_currentBlock = m_macroBlocks[++m_currentBlockIndex]; + } else { + DecodeBuffer(); } + ASSERT(m_currentBlock); } ////////////////////////////////////////////////////////////////////// +// Read next block from stream and decode into macro block +// Decoding scheme: (16 bits) [ ROI ] data +// ROI ::= (15 bits) (1 bit) +// It might throw an IOException. +void CDecoder::DecodeBuffer() THROW_ { + 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]; + } +} + +////////////////////////////////////////////////////////////////////// // Read next block from stream and store it in the given block // It might throw an IOException. void CDecoder::ReadMacroBlock(CMacroBlock* block) THROW_ { @@ -501,12 +557,12 @@ // ROI ::= (15 bits) (1 bit) // It might throw an IOException. void CDecoder::SkipTileBuffer() THROW_ { + // current block is not used + m_macroBlocksAvailable--; + // check if pre-decoded data is available - if (m_macroBlocksAvailable) { - // current block is not used - m_macroBlocksAvailable--; - if (m_macroBlocksAvailable) - m_currentBlock = m_macroBlocks[++m_currentBlockIndex]; + if (m_macroBlocksAvailable > 0) { + m_currentBlock = m_macroBlocks[++m_currentBlockIndex]; return; } @@ -532,63 +588,6 @@ } ////////////////////////////////////////////////////////////////////// -// Read next block from stream and decode into macro block -// It might throw an IOException. -void CDecoder::DecodeTileBuffer() THROW_ { - if (m_macroBlocksAvailable) { - // current block has been read - m_macroBlocksAvailable--; - if (m_macroBlocksAvailable) - m_currentBlock = m_macroBlocks[++m_currentBlockIndex]; - } else { - DecodeBuffer(); - ASSERT(m_currentBlock); - ASSERT(m_currentBlock->m_valuePos == 0); - ASSERT(m_macroBlocksAvailable); - } -} - -////////////////////////////////////////////////////////////////////// -// Read next block from stream and decode into macro block -// Decoding scheme: (16 bits) [ ROI ] data -// ROI ::= (15 bits) (1 bit) -// It might throw an IOException. -void CDecoder::DecodeBuffer() THROW_ { - ASSERT(m_macroBlocksAvailable == 0); - - // macro block management - if (m_macroBlockLen == 1) { - ASSERT(m_currentBlock); - ReadMacroBlock(m_currentBlock); - m_currentBlock->BitplaneDecode(); - m_macroBlocksAvailable = 1; - } else { - 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 levels 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(); - } - - m_currentBlockIndex = 0; - m_currentBlock = m_macroBlocks[m_currentBlockIndex]; - } -} - -////////////////////////////////////////////////////////////////////// // Decode block into buffer of given size using bit plane coding. // A buffer contains bufferLen UINT32 values, thus, bufferSize bits per bit plane. // Following coding scheme is used: Index: src/PGFstream.cpp =================================================================== --- src/PGFstream.cpp (revision 44) +++ src/PGFstream.cpp (revision 48) @@ -78,7 +78,7 @@ CPGFMemoryStream::CPGFMemoryStream(size_t size) THROW_ : m_size(size) , m_allocated(true) { - m_buffer = m_pos = new UINT8[m_size]; + m_buffer = m_pos = m_eos = new(std::nothrow) UINT8[m_size]; if (!m_buffer) ReturnWithError(InsufficientMemory); } @@ -89,6 +89,7 @@ CPGFMemoryStream::CPGFMemoryStream(UINT8 *pBuffer, size_t size) THROW_ : m_buffer(pBuffer) , m_pos(pBuffer) +, m_eos(pBuffer + size) , m_size(size) , m_allocated(false) { ASSERT(IsValid()); @@ -100,9 +101,9 @@ /// @param size Memory size void CPGFMemoryStream::Reinitialize(UINT8 *pBuffer, size_t size) THROW_ { if (!m_allocated) { - m_buffer = pBuffer; - m_pos = pBuffer; + m_buffer = m_pos = pBuffer; m_size = size; + m_eos = m_buffer + size; } } @@ -115,7 +116,8 @@ if (m_pos + *count <= m_buffer + m_size) { memcpy(m_pos, buffPtr, *count); - m_pos += *count; + m_pos += *count; + if (m_pos > m_eos) m_eos = m_pos; } else if (m_allocated) { // memory block is too small -> reallocate a deltaSize larger block size_t offset = m_pos - m_buffer; @@ -134,28 +136,32 @@ // write block memcpy(m_pos, buffPtr, *count); - m_pos += *count; + m_pos += *count; + if (m_pos > m_eos) m_eos = m_pos; } else { ReturnWithError(InsufficientMemory); } + ASSERT(m_pos <= m_eos); } ////////////////////////////////////////////////////////////////////// -void CPGFMemoryStream::Read(int *count, void *buffPtr) THROW_ { +void CPGFMemoryStream::Read(int *count, void *buffPtr) { + ASSERT(IsValid()); ASSERT(count); ASSERT(buffPtr); - ASSERT(IsValid()); + ASSERT(m_buffer + m_size >= m_eos); + ASSERT(m_pos <= m_eos); - if (m_pos + *count <= m_buffer + m_size) { + if (m_pos + *count <= m_eos) { memcpy(buffPtr, m_pos, *count); m_pos += *count; } else { // end of memory block reached -> read only until end - *count = (int)(m_buffer + m_size - m_pos); + *count = (int)__max(0, m_eos - m_pos); memcpy(buffPtr, m_pos, *count); m_pos += *count; - ReturnWithError(EndOfMemory); } + ASSERT(m_pos <= m_eos); } ////////////////////////////////////////////////////////////////////// @@ -169,20 +175,16 @@ m_pos += posOff; break; case FSFromEnd: - m_pos = m_buffer + m_size + posOff; + m_pos = m_eos + posOff; break; default: ASSERT(false); } + if (m_pos > m_eos) + ReturnWithError(InvalidStreamPos); } -////////////////////////////////////////////////////////////////////// -UINT64 CPGFMemoryStream::GetPos() const THROW_ { - ASSERT(IsValid()); - return m_pos - m_buffer; -} - ////////////////////////////////////////////////////////////////////// // CPGFMemFileStream #ifdef _MFC_VER Index: src/WaveletTransform.h =================================================================== --- src/WaveletTransform.h (revision 44) +++ src/WaveletTransform.h (revision 48) @@ -109,7 +109,9 @@ /// Compute fast forward wavelet transform of LL subband at given level and /// stores result on all 4 subbands of level + 1. /// @param level A wavelet transform pyramid level (>= 0 && < Levels()) - void ForwardTransform(int level); + /// @param quant A quantization value (linear scalar quantization) + /// @return error in case of a memory allocation problem + OSError ForwardTransform(int level, int quant); ////////////////////////////////////////////////////////////////////// /// Compute fast inverse wavelet transform of all 4 subbands of given level and @@ -118,7 +120,8 @@ /// @param width A pointer to the returned width of subband LL (in pixels) /// @param height A pointer to the returned height of subband LL (in pixels) /// @param data A pointer to the returned array of image data - void InverseTransform(int level, UINT32* width, UINT32* height, DataT** data); + /// @return error in case of a memory allocation problem + OSError InverseTransform(int level, UINT32* width, UINT32* height, DataT** data); ////////////////////////////////////////////////////////////////////// /// Get pointer to one of the 4 subband at a given level. Index: src/Decoder.h =================================================================== --- src/Decoder.h (revision 44) +++ src/Decoder.h (revision 48) @@ -49,16 +49,28 @@ /// @brief A macro block is a decoding unit of fixed size (uncoded) class CMacroBlock { public: + ////////////////////////////////////////////////////////////////////// + /// Constructor: Initializes new macro block. + /// @param decoder Pointer to outer class. CMacroBlock(CDecoder *decoder) - : m_decoder(decoder) - , m_header(0) + : m_header(0) // makes sure that IsCompletelyRead() returns true for an empty macro block , m_valuePos(0) + , m_decoder(decoder) { ASSERT(m_decoder); } - void BitplaneDecode(); // several macro blocks can be encoded in parallel + ////////////////////////////////////////////////////////////////////// + /// Returns true if this macro block has been completely read. + /// @return true if current value position is at block end + bool IsCompletelyRead() const { return m_valuePos >= m_header.rbh.bufferSize; } + ////////////////////////////////////////////////////////////////////// + /// Decodes already read input data into this macro block. + /// Several macro blocks can be decoded in parallel. + /// Call CDecoder::ReadMacroBlock before this method. + void BitplaneDecode(); + ROIBlockHeader m_header; // block header DataT m_value[BufferSize]; // output buffer of values with index m_valuePos UINT32 m_codeBuffer[BufferSize]; // input buffer for encoded bitstream @@ -133,10 +145,11 @@ ///////////////////////////////////////////////////////////////////// /// Dequantization of a single value at given position in subband. + /// It might throw an IOException. /// @param band A subband /// @param bandPos A valid position in subband band /// @param quantParam The quantization parameter - void DequantizeValue(CSubband* band, UINT32 bandPos, int quantParam); + void DequantizeValue(CSubband* band, UINT32 bandPos, int quantParam) THROW_; ////////////////////////////////////////////////////////////////////// /// Copies data from the open stream to a target buffer. @@ -182,7 +195,7 @@ 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 + int m_macroBlocksAvailable; // number of decoded macro blocks (including currently used macro block) CMacroBlock *m_currentBlock; // current macro block (used by main thread) #ifdef __PGFROISUPPORT__ Index: PGFCodec.vcproj =================================================================== --- PGFCodec.vcproj (revision 44) +++ PGFCodec.vcproj (revision 48) @@ -26,10 +26,10 @@ OutputDirectory="lib\$(PlatformName)" IntermediateDirectory="$(PlatformName)\$(ConfigurationName)" ConfigurationType="4" - InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="false" CharacterSet="2" + EnableManagedIncrementalBuild="0" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1991,6 +2727,22 @@ WarningLevel="4" /> + + + + + +