// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_ENCODERSTRATEGY #define CHARLS_ENCODERSTRATEGY #include "processline.h" #include "decoderstrategy.h" // Purpose: Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy class EncoderStrategy { public: explicit EncoderStrategy(const JlsParameters& params) : _params(params), _bitBuffer(0), _freeBitCount(sizeof(_bitBuffer) * 8), _compressedLength(0), _position(nullptr), _isFFWritten(false), _bytesWritten(0), _compressedStream(nullptr) { } virtual ~EncoderStrategy() = default; int32_t PeekByte(); void OnLineBegin(int32_t cpixel, void* ptypeBuffer, int32_t pixelStride) { _processLine->NewLineRequested(ptypeBuffer, cpixel, pixelStride); } void OnLineEnd(int32_t /*cpixel*/, void* /*ptypeBuffer*/, int32_t /*pixelStride*/) { } virtual void SetPresets(const JlsCustomParameters& presets) = 0; virtual std::size_t EncodeScan(std::unique_ptr rawData, ByteStreamInfo& compressedData, void* pvoidCompare) = 0; virtual ProcessLine* CreateProcess(ByteStreamInfo rawStreamInfo) = 0; protected: void Init(ByteStreamInfo& compressedStream) { _freeBitCount = sizeof(_bitBuffer) * 8; _bitBuffer = 0; if (compressedStream.rawStream) { _compressedStream = compressedStream.rawStream; _buffer.resize(4000); _position = static_cast(&_buffer[0]); _compressedLength = _buffer.size(); } else { _position = compressedStream.rawData; _compressedLength = compressedStream.count; } } void AppendToBitStream(int32_t bits, int32_t bitCount) { ASSERT(bitCount < 32 && bitCount >= 0); ASSERT((!_qdecoder) || (bitCount == 0 && bits == 0) ||( _qdecoder->ReadLongValue(bitCount) == bits)); #ifndef NDEBUG int mask = (1u << (bitCount)) - 1; ASSERT((bits | mask) == mask); // Not used bits must be set to zero. #endif _freeBitCount -= bitCount; if (_freeBitCount >= 0) { _bitBuffer |= bits << _freeBitCount; } else { // Add as much bits in the remaining space as possible and flush. _bitBuffer |= bits >> -_freeBitCount; Flush(); // A second flush may be required if extra marker detect bits were needed and not all bits could be written. if (_freeBitCount < 0) { _bitBuffer |= bits >> -_freeBitCount; Flush(); } ASSERT(_freeBitCount >= 0); _bitBuffer |= bits << _freeBitCount; } } void EndScan() { Flush(); // if a 0xff was written, Flush() will force one unset bit anyway if (_isFFWritten) AppendToBitStream(0, (_freeBitCount - 1) % 8); else AppendToBitStream(0, _freeBitCount % 8); Flush(); ASSERT(_freeBitCount == 0x20); if (_compressedStream) { OverFlow(); } } void OverFlow() { if (!_compressedStream) throw std::system_error(static_cast(charls::ApiResult::CompressedBufferTooSmall), CharLSCategoryInstance()); std::size_t bytesCount = _position - static_cast(&_buffer[0]); std::size_t bytesWritten = static_cast(_compressedStream->sputn(reinterpret_cast(&_buffer[0]), _position - static_cast(&_buffer[0]))); if (bytesWritten != bytesCount) throw std::system_error(static_cast(charls::ApiResult::CompressedBufferTooSmall), CharLSCategoryInstance()); _position = static_cast(&_buffer[0]); _compressedLength = _buffer.size(); } void Flush() { if (_compressedLength < 4) { OverFlow(); } for (int i = 0; i < 4; ++i) { if (_freeBitCount >= 32) break; if (_isFFWritten) { // JPEG-LS requirement (T.87, A.1) to detect markers: after a xFF value a single 0 bit needs to be inserted. *_position = static_cast(_bitBuffer >> 25); _bitBuffer = _bitBuffer << 7; _freeBitCount += 7; } else { *_position = static_cast(_bitBuffer >> 24); _bitBuffer = _bitBuffer << 8; _freeBitCount += 8; } _isFFWritten = *_position == 0xFF; _position++; _compressedLength--; _bytesWritten++; } } std::size_t GetLength() const { return _bytesWritten - (_freeBitCount - 32) / 8; } inlinehint void AppendOnesToBitStream(int32_t length) { AppendToBitStream((1 << length) - 1, length); } std::unique_ptr _qdecoder; protected: JlsParameters _params; std::unique_ptr _processLine; private: unsigned int _bitBuffer; int32_t _freeBitCount; std::size_t _compressedLength; // encoding uint8_t* _position; bool _isFFWritten; std::size_t _bytesWritten; std::vector _buffer; std::basic_streambuf* _compressedStream; }; #endif