1 // 2 // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. 3 // 4 5 #ifndef CHARLS_ENCODERSTRATEGY 6 #define CHARLS_ENCODERSTRATEGY 7 8 #include "processline.h" 9 #include "decoderstrategy.h" 10 11 12 // Purpose: Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy 13 class EncoderStrategy 14 { 15 16 public: EncoderStrategy(const JlsParameters & params)17 explicit EncoderStrategy(const JlsParameters& params) : 18 _params(params), 19 _bitBuffer(0), 20 _freeBitCount(sizeof(_bitBuffer) * 8), 21 _compressedLength(0), 22 _position(nullptr), 23 _isFFWritten(false), 24 _bytesWritten(0), 25 _compressedStream(nullptr) 26 { 27 } 28 29 virtual ~EncoderStrategy() 30 = default; 31 32 int32_t PeekByte(); 33 OnLineBegin(int32_t cpixel,void * ptypeBuffer,int32_t pixelStride)34 void OnLineBegin(int32_t cpixel, void* ptypeBuffer, int32_t pixelStride) 35 { 36 _processLine->NewLineRequested(ptypeBuffer, cpixel, pixelStride); 37 } 38 OnLineEnd(int32_t,void *,int32_t)39 void OnLineEnd(int32_t /*cpixel*/, void* /*ptypeBuffer*/, int32_t /*pixelStride*/) { } 40 41 virtual void SetPresets(const JlsCustomParameters& presets) = 0; 42 43 virtual std::size_t EncodeScan(std::unique_ptr<ProcessLine> rawData, ByteStreamInfo& compressedData, void* pvoidCompare) = 0; 44 45 virtual ProcessLine* CreateProcess(ByteStreamInfo rawStreamInfo) = 0; 46 47 protected: 48 Init(ByteStreamInfo & compressedStream)49 void Init(ByteStreamInfo& compressedStream) 50 { 51 _freeBitCount = sizeof(_bitBuffer) * 8; 52 _bitBuffer = 0; 53 54 if (compressedStream.rawStream) 55 { 56 _compressedStream = compressedStream.rawStream; 57 _buffer.resize(4000); 58 _position = static_cast<uint8_t*>(&_buffer[0]); 59 _compressedLength = _buffer.size(); 60 } 61 else 62 { 63 _position = compressedStream.rawData; 64 _compressedLength = compressedStream.count; 65 } 66 } 67 AppendToBitStream(int32_t bits,int32_t bitCount)68 void AppendToBitStream(int32_t bits, int32_t bitCount) 69 { 70 ASSERT(bitCount < 32 && bitCount >= 0); 71 ASSERT((!_qdecoder) || (bitCount == 0 && bits == 0) ||( _qdecoder->ReadLongValue(bitCount) == bits)); 72 #ifndef NDEBUG 73 int mask = (1u << (bitCount)) - 1; 74 ASSERT((bits | mask) == mask); // Not used bits must be set to zero. 75 #endif 76 77 _freeBitCount -= bitCount; 78 if (_freeBitCount >= 0) 79 { 80 _bitBuffer |= bits << _freeBitCount; 81 } 82 else 83 { 84 // Add as much bits in the remaining space as possible and flush. 85 _bitBuffer |= bits >> -_freeBitCount; 86 Flush(); 87 88 // A second flush may be required if extra marker detect bits were needed and not all bits could be written. 89 if (_freeBitCount < 0) 90 { 91 _bitBuffer |= bits >> -_freeBitCount; 92 Flush(); 93 } 94 95 ASSERT(_freeBitCount >= 0); 96 _bitBuffer |= bits << _freeBitCount; 97 } 98 } 99 EndScan()100 void EndScan() 101 { 102 Flush(); 103 104 // if a 0xff was written, Flush() will force one unset bit anyway 105 if (_isFFWritten) 106 AppendToBitStream(0, (_freeBitCount - 1) % 8); 107 else 108 AppendToBitStream(0, _freeBitCount % 8); 109 110 Flush(); 111 ASSERT(_freeBitCount == 0x20); 112 113 if (_compressedStream) 114 { 115 OverFlow(); 116 } 117 } 118 OverFlow()119 void OverFlow() 120 { 121 if (!_compressedStream) 122 throw std::system_error(static_cast<int>(charls::ApiResult::CompressedBufferTooSmall), CharLSCategoryInstance()); 123 124 std::size_t bytesCount = _position - static_cast<uint8_t*>(&_buffer[0]); 125 std::size_t bytesWritten = static_cast<std::size_t>(_compressedStream->sputn(reinterpret_cast<char*>(&_buffer[0]), _position - static_cast<uint8_t*>(&_buffer[0]))); 126 127 if (bytesWritten != bytesCount) 128 throw std::system_error(static_cast<int>(charls::ApiResult::CompressedBufferTooSmall), CharLSCategoryInstance()); 129 130 _position = static_cast<uint8_t*>(&_buffer[0]); 131 _compressedLength = _buffer.size(); 132 } 133 Flush()134 void Flush() 135 { 136 if (_compressedLength < 4) 137 { 138 OverFlow(); 139 } 140 141 for (int i = 0; i < 4; ++i) 142 { 143 if (_freeBitCount >= 32) 144 break; 145 146 if (_isFFWritten) 147 { 148 // JPEG-LS requirement (T.87, A.1) to detect markers: after a xFF value a single 0 bit needs to be inserted. 149 *_position = static_cast<uint8_t>(_bitBuffer >> 25); 150 _bitBuffer = _bitBuffer << 7; 151 _freeBitCount += 7; 152 } 153 else 154 { 155 *_position = static_cast<uint8_t>(_bitBuffer >> 24); 156 _bitBuffer = _bitBuffer << 8; 157 _freeBitCount += 8; 158 } 159 160 _isFFWritten = *_position == 0xFF; 161 _position++; 162 _compressedLength--; 163 _bytesWritten++; 164 } 165 } 166 GetLength()167 std::size_t GetLength() const 168 { 169 return _bytesWritten - (_freeBitCount - 32) / 8; 170 } 171 AppendOnesToBitStream(int32_t length)172 inlinehint void AppendOnesToBitStream(int32_t length) 173 { 174 AppendToBitStream((1 << length) - 1, length); 175 } 176 177 std::unique_ptr<DecoderStrategy> _qdecoder; 178 179 protected: 180 JlsParameters _params; 181 std::unique_ptr<ProcessLine> _processLine; 182 183 private: 184 unsigned int _bitBuffer; 185 int32_t _freeBitCount; 186 std::size_t _compressedLength; 187 188 // encoding 189 uint8_t* _position; 190 bool _isFFWritten; 191 std::size_t _bytesWritten; 192 193 std::vector<uint8_t> _buffer; 194 std::basic_streambuf<char>* _compressedStream; 195 }; 196 197 #endif 198