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