/src/brunsli/c/dec/jpeg_data_writer.cc
Line | Count | Source |
1 | | // Copyright (c) Google LLC 2019 |
2 | | // |
3 | | // Use of this source code is governed by an MIT-style |
4 | | // license that can be found in the LICENSE file or at |
5 | | // https://opensource.org/licenses/MIT. |
6 | | |
7 | | #include <brunsli/jpeg_data_writer.h> |
8 | | |
9 | | #include <cstddef> |
10 | | #include <cstdlib> |
11 | | #include <cstring> /* for memset, memcpy */ |
12 | | #include <deque> |
13 | | #include <string> |
14 | | #include <vector> |
15 | | |
16 | | #include "../common/constants.h" |
17 | | #include <brunsli/jpeg_data.h> |
18 | | #include "../common/platform.h" |
19 | | #include <brunsli/types.h> |
20 | | #include "./serialization_state.h" |
21 | | #include "./state.h" |
22 | | #include "./state_internal.h" |
23 | | |
24 | | namespace brunsli { |
25 | | |
26 | | using ::brunsli::internal::dec::BitWriter; |
27 | | using ::brunsli::internal::dec::DCTCodingState; |
28 | | using ::brunsli::internal::dec::EncodeScanState; |
29 | | using ::brunsli::internal::dec::OutputChunk; |
30 | | using ::brunsli::internal::dec::SerializationState; |
31 | | using ::brunsli::internal::dec::SerializationStatus; |
32 | | using ::brunsli::internal::dec::SerializeJpeg; |
33 | | using ::brunsli::internal::dec::Stage; |
34 | | using ::brunsli::internal::dec::State; |
35 | | |
36 | | namespace { |
37 | | |
38 | | const int kJpegPrecision = 8; |
39 | | |
40 | | // BitWriter: buffer size |
41 | | const size_t kBitWriterChunkSize = 16384; |
42 | | |
43 | | // Returns ceil(a/b). |
44 | 19.5k | static BRUNSLI_INLINE int DivCeil(int a, int b) { return (a + b - 1) / b; } |
45 | | |
46 | | // Returns non-zero if and only if x has a zero byte, i.e. one of |
47 | | // x & 0xff, x & 0xff00, ..., x & 0xff00000000000000 is zero. |
48 | 4.04M | static BRUNSLI_INLINE uint64_t HasZeroByte(uint64_t x) { |
49 | 4.04M | return (x - 0x0101010101010101ULL) & ~x & 0x8080808080808080ULL; |
50 | 4.04M | } |
51 | | |
52 | 9.77k | void BitWriterInit(BitWriter* bw, std::deque<OutputChunk>* output_queue) { |
53 | 9.77k | bw->output = output_queue; |
54 | 9.77k | bw->chunk = OutputChunk(kBitWriterChunkSize); |
55 | 9.77k | bw->pos = 0; |
56 | 9.77k | bw->put_buffer = 0; |
57 | 9.77k | bw->put_bits = 64; |
58 | 9.77k | bw->healthy = true; |
59 | 9.77k | bw->data = bw->chunk.buffer->data(); |
60 | 9.77k | } |
61 | | |
62 | 1.47k | static BRUNSLI_NOINLINE void SwapBuffer(BitWriter* bw) { |
63 | 1.47k | bw->chunk.len = bw->pos; |
64 | 1.47k | bw->output->emplace_back(std::move(bw->chunk)); |
65 | 1.47k | bw->chunk = OutputChunk(kBitWriterChunkSize); |
66 | 1.47k | bw->data = bw->chunk.buffer->data(); |
67 | 1.47k | bw->pos = 0; |
68 | 1.47k | } |
69 | | |
70 | 5.07M | static BRUNSLI_INLINE void Reserve(BitWriter* bw, size_t n_bytes) { |
71 | 5.07M | if (BRUNSLI_PREDICT_FALSE((bw->pos + n_bytes) > kBitWriterChunkSize)) { |
72 | 1.47k | SwapBuffer(bw); |
73 | 1.47k | } |
74 | 5.07M | } |
75 | | |
76 | | /** |
77 | | * Writes the given byte to the output, writes an extra zero if byte is 0xFF. |
78 | | * |
79 | | * This method is "careless" - caller must make sure that there is enough |
80 | | * space in the output buffer. Emits up to 2 bytes to buffer. |
81 | | */ |
82 | 9.88M | static BRUNSLI_INLINE void EmitByte(BitWriter* bw, int byte) { |
83 | 9.88M | bw->data[bw->pos++] = byte; |
84 | 9.88M | if (byte == 0xFF) bw->data[bw->pos++] = 0; |
85 | 9.88M | } |
86 | | |
87 | 4.04M | static BRUNSLI_INLINE void DischargeBitBuffer(BitWriter* bw) { |
88 | | // At this point we are ready to emit the most significant 6 bytes of |
89 | | // put_buffer_ to the output. |
90 | | // The JPEG format requires that after every 0xff byte in the entropy |
91 | | // coded section, there is a zero byte, therefore we first check if any of |
92 | | // the 6 most significant bytes of put_buffer_ is 0xFF. |
93 | 4.04M | Reserve(bw, 12); |
94 | 4.04M | if (HasZeroByte(~bw->put_buffer | 0xFFFF)) { |
95 | | // We have a 0xFF byte somewhere, examine each byte and append a zero |
96 | | // byte if necessary. |
97 | 1.45M | EmitByte(bw, (bw->put_buffer >> 56) & 0xFF); |
98 | 1.45M | EmitByte(bw, (bw->put_buffer >> 48) & 0xFF); |
99 | 1.45M | EmitByte(bw, (bw->put_buffer >> 40) & 0xFF); |
100 | 1.45M | EmitByte(bw, (bw->put_buffer >> 32) & 0xFF); |
101 | 1.45M | EmitByte(bw, (bw->put_buffer >> 24) & 0xFF); |
102 | 1.45M | EmitByte(bw, (bw->put_buffer >> 16) & 0xFF); |
103 | 2.58M | } else { |
104 | | // We don't have any 0xFF bytes, output all 6 bytes without checking. |
105 | 2.58M | bw->data[bw->pos] = (bw->put_buffer >> 56) & 0xFF; |
106 | 2.58M | bw->data[bw->pos + 1] = (bw->put_buffer >> 48) & 0xFF; |
107 | 2.58M | bw->data[bw->pos + 2] = (bw->put_buffer >> 40) & 0xFF; |
108 | 2.58M | bw->data[bw->pos + 3] = (bw->put_buffer >> 32) & 0xFF; |
109 | 2.58M | bw->data[bw->pos + 4] = (bw->put_buffer >> 24) & 0xFF; |
110 | 2.58M | bw->data[bw->pos + 5] = (bw->put_buffer >> 16) & 0xFF; |
111 | 2.58M | bw->pos += 6; |
112 | 2.58M | } |
113 | 4.04M | bw->put_buffer <<= 48; |
114 | 4.04M | bw->put_bits += 48; |
115 | 4.04M | } |
116 | | |
117 | 50.4M | static BRUNSLI_INLINE void WriteBits(BitWriter* bw, int nbits, uint64_t bits) { |
118 | | // This is an optimization; if everything goes well, |
119 | | // then |nbits| is positive; if non-existing Huffman symbol is going to be |
120 | | // encoded, its length should be zero; later encoder could check the |
121 | | // "health" of BitWriter. |
122 | 50.4M | if (nbits == 0) { |
123 | 7.87M | bw->healthy = false; |
124 | 7.87M | return; |
125 | 7.87M | } |
126 | 42.5M | bw->put_bits -= nbits; |
127 | 42.5M | bw->put_buffer |= (bits << bw->put_bits); |
128 | 42.5M | if (bw->put_bits <= 16) DischargeBitBuffer(bw); |
129 | 42.5M | } |
130 | | |
131 | 512k | void EmitMarker(BitWriter* bw, int marker) { |
132 | 512k | Reserve(bw, 2); |
133 | 512k | BRUNSLI_DCHECK(marker != 0xFF); |
134 | 512k | bw->data[bw->pos++] = 0xFF; |
135 | 512k | bw->data[bw->pos++] = marker; |
136 | 512k | } |
137 | | |
138 | | bool JumpToByteBoundary(BitWriter* bw, const int** pad_bits, |
139 | 522k | const int* pad_bits_end) { |
140 | 522k | size_t n_bits = bw->put_bits & 7u; |
141 | 522k | uint8_t pad_pattern; |
142 | 522k | if (*pad_bits == nullptr) { |
143 | 518k | pad_pattern = (1u << n_bits) - 1; |
144 | 518k | } else { |
145 | 4.12k | pad_pattern = 0; |
146 | 4.12k | const int* src = *pad_bits; |
147 | | // TODO(eustas): bitwise reading looks insanely ineffective... |
148 | 10.8k | while (n_bits--) { |
149 | 6.88k | pad_pattern <<= 1; |
150 | 6.88k | if (src >= pad_bits_end) return false; |
151 | | // TODO(eustas): DCHECK *src == {0, 1} |
152 | 6.76k | pad_pattern |= !!*(src++); |
153 | 6.76k | } |
154 | 4.01k | *pad_bits = src; |
155 | 4.01k | } |
156 | | |
157 | 522k | Reserve(bw, 16); |
158 | | |
159 | 1.28M | while (bw->put_bits <= 56) { |
160 | 765k | int c = (bw->put_buffer >> 56) & 0xFF; |
161 | 765k | EmitByte(bw, c); |
162 | 765k | bw->put_buffer <<= 8; |
163 | 765k | bw->put_bits += 8; |
164 | 765k | } |
165 | 522k | if (bw->put_bits < 64) { |
166 | 387k | int pad_mask = 0xFFu >> (64 - bw->put_bits); |
167 | 387k | int c = ((bw->put_buffer >> 56) & ~pad_mask) | pad_pattern; |
168 | 387k | EmitByte(bw, c); |
169 | 387k | } |
170 | 522k | bw->put_buffer = 0; |
171 | 522k | bw->put_bits = 64; |
172 | | |
173 | 522k | return true; |
174 | 522k | } |
175 | | |
176 | 9.65k | void BitWriterFinish(BitWriter* bw) { |
177 | 9.65k | if (bw->pos == 0) return; |
178 | 9.20k | bw->chunk.len = bw->pos; |
179 | 9.20k | bw->output->emplace_back(std::move(bw->chunk)); |
180 | 9.20k | bw->chunk = OutputChunk(nullptr, 0); |
181 | 9.20k | bw->data = nullptr; |
182 | 9.20k | bw->pos = 0; |
183 | 9.20k | } |
184 | | |
185 | 9.77k | void DCTCodingStateInit(DCTCodingState* s) { |
186 | 9.77k | s->eob_run_ = 0; |
187 | 9.77k | s->cur_ac_huff_ = nullptr; |
188 | 9.77k | s->refinement_bits_.clear(); |
189 | 9.77k | s->refinement_bits_.reserve(64); // 1024 bits most often is more than enough. |
190 | 9.77k | s->refinement_bits_count_ = 0; |
191 | 9.77k | } |
192 | | |
193 | | // Emit all buffered data to the bit stream using the given Huffman code and |
194 | | // bit writer. |
195 | 13.9M | static BRUNSLI_INLINE void Flush(DCTCodingState* s, BitWriter* bw) { |
196 | 13.9M | if (s->eob_run_ > 0) { |
197 | 13.3M | int nbits = Log2FloorNonZero(s->eob_run_); |
198 | 13.3M | int symbol = nbits << 4u; |
199 | 13.3M | WriteBits(bw, s->cur_ac_huff_->depth[symbol], |
200 | 13.3M | s->cur_ac_huff_->code[symbol]); |
201 | 13.3M | if (nbits > 0) { |
202 | 63.5k | WriteBits(bw, nbits, s->eob_run_ & ((1 << nbits) - 1)); |
203 | 63.5k | } |
204 | 13.3M | s->eob_run_ = 0; |
205 | 13.3M | } |
206 | 13.9M | size_t num_words = s->refinement_bits_count_ >> 4; |
207 | 14.0M | for (size_t i = 0; i < num_words; ++i) { |
208 | 51.5k | WriteBits(bw, 16, s->refinement_bits_[i]); |
209 | 51.5k | } |
210 | 13.9M | size_t tail = s->refinement_bits_count_ & 0xF; |
211 | 13.9M | if (tail) { |
212 | 61.5k | WriteBits(bw, tail, s->refinement_bits_.back()); |
213 | 61.5k | } |
214 | 13.9M | s->refinement_bits_.clear(); |
215 | 13.9M | s->refinement_bits_count_ = 0; |
216 | 13.9M | } |
217 | | |
218 | | // Buffer some more data at the end-of-band (the last non-zero or newly |
219 | | // non-zero coefficient within the [Ss, Se] spectral band). |
220 | | static BRUNSLI_INLINE bool BufferEndOfBand(DCTCodingState* s, |
221 | | const HuffmanCodeTable* ac_huff, |
222 | | const int* new_bits_array, |
223 | | size_t new_bits_count, |
224 | 69.8M | BitWriter* bw) { |
225 | 69.8M | if (s->eob_run_ == 0) { |
226 | 13.3M | s->cur_ac_huff_ = ac_huff; |
227 | 13.3M | } |
228 | 69.8M | ++s->eob_run_; |
229 | 69.8M | if (new_bits_count) { |
230 | 260k | uint64_t new_bits = 0; |
231 | 1.37M | for (size_t i = 0; i < new_bits_count; ++i) { |
232 | 1.11M | new_bits = (new_bits << 1) | new_bits_array[i]; |
233 | 1.11M | } |
234 | 260k | size_t tail = s->refinement_bits_count_ & 0xF; |
235 | 260k | if (tail) { // First stuff the tail item |
236 | 188k | size_t stuff_bits_count = std::min(16 - tail, new_bits_count); |
237 | 188k | uint16_t stuff_bits = new_bits >> (new_bits_count - stuff_bits_count); |
238 | 188k | stuff_bits &= ((1u << stuff_bits_count) - 1); |
239 | 188k | s->refinement_bits_.back() = |
240 | 188k | (s->refinement_bits_.back() << stuff_bits_count) | stuff_bits; |
241 | 188k | new_bits_count -= stuff_bits_count; |
242 | 188k | s->refinement_bits_count_ += stuff_bits_count; |
243 | 188k | } |
244 | 281k | while (new_bits_count >= 16) { |
245 | 20.7k | s->refinement_bits_.push_back(new_bits >> (new_bits_count - 16)); |
246 | 20.7k | new_bits_count -= 16; |
247 | 20.7k | s->refinement_bits_count_ += 16; |
248 | 20.7k | } |
249 | 260k | if (new_bits_count) { |
250 | 92.4k | s->refinement_bits_.push_back(new_bits & ((1u << new_bits_count) - 1)); |
251 | 92.4k | s->refinement_bits_count_ += new_bits_count; |
252 | 92.4k | } |
253 | 260k | } |
254 | | // At most we buffer at most ~258041 bytes; that is less than we have reserved |
255 | | // before; still, let's make sure we don't use more memory ever. |
256 | 69.8M | if (s->refinement_bits_count_ > 0x7FFF * (kDCTBlockSize - 1)) { |
257 | 0 | return false; |
258 | 0 | } |
259 | 69.8M | if (s->eob_run_ == 0x7FFF) { |
260 | 1.41k | Flush(s, bw); |
261 | 1.41k | } |
262 | 69.8M | return true; |
263 | 69.8M | } |
264 | | |
265 | | bool BuildHuffmanCodeTable(const JPEGHuffmanCode& huff, |
266 | 24.4k | HuffmanCodeTable* table) { |
267 | 24.4k | int huff_code[kJpegHuffmanAlphabetSize]; |
268 | | // +1 for a sentinel element. |
269 | 24.4k | uint32_t huff_size[kJpegHuffmanAlphabetSize + 1]; |
270 | 24.4k | int p = 0; |
271 | 415k | for (size_t l = 1; l <= kJpegHuffmanMaxBitLength; ++l) { |
272 | 390k | int i = huff.counts[l]; |
273 | 390k | if (p + i > kJpegHuffmanAlphabetSize + 1) { |
274 | 0 | return false; |
275 | 0 | } |
276 | 2.19M | while (i--) huff_size[p++] = static_cast<uint32_t>(l); |
277 | 390k | } |
278 | | |
279 | 24.4k | if (p == 0) { |
280 | 0 | return true; |
281 | 0 | } |
282 | | |
283 | | // Reuse sentinel element. |
284 | 24.4k | int last_p = p - 1; |
285 | 24.4k | huff_size[last_p] = 0; |
286 | | |
287 | 24.4k | int code = 0; |
288 | 24.4k | uint32_t si = huff_size[0]; |
289 | 24.4k | p = 0; |
290 | 244k | while (huff_size[p]) { |
291 | 1.99M | while ((huff_size[p]) == si) { |
292 | 1.77M | huff_code[p++] = code; |
293 | 1.77M | code++; |
294 | 1.77M | } |
295 | 220k | code <<= 1; |
296 | 220k | si++; |
297 | 220k | } |
298 | 1.80M | for (p = 0; p < last_p; p++) { |
299 | 1.77M | int i = huff.values[p]; |
300 | 1.77M | table->depth[i] = huff_size[p]; |
301 | 1.77M | table->code[i] = huff_code[p]; |
302 | 1.77M | } |
303 | 24.4k | return true; |
304 | 24.4k | } |
305 | | |
306 | 9.24k | bool EncodeSOI(SerializationState* state) { |
307 | 9.24k | state->output_queue.push_back(OutputChunk({0xFF, 0xD8})); |
308 | 9.24k | return true; |
309 | 9.24k | } |
310 | | |
311 | 754 | bool EncodeEOI(const JPEGData& jpg, SerializationState* state) { |
312 | 754 | state->output_queue.push_back(OutputChunk({0xFF, 0xD9})); |
313 | 754 | state->output_queue.emplace_back(jpg.tail_data); |
314 | 754 | return true; |
315 | 754 | } |
316 | | |
317 | 25.3k | bool EncodeSOF(const JPEGData& jpg, uint8_t marker, SerializationState* state) { |
318 | 25.3k | if (marker <= 0xC2) state->is_progressive = (marker == 0xC2); |
319 | | |
320 | 25.3k | const size_t n_comps = jpg.components.size(); |
321 | 25.3k | const size_t marker_len = 8 + 3 * n_comps; |
322 | 25.3k | state->output_queue.emplace_back(marker_len + 2); |
323 | 25.3k | uint8_t* data = state->output_queue.back().buffer->data(); |
324 | 25.3k | size_t pos = 0; |
325 | 25.3k | data[pos++] = 0xFFu; |
326 | 25.3k | data[pos++] = marker; |
327 | 25.3k | data[pos++] = static_cast<uint8_t>(marker_len >> 8u); |
328 | 25.3k | data[pos++] = static_cast<uint8_t>(marker_len); |
329 | 25.3k | data[pos++] = kJpegPrecision; |
330 | 25.3k | data[pos++] = jpg.height >> 8u; |
331 | 25.3k | data[pos++] = jpg.height & 0xFFu; |
332 | 25.3k | data[pos++] = jpg.width >> 8u; |
333 | 25.3k | data[pos++] = jpg.width & 0xFFu; |
334 | 25.3k | data[pos++] = static_cast<uint8_t>(n_comps); |
335 | 51.1k | for (size_t i = 0; i < n_comps; ++i) { |
336 | 25.7k | data[pos++] = jpg.components[i].id; |
337 | 25.7k | data[pos++] = ((jpg.components[i].h_samp_factor << 4u) | |
338 | 25.7k | (jpg.components[i].v_samp_factor)); |
339 | 25.7k | const size_t quant_idx = jpg.components[i].quant_idx; |
340 | 25.7k | if (quant_idx >= jpg.quant.size()) return false; |
341 | 25.7k | data[pos++] = jpg.quant[quant_idx].index; |
342 | 25.7k | } |
343 | 25.3k | return true; |
344 | 25.3k | } |
345 | | |
346 | | bool EncodeSOS(const JPEGData& jpg, const JPEGScanInfo& scan_info, |
347 | 10.0k | SerializationState* state) { |
348 | 10.0k | const size_t n_scans = scan_info.num_components; |
349 | 10.0k | const size_t marker_len = 6 + 2 * n_scans; |
350 | 10.0k | state->output_queue.emplace_back(marker_len + 2); |
351 | 10.0k | uint8_t* data = state->output_queue.back().buffer->data(); |
352 | 10.0k | size_t pos = 0; |
353 | 10.0k | data[pos++] = 0xFFu; |
354 | 10.0k | data[pos++] = 0xDAu; |
355 | 10.0k | data[pos++] = static_cast<uint8_t>(marker_len >> 8u); |
356 | 10.0k | data[pos++] = static_cast<uint8_t>(marker_len); |
357 | 10.0k | data[pos++] = static_cast<uint8_t>(n_scans); |
358 | 35.1k | for (size_t i = 0; i < n_scans; ++i) { |
359 | 25.4k | const JPEGComponentScanInfo& si = scan_info.components[i]; |
360 | 25.4k | if (si.comp_idx >= jpg.components.size()) return false; |
361 | 25.1k | data[pos++] = jpg.components[si.comp_idx].id; |
362 | 25.1k | data[pos++] = (si.dc_tbl_idx << 4u) + si.ac_tbl_idx; |
363 | 25.1k | } |
364 | 9.77k | data[pos++] = scan_info.Ss; |
365 | 9.77k | data[pos++] = scan_info.Se; |
366 | 9.77k | data[pos++] = ((scan_info.Ah << 4u) | (scan_info.Al)); |
367 | 9.77k | return true; |
368 | 10.0k | } |
369 | | |
370 | 9.47k | bool EncodeDHT(const JPEGData& jpg, SerializationState* state) { |
371 | 9.47k | const std::vector<JPEGHuffmanCode>& huffman_code = jpg.huffman_code; |
372 | | |
373 | 9.47k | size_t marker_len = 2; |
374 | 24.4k | for (size_t i = state->dht_index; i < huffman_code.size(); ++i) { |
375 | 24.4k | const JPEGHuffmanCode& huff = huffman_code[i]; |
376 | 24.4k | marker_len += kJpegHuffmanMaxBitLength; |
377 | 439k | for (size_t j = 0; j < huff.counts.size(); ++j) { |
378 | 415k | marker_len += huff.counts[j]; |
379 | 415k | } |
380 | 24.4k | if (huff.is_last) break; |
381 | 24.4k | } |
382 | 9.47k | state->output_queue.emplace_back(marker_len + 2); |
383 | 9.47k | uint8_t* data = state->output_queue.back().buffer->data(); |
384 | 9.47k | size_t pos = 0; |
385 | 9.47k | data[pos++] = 0xFFu; |
386 | 9.47k | data[pos++] = 0xC4u; |
387 | 9.47k | data[pos++] = static_cast<uint8_t>(marker_len >> 8u); |
388 | 9.47k | data[pos++] = static_cast<uint8_t>(marker_len); |
389 | 24.4k | while (true) { |
390 | 24.4k | const size_t huffman_code_index = state->dht_index++; |
391 | 24.4k | if (huffman_code_index >= huffman_code.size()) { |
392 | 0 | return false; |
393 | 0 | } |
394 | 24.4k | const JPEGHuffmanCode& huff = huffman_code[huffman_code_index]; |
395 | 24.4k | size_t index = huff.slot_id; |
396 | 24.4k | HuffmanCodeTable* huff_table; |
397 | 24.4k | if (index & 0x10) { |
398 | 13.5k | index -= 0x10; |
399 | 13.5k | huff_table = &state->ac_huff_table[index]; |
400 | 13.5k | } else { |
401 | 10.8k | huff_table = &state->dc_huff_table[index]; |
402 | 10.8k | } |
403 | | // TODO(eustas): cache |
404 | | // TODO(eustas): set up non-existing symbols |
405 | 24.4k | if (!BuildHuffmanCodeTable(huff, huff_table)) { |
406 | 0 | return false; |
407 | 0 | } |
408 | 24.4k | size_t total_count = 0; |
409 | 24.4k | size_t max_length = 0; |
410 | 439k | for (size_t i = 0; i < huff.counts.size(); ++i) { |
411 | 415k | if (huff.counts[i] != 0) { |
412 | 203k | max_length = i; |
413 | 203k | } |
414 | 415k | total_count += huff.counts[i]; |
415 | 415k | } |
416 | 24.4k | --total_count; |
417 | 24.4k | data[pos++] = huff.slot_id; |
418 | 415k | for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) { |
419 | 390k | data[pos++] = (i == max_length ? huff.counts[i] - 1 : huff.counts[i]); |
420 | 390k | } |
421 | 1.80M | for (size_t i = 0; i < total_count; ++i) { |
422 | 1.77M | data[pos++] = huff.values[i]; |
423 | 1.77M | } |
424 | 24.4k | if (huff.is_last) break; |
425 | 24.4k | } |
426 | 9.47k | return true; |
427 | 9.47k | } |
428 | | |
429 | 745 | bool EncodeDQT(const JPEGData& jpg, SerializationState* state) { |
430 | 745 | int marker_len = 2; |
431 | 745 | for (size_t i = state->dqt_index; i < jpg.quant.size(); ++i) { |
432 | 723 | const JPEGQuantTable& table = jpg.quant[i]; |
433 | 723 | marker_len += 1 + (table.precision ? 2 : 1) * kDCTBlockSize; |
434 | 723 | if (table.is_last) break; |
435 | 723 | } |
436 | 745 | state->output_queue.emplace_back(marker_len + 2); |
437 | 745 | uint8_t* data = state->output_queue.back().buffer->data(); |
438 | 745 | size_t pos = 0; |
439 | 745 | data[pos++] = 0xFF; |
440 | 745 | data[pos++] = 0xDB; |
441 | 745 | data[pos++] = marker_len >> 8u; |
442 | 745 | data[pos++] = marker_len & 0xFFu; |
443 | 745 | while (true) { |
444 | 745 | const size_t idx = state->dqt_index++; |
445 | 745 | if (idx >= jpg.quant.size()) { |
446 | 22 | return false; // corrupt input |
447 | 22 | } |
448 | 723 | const JPEGQuantTable& table = jpg.quant[idx]; |
449 | 723 | data[pos++] = (table.precision << 4u) + table.index; |
450 | 46.9k | for (size_t i = 0; i < kDCTBlockSize; ++i) { |
451 | 46.2k | int val_idx = kJPEGNaturalOrder[i]; |
452 | 46.2k | int val = table.values[val_idx]; |
453 | 46.2k | if (table.precision) { |
454 | 12.3k | data[pos++] = val >> 8u; |
455 | 12.3k | } |
456 | 46.2k | data[pos++] = val & 0xFFu; |
457 | 46.2k | } |
458 | 723 | if (table.is_last) break; |
459 | 723 | } |
460 | 723 | return true; |
461 | 745 | } |
462 | | |
463 | 3.67k | bool EncodeDRI(const JPEGData& jpg, SerializationState* state) { |
464 | 3.67k | state->seen_dri_marker = true; |
465 | 3.67k | OutputChunk dri_marker = {0xFF, |
466 | 3.67k | 0xDD, |
467 | 3.67k | 0, |
468 | 3.67k | 4, |
469 | 3.67k | static_cast<uint8_t>(jpg.restart_interval >> 8), |
470 | 3.67k | static_cast<uint8_t>(jpg.restart_interval & 0xFF)}; |
471 | 3.67k | state->output_queue.push_back(std::move(dri_marker)); |
472 | 3.67k | return true; |
473 | 3.67k | } |
474 | | |
475 | 17.7k | bool EncodeRestart(uint8_t marker, SerializationState* state) { |
476 | 17.7k | state->output_queue.push_back(OutputChunk({0xFF, marker})); |
477 | 17.7k | return true; |
478 | 17.7k | } |
479 | | |
480 | 453 | bool EncodeAPP(const JPEGData& jpg, uint8_t marker, SerializationState* state) { |
481 | | // TODO(eustas): check that marker corresponds to payload? |
482 | 453 | (void)marker; |
483 | | |
484 | 453 | size_t app_index = state->app_index++; |
485 | 453 | if (app_index >= jpg.app_data.size()) return false; |
486 | 37 | state->output_queue.push_back(OutputChunk({0xFF})); |
487 | 37 | state->output_queue.emplace_back(jpg.app_data[app_index]); |
488 | 37 | return true; |
489 | 453 | } |
490 | | |
491 | 13 | bool EncodeCOM(const JPEGData& jpg, SerializationState* state) { |
492 | 13 | size_t com_index = state->com_index++; |
493 | 13 | if (com_index >= jpg.com_data.size()) return false; |
494 | 0 | state->output_queue.push_back(OutputChunk({0xFF})); |
495 | 0 | state->output_queue.emplace_back(jpg.com_data[com_index]); |
496 | 0 | return true; |
497 | 13 | } |
498 | | |
499 | 53 | bool EncodeInterMarkerData(const JPEGData& jpg, SerializationState* state) { |
500 | 53 | size_t index = state->data_index++; |
501 | 53 | if (index >= jpg.inter_marker_data.size()) return false; |
502 | 53 | state->output_queue.emplace_back(jpg.inter_marker_data[index]); |
503 | 53 | return true; |
504 | 53 | } |
505 | | |
506 | | bool EncodeDCTBlockSequential(const coeff_t* coeffs, |
507 | | const HuffmanCodeTable& dc_huff, |
508 | | const HuffmanCodeTable& ac_huff, |
509 | | int num_zero_runs, coeff_t* last_dc_coeff, |
510 | 7.55M | BitWriter* bw) { |
511 | 7.55M | coeff_t temp2; |
512 | 7.55M | coeff_t temp; |
513 | 7.55M | temp2 = coeffs[0]; |
514 | 7.55M | temp = temp2 - *last_dc_coeff; |
515 | 7.55M | *last_dc_coeff = temp2; |
516 | 7.55M | temp2 = temp; |
517 | 7.55M | if (temp < 0) { |
518 | 1.91M | temp = -temp; |
519 | 1.91M | temp2--; |
520 | 1.91M | } |
521 | 7.55M | int dc_nbits = (temp == 0) ? 0 : (Log2FloorNonZero(temp) + 1); |
522 | 7.55M | WriteBits(bw, dc_huff.depth[dc_nbits], dc_huff.code[dc_nbits]); |
523 | 7.55M | if (dc_nbits > 0) { |
524 | 3.75M | WriteBits(bw, dc_nbits, temp2 & ((1u << dc_nbits) - 1)); |
525 | 3.75M | } |
526 | 7.55M | int r = 0; |
527 | 483M | for (int k = 1; k < 64; ++k) { |
528 | 476M | if ((temp = coeffs[kJPEGNaturalOrder[k]]) == 0) { |
529 | 476M | r++; |
530 | 476M | continue; |
531 | 476M | } |
532 | 71.5k | if (temp < 0) { |
533 | 45.7k | temp = -temp; |
534 | 45.7k | temp2 = ~temp; |
535 | 45.7k | } else { |
536 | 25.8k | temp2 = temp; |
537 | 25.8k | } |
538 | 123k | while (r > 15) { |
539 | 51.5k | WriteBits(bw, ac_huff.depth[0xf0], ac_huff.code[0xf0]); |
540 | 51.5k | r -= 16; |
541 | 51.5k | } |
542 | 71.5k | int ac_nbits = Log2FloorNonZero(temp) + 1; |
543 | 71.5k | int symbol = (r << 4u) + ac_nbits; |
544 | 71.5k | WriteBits(bw, ac_huff.depth[symbol], ac_huff.code[symbol]); |
545 | 71.5k | WriteBits(bw, ac_nbits, temp2 & ((1 << ac_nbits) - 1)); |
546 | 71.5k | r = 0; |
547 | 71.5k | } |
548 | 7.56M | for (int i = 0; i < num_zero_runs; ++i) { |
549 | 6.57k | WriteBits(bw, ac_huff.depth[0xf0], ac_huff.code[0xf0]); |
550 | 6.57k | r -= 16; |
551 | 6.57k | } |
552 | 7.55M | if (r > 0) { |
553 | 7.55M | WriteBits(bw, ac_huff.depth[0], ac_huff.code[0]); |
554 | 7.55M | } |
555 | 7.55M | return true; |
556 | 7.55M | } |
557 | | |
558 | | bool EncodeDCTBlockProgressive(const coeff_t* coeffs, |
559 | | const HuffmanCodeTable& dc_huff, |
560 | | const HuffmanCodeTable& ac_huff, int Ss, int Se, |
561 | | int Al, int num_zero_runs, |
562 | | DCTCodingState* coding_state, |
563 | 18.9M | coeff_t* last_dc_coeff, BitWriter* bw) { |
564 | 18.9M | bool eob_run_allowed = Ss > 0; |
565 | 18.9M | coeff_t temp2; |
566 | 18.9M | coeff_t temp; |
567 | 18.9M | if (Ss == 0) { |
568 | 6.63M | temp2 = coeffs[0] >> Al; |
569 | 6.63M | temp = temp2 - *last_dc_coeff; |
570 | 6.63M | *last_dc_coeff = temp2; |
571 | 6.63M | temp2 = temp; |
572 | 6.63M | if (temp < 0) { |
573 | 1.67M | temp = -temp; |
574 | 1.67M | temp2--; |
575 | 1.67M | } |
576 | 6.63M | int nbits = (temp == 0) ? 0 : (Log2FloorNonZero(temp) + 1); |
577 | 6.63M | WriteBits(bw, dc_huff.depth[nbits], dc_huff.code[nbits]); |
578 | 6.63M | if (nbits > 0) { |
579 | 3.37M | WriteBits(bw, nbits, temp2 & ((1 << nbits) - 1)); |
580 | 3.37M | } |
581 | 6.63M | ++Ss; |
582 | 6.63M | } |
583 | 18.9M | if (Ss > Se) { |
584 | 844k | return true; |
585 | 844k | } |
586 | 18.0M | int r = 0; |
587 | 494M | for (int k = Ss; k <= Se; ++k) { |
588 | 476M | if ((temp = coeffs[kJPEGNaturalOrder[k]]) == 0) { |
589 | 476M | r++; |
590 | 476M | continue; |
591 | 476M | } |
592 | 107k | if (temp < 0) { |
593 | 77.0k | temp = -temp; |
594 | 77.0k | temp >>= Al; |
595 | 77.0k | temp2 = ~temp; |
596 | 77.0k | } else { |
597 | 30.0k | temp >>= Al; |
598 | 30.0k | temp2 = temp; |
599 | 30.0k | } |
600 | 107k | if (temp == 0) { |
601 | 4.03k | r++; |
602 | 4.03k | continue; |
603 | 4.03k | } |
604 | 103k | Flush(coding_state, bw); |
605 | 170k | while (r > 15) { |
606 | 67.7k | WriteBits(bw, ac_huff.depth[0xf0], ac_huff.code[0xf0]); |
607 | 67.7k | r -= 16; |
608 | 67.7k | } |
609 | 103k | int nbits = Log2FloorNonZero(temp) + 1; |
610 | 103k | int symbol = (r << 4u) + nbits; |
611 | 103k | WriteBits(bw, ac_huff.depth[symbol], ac_huff.code[symbol]); |
612 | 103k | WriteBits(bw, nbits, temp2 & ((1 << nbits) - 1)); |
613 | 103k | r = 0; |
614 | 103k | } |
615 | 18.0M | if (num_zero_runs > 0) { |
616 | 8.73k | Flush(coding_state, bw); |
617 | 23.6k | for (int i = 0; i < num_zero_runs; ++i) { |
618 | 14.8k | WriteBits(bw, ac_huff.depth[0xf0], ac_huff.code[0xf0]); |
619 | 14.8k | r -= 16; |
620 | 14.8k | } |
621 | 8.73k | } |
622 | 18.0M | if (r > 0) { |
623 | | // Ignore result: since we do not buffer bits - it can not fail. |
624 | 18.0M | BufferEndOfBand(coding_state, &ac_huff, nullptr, 0, bw); |
625 | 18.0M | if (!eob_run_allowed) { |
626 | 6.18M | Flush(coding_state, bw); |
627 | 6.18M | } |
628 | 18.0M | } |
629 | 18.0M | return true; |
630 | 18.9M | } |
631 | | |
632 | | bool EncodeRefinementBits(const coeff_t* coeffs, |
633 | | const HuffmanCodeTable& ac_huff, int Ss, int Se, |
634 | 52.1M | int Al, DCTCodingState* coding_state, BitWriter* bw) { |
635 | 52.1M | bool eob_run_allowed = Ss > 0; |
636 | 52.1M | if (Ss == 0) { |
637 | | // Emit next bit of DC component. |
638 | 6.98M | WriteBits(bw, 1, (coeffs[0] >> Al) & 1); |
639 | 6.98M | ++Ss; |
640 | 6.98M | } |
641 | 52.1M | if (Ss > Se) { |
642 | 449k | return true; |
643 | 449k | } |
644 | 51.7M | int abs_values[kDCTBlockSize]; |
645 | 51.7M | int eob = 0; |
646 | 1.33G | for (int k = Ss; k <= Se; k++) { |
647 | 1.28G | const coeff_t abs_val = std::abs(coeffs[kJPEGNaturalOrder[k]]); |
648 | 1.28G | abs_values[k] = abs_val >> Al; |
649 | 1.28G | if (abs_values[k] == 1) { |
650 | 186k | eob = k; |
651 | 186k | } |
652 | 1.28G | } |
653 | 51.7M | int r = 0; |
654 | 51.7M | int refinement_bits[kDCTBlockSize]; |
655 | 51.7M | size_t refinement_bits_count = 0; |
656 | 1.33G | for (int k = Ss; k <= Se; k++) { |
657 | 1.28G | if (abs_values[k] == 0) { |
658 | 1.28G | r++; |
659 | 1.28G | continue; |
660 | 1.28G | } |
661 | 1.46M | while (r > 15 && k <= eob) { |
662 | 108k | Flush(coding_state, bw); |
663 | 108k | WriteBits(bw, ac_huff.depth[0xf0], ac_huff.code[0xf0]); |
664 | 108k | r -= 16; |
665 | 127k | for (size_t i = 0; i < refinement_bits_count; ++i) { |
666 | 18.7k | WriteBits(bw, 1, refinement_bits[i]); |
667 | 18.7k | } |
668 | 108k | refinement_bits_count = 0; |
669 | 108k | } |
670 | 1.35M | if (abs_values[k] > 1) { |
671 | 1.16M | refinement_bits[refinement_bits_count++] = abs_values[k] & 1u; |
672 | 1.16M | continue; |
673 | 1.16M | } |
674 | 186k | Flush(coding_state, bw); |
675 | 186k | int symbol = (r << 4u) + 1; |
676 | 186k | int new_non_zero_bit = (coeffs[kJPEGNaturalOrder[k]] < 0) ? 0 : 1; |
677 | 186k | WriteBits(bw, ac_huff.depth[symbol], ac_huff.code[symbol]); |
678 | 186k | WriteBits(bw, 1, new_non_zero_bit); |
679 | 225k | for (size_t i = 0; i < refinement_bits_count; ++i) { |
680 | 38.7k | WriteBits(bw, 1, refinement_bits[i]); |
681 | 38.7k | } |
682 | 186k | refinement_bits_count = 0; |
683 | 186k | r = 0; |
684 | 186k | } |
685 | 51.7M | if (r > 0 || refinement_bits_count) { |
686 | 51.7M | if (!BufferEndOfBand(coding_state, &ac_huff, refinement_bits, |
687 | 51.7M | refinement_bits_count, bw)) { |
688 | 0 | return false; |
689 | 0 | } |
690 | 51.7M | if (!eob_run_allowed) { |
691 | 6.84M | Flush(coding_state, bw); |
692 | 6.84M | } |
693 | 51.7M | } |
694 | 51.7M | return true; |
695 | 51.7M | } |
696 | | |
697 | | template <int kMode> |
698 | | SerializationStatus BRUNSLI_NOINLINE DoEncodeScan(const JPEGData& jpg, |
699 | | const State& parsing_state, |
700 | 10.0k | SerializationState* state) { |
701 | 10.0k | const JPEGScanInfo& scan_info = jpg.scan_info[state->scan_index]; |
702 | 10.0k | EncodeScanState& ss = state->scan_state; |
703 | | |
704 | 10.0k | const int restart_interval = |
705 | 10.0k | state->seen_dri_marker ? jpg.restart_interval : 0; |
706 | | |
707 | 22.7k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { |
708 | 22.7k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { |
709 | 13.0k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; |
710 | 13.0k | } else { |
711 | 9.66k | return -1; |
712 | 9.66k | } |
713 | 22.7k | }; jpeg_data_writer.cc:brunsli::(anonymous namespace)::DoEncodeScan<0>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*)::{lambda()#1}::operator()() constLine | Count | Source | 707 | 3.69k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { | 708 | 3.69k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { | 709 | 2.18k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; | 710 | 2.18k | } else { | 711 | 1.50k | return -1; | 712 | 1.50k | } | 713 | 3.69k | }; |
jpeg_data_writer.cc:brunsli::(anonymous namespace)::DoEncodeScan<1>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*)::{lambda()#1}::operator()() constLine | Count | Source | 707 | 11.8k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { | 708 | 11.8k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { | 709 | 8.87k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; | 710 | 8.87k | } else { | 711 | 3.01k | return -1; | 712 | 3.01k | } | 713 | 11.8k | }; |
jpeg_data_writer.cc:brunsli::(anonymous namespace)::DoEncodeScan<2>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*)::{lambda()#1}::operator()() constLine | Count | Source | 707 | 7.11k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { | 708 | 7.11k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { | 709 | 1.97k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; | 710 | 5.13k | } else { | 711 | 5.13k | return -1; | 712 | 5.13k | } | 713 | 7.11k | }; |
|
714 | | |
715 | 38.3k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { |
716 | 38.3k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { |
717 | 28.7k | return scan_info.reset_points[ss.next_reset_point_pos++]; |
718 | 28.7k | } else { |
719 | 9.59k | return -1; |
720 | 9.59k | } |
721 | 38.3k | }; jpeg_data_writer.cc:brunsli::(anonymous namespace)::DoEncodeScan<0>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*)::{lambda()#2}::operator()() constLine | Count | Source | 715 | 2.87k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { | 716 | 2.87k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { | 717 | 1.36k | return scan_info.reset_points[ss.next_reset_point_pos++]; | 718 | 1.50k | } else { | 719 | 1.50k | return -1; | 720 | 1.50k | } | 721 | 2.87k | }; |
jpeg_data_writer.cc:brunsli::(anonymous namespace)::DoEncodeScan<1>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*)::{lambda()#2}::operator()() constLine | Count | Source | 715 | 12.6k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { | 716 | 12.6k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { | 717 | 9.68k | return scan_info.reset_points[ss.next_reset_point_pos++]; | 718 | 9.68k | } else { | 719 | 3.01k | return -1; | 720 | 3.01k | } | 721 | 12.6k | }; |
jpeg_data_writer.cc:brunsli::(anonymous namespace)::DoEncodeScan<2>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*)::{lambda()#2}::operator()() constLine | Count | Source | 715 | 22.7k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { | 716 | 22.7k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { | 717 | 17.6k | return scan_info.reset_points[ss.next_reset_point_pos++]; | 718 | 17.6k | } else { | 719 | 5.08k | return -1; | 720 | 5.08k | } | 721 | 22.7k | }; |
|
722 | | |
723 | 10.0k | if (ss.stage == EncodeScanState::HEAD) { |
724 | 10.0k | if (!EncodeSOS(jpg, scan_info, state)) return SerializationStatus::ERROR; |
725 | 9.77k | BitWriterInit(&ss.bw, &state->output_queue); |
726 | 9.77k | DCTCodingStateInit(&ss.coding_state); |
727 | 9.77k | ss.restarts_to_go = restart_interval; |
728 | 9.77k | ss.next_restart_marker = 0; |
729 | 9.77k | ss.block_scan_index = 0; |
730 | 9.77k | ss.extra_zero_runs_pos = 0; |
731 | 9.77k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); |
732 | 9.77k | ss.next_reset_point_pos = 0; |
733 | 9.77k | ss.next_reset_point = get_next_reset_point(); |
734 | 9.77k | ss.mcu_y = 0; |
735 | 9.77k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); |
736 | 9.77k | ss.stage = EncodeScanState::BODY; |
737 | 9.77k | } |
738 | 9.77k | BitWriter* bw = &ss.bw; |
739 | 9.77k | DCTCodingState* coding_state = &ss.coding_state; |
740 | | |
741 | 9.77k | BRUNSLI_DCHECK(ss.stage == EncodeScanState::BODY); |
742 | | |
743 | | // "Non-interleaved" means color data comes in separate scans, in other words |
744 | | // each scan can contain only one color component. |
745 | 9.77k | const bool is_interleaved = (scan_info.num_components > 1); |
746 | 9.77k | const JPEGComponent& base_component = |
747 | 9.77k | jpg.components[scan_info.components[0].comp_idx]; |
748 | | // h_group / v_group act as numerators for converting number of blocks to |
749 | | // number of MCU. In interleaved mode it is 1, so MCU is represented with |
750 | | // max_*_samp_factor blocks. In non-interleaved mode we choose numerator to |
751 | | // be the samping factor, consequently MCU is always represented with single |
752 | | // block. |
753 | 9.77k | const int h_group = is_interleaved ? 1 : base_component.h_samp_factor; |
754 | 9.77k | const int v_group = is_interleaved ? 1 : base_component.v_samp_factor; |
755 | 9.77k | const int MCUs_per_row = |
756 | 9.77k | DivCeil(jpg.width * h_group, 8 * jpg.max_h_samp_factor); |
757 | 9.77k | const int MCU_rows = DivCeil(jpg.height * v_group, 8 * jpg.max_v_samp_factor); |
758 | 9.77k | const bool is_progressive = state->is_progressive; |
759 | 9.77k | const int Al = is_progressive ? scan_info.Al : 0; |
760 | 9.77k | const int Ss = is_progressive ? scan_info.Ss : 0; |
761 | 9.77k | const int Se = is_progressive ? scan_info.Se : 63; |
762 | | |
763 | | // DC-only is defined by [0..0] spectral range. |
764 | 9.77k | const bool want_ac = ((Ss != 0) || (Se != 0)); |
765 | 9.77k | const bool complete_ac = (parsing_state.stage == Stage::DONE); |
766 | 9.77k | const bool has_ac = |
767 | 9.77k | complete_ac || HasSection(&parsing_state, kBrunsliACDataTag); |
768 | 9.77k | if (want_ac && !has_ac) return SerializationStatus::NEEDS_MORE_INPUT; |
769 | | |
770 | | // |has_ac| implies |complete_dc| but not vice versa; for the sake of |
771 | | // simplicity we pretend they are equal, because they are separated by just a |
772 | | // few bytes of input. |
773 | 9.77k | const bool complete_dc = has_ac; |
774 | 9.77k | const bool complete = want_ac ? complete_ac : complete_dc; |
775 | | // When "incomplete" |ac_dc| tracks information about current ("incomplete") |
776 | | // band parsing progress. |
777 | 9.77k | const int last_mcu_y = |
778 | 9.77k | complete ? MCU_rows : parsing_state.internal->ac_dc.next_mcu_y * v_group; |
779 | | |
780 | 389k | for (; ss.mcu_y < last_mcu_y; ++ss.mcu_y) { |
781 | 3.40M | for (int mcu_x = 0; mcu_x < MCUs_per_row; ++mcu_x) { |
782 | | // Possibly emit a restart marker. |
783 | 3.02M | if (restart_interval > 0 && ss.restarts_to_go == 0) { |
784 | 512k | Flush(coding_state, bw); |
785 | 512k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { |
786 | 51 | return SerializationStatus::ERROR; |
787 | 51 | } |
788 | 512k | EmitMarker(bw, 0xD0 + ss.next_restart_marker); |
789 | 512k | ss.next_restart_marker += 1; |
790 | 512k | ss.next_restart_marker &= 0x7; |
791 | 512k | ss.restarts_to_go = restart_interval; |
792 | 512k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); |
793 | 512k | } |
794 | | // Encode one MCU |
795 | 9.44M | for (size_t i = 0; i < scan_info.num_components; ++i) { |
796 | 6.41M | const JPEGComponentScanInfo& si = scan_info.components[i]; |
797 | 6.41M | const JPEGComponent& c = jpg.components[si.comp_idx]; |
798 | 6.41M | const HuffmanCodeTable& dc_huff = state->dc_huff_table[si.dc_tbl_idx]; |
799 | 6.41M | const HuffmanCodeTable& ac_huff = state->ac_huff_table[si.ac_tbl_idx]; |
800 | 6.41M | int n_blocks_y = is_interleaved ? c.v_samp_factor : 1; |
801 | 6.41M | int n_blocks_x = is_interleaved ? c.h_samp_factor : 1; |
802 | 32.0M | for (int iy = 0; iy < n_blocks_y; ++iy) { |
803 | 104M | for (int ix = 0; ix < n_blocks_x; ++ix) { |
804 | 78.6M | int block_y = ss.mcu_y * n_blocks_y + iy; |
805 | 78.6M | int block_x = mcu_x * n_blocks_x + ix; |
806 | 78.6M | int block_idx = block_y * c.width_in_blocks + block_x; |
807 | 78.6M | if (ss.block_scan_index == ss.next_reset_point) { |
808 | 28.5k | Flush(coding_state, bw); |
809 | 28.5k | ss.next_reset_point = get_next_reset_point(); |
810 | 28.5k | } |
811 | 78.6M | int num_zero_runs = 0; |
812 | 78.6M | if (ss.block_scan_index == ss.next_extra_zero_run_index) { |
813 | 12.9k | num_zero_runs = scan_info.extra_zero_runs[ss.extra_zero_runs_pos] |
814 | 12.9k | .num_extra_zero_runs; |
815 | 12.9k | ++ss.extra_zero_runs_pos; |
816 | 12.9k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); |
817 | 12.9k | } |
818 | 78.6M | const coeff_t* coeffs = &c.coeffs[block_idx << 6]; |
819 | 78.6M | bool ok; |
820 | 78.6M | if (kMode == 0) { |
821 | 7.55M | ok = EncodeDCTBlockSequential(coeffs, dc_huff, ac_huff, |
822 | 7.55M | num_zero_runs, |
823 | 7.55M | ss.last_dc_coeff + si.comp_idx, bw); |
824 | 71.1M | } else if (kMode == 1) { |
825 | 18.9M | ok = EncodeDCTBlockProgressive( |
826 | 18.9M | coeffs, dc_huff, ac_huff, Ss, Se, Al, num_zero_runs, |
827 | 18.9M | coding_state, ss.last_dc_coeff + si.comp_idx, bw); |
828 | 52.1M | } else { |
829 | 52.1M | ok = EncodeRefinementBits(coeffs, ac_huff, Ss, Se, Al, |
830 | 52.1M | coding_state, bw); |
831 | 52.1M | } |
832 | 78.6M | if (!ok) return SerializationStatus::ERROR; |
833 | 78.6M | ++ss.block_scan_index; |
834 | 78.6M | } |
835 | 25.6M | } |
836 | 6.41M | } |
837 | 3.02M | --ss.restarts_to_go; |
838 | 3.02M | } |
839 | 379k | } |
840 | 9.72k | if (ss.mcu_y < MCU_rows) { |
841 | 0 | if (!bw->healthy) return SerializationStatus::ERROR; |
842 | 0 | return SerializationStatus::NEEDS_MORE_INPUT; |
843 | 0 | } |
844 | 9.72k | Flush(coding_state, bw); |
845 | 9.72k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { |
846 | 64 | return SerializationStatus::ERROR; |
847 | 64 | } |
848 | 9.65k | BitWriterFinish(bw); |
849 | 9.65k | ss.stage = EncodeScanState::HEAD; |
850 | 9.65k | state->scan_index++; |
851 | 9.65k | if (!bw->healthy) return SerializationStatus::ERROR; |
852 | | |
853 | 2.24k | return SerializationStatus::DONE; |
854 | 9.65k | } jpeg_data_writer.cc:brunsli::internal::dec::SerializationStatus brunsli::(anonymous namespace)::DoEncodeScan<0>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*) Line | Count | Source | 700 | 1.60k | SerializationState* state) { | 701 | 1.60k | const JPEGScanInfo& scan_info = jpg.scan_info[state->scan_index]; | 702 | 1.60k | EncodeScanState& ss = state->scan_state; | 703 | | | 704 | 1.60k | const int restart_interval = | 705 | 1.60k | state->seen_dri_marker ? jpg.restart_interval : 0; | 706 | | | 707 | 1.60k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { | 708 | 1.60k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { | 709 | 1.60k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; | 710 | 1.60k | } else { | 711 | 1.60k | return -1; | 712 | 1.60k | } | 713 | 1.60k | }; | 714 | | | 715 | 1.60k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { | 716 | 1.60k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { | 717 | 1.60k | return scan_info.reset_points[ss.next_reset_point_pos++]; | 718 | 1.60k | } else { | 719 | 1.60k | return -1; | 720 | 1.60k | } | 721 | 1.60k | }; | 722 | | | 723 | 1.60k | if (ss.stage == EncodeScanState::HEAD) { | 724 | 1.60k | if (!EncodeSOS(jpg, scan_info, state)) return SerializationStatus::ERROR; | 725 | 1.51k | BitWriterInit(&ss.bw, &state->output_queue); | 726 | 1.51k | DCTCodingStateInit(&ss.coding_state); | 727 | 1.51k | ss.restarts_to_go = restart_interval; | 728 | 1.51k | ss.next_restart_marker = 0; | 729 | 1.51k | ss.block_scan_index = 0; | 730 | 1.51k | ss.extra_zero_runs_pos = 0; | 731 | 1.51k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); | 732 | 1.51k | ss.next_reset_point_pos = 0; | 733 | 1.51k | ss.next_reset_point = get_next_reset_point(); | 734 | 1.51k | ss.mcu_y = 0; | 735 | 1.51k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); | 736 | 1.51k | ss.stage = EncodeScanState::BODY; | 737 | 1.51k | } | 738 | 1.51k | BitWriter* bw = &ss.bw; | 739 | 1.51k | DCTCodingState* coding_state = &ss.coding_state; | 740 | | | 741 | 1.51k | BRUNSLI_DCHECK(ss.stage == EncodeScanState::BODY); | 742 | | | 743 | | // "Non-interleaved" means color data comes in separate scans, in other words | 744 | | // each scan can contain only one color component. | 745 | 1.51k | const bool is_interleaved = (scan_info.num_components > 1); | 746 | 1.51k | const JPEGComponent& base_component = | 747 | 1.51k | jpg.components[scan_info.components[0].comp_idx]; | 748 | | // h_group / v_group act as numerators for converting number of blocks to | 749 | | // number of MCU. In interleaved mode it is 1, so MCU is represented with | 750 | | // max_*_samp_factor blocks. In non-interleaved mode we choose numerator to | 751 | | // be the samping factor, consequently MCU is always represented with single | 752 | | // block. | 753 | 1.51k | const int h_group = is_interleaved ? 1 : base_component.h_samp_factor; | 754 | 1.51k | const int v_group = is_interleaved ? 1 : base_component.v_samp_factor; | 755 | 1.51k | const int MCUs_per_row = | 756 | 1.51k | DivCeil(jpg.width * h_group, 8 * jpg.max_h_samp_factor); | 757 | 1.51k | const int MCU_rows = DivCeil(jpg.height * v_group, 8 * jpg.max_v_samp_factor); | 758 | 1.51k | const bool is_progressive = state->is_progressive; | 759 | 1.51k | const int Al = is_progressive ? scan_info.Al : 0; | 760 | 1.51k | const int Ss = is_progressive ? scan_info.Ss : 0; | 761 | 1.51k | const int Se = is_progressive ? scan_info.Se : 63; | 762 | | | 763 | | // DC-only is defined by [0..0] spectral range. | 764 | 1.51k | const bool want_ac = ((Ss != 0) || (Se != 0)); | 765 | 1.51k | const bool complete_ac = (parsing_state.stage == Stage::DONE); | 766 | 1.51k | const bool has_ac = | 767 | 1.51k | complete_ac || HasSection(&parsing_state, kBrunsliACDataTag); | 768 | 1.51k | if (want_ac && !has_ac) return SerializationStatus::NEEDS_MORE_INPUT; | 769 | | | 770 | | // |has_ac| implies |complete_dc| but not vice versa; for the sake of | 771 | | // simplicity we pretend they are equal, because they are separated by just a | 772 | | // few bytes of input. | 773 | 1.51k | const bool complete_dc = has_ac; | 774 | 1.51k | const bool complete = want_ac ? complete_ac : complete_dc; | 775 | | // When "incomplete" |ac_dc| tracks information about current ("incomplete") | 776 | | // band parsing progress. | 777 | 1.51k | const int last_mcu_y = | 778 | 1.51k | complete ? MCU_rows : parsing_state.internal->ac_dc.next_mcu_y * v_group; | 779 | | | 780 | 123k | for (; ss.mcu_y < last_mcu_y; ++ss.mcu_y) { | 781 | 796k | for (int mcu_x = 0; mcu_x < MCUs_per_row; ++mcu_x) { | 782 | | // Possibly emit a restart marker. | 783 | 674k | if (restart_interval > 0 && ss.restarts_to_go == 0) { | 784 | 190k | Flush(coding_state, bw); | 785 | 190k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { | 786 | 22 | return SerializationStatus::ERROR; | 787 | 22 | } | 788 | 190k | EmitMarker(bw, 0xD0 + ss.next_restart_marker); | 789 | 190k | ss.next_restart_marker += 1; | 790 | 190k | ss.next_restart_marker &= 0x7; | 791 | 190k | ss.restarts_to_go = restart_interval; | 792 | 190k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); | 793 | 190k | } | 794 | | // Encode one MCU | 795 | 2.06M | for (size_t i = 0; i < scan_info.num_components; ++i) { | 796 | 1.38M | const JPEGComponentScanInfo& si = scan_info.components[i]; | 797 | 1.38M | const JPEGComponent& c = jpg.components[si.comp_idx]; | 798 | 1.38M | const HuffmanCodeTable& dc_huff = state->dc_huff_table[si.dc_tbl_idx]; | 799 | 1.38M | const HuffmanCodeTable& ac_huff = state->ac_huff_table[si.ac_tbl_idx]; | 800 | 1.38M | int n_blocks_y = is_interleaved ? c.v_samp_factor : 1; | 801 | 1.38M | int n_blocks_x = is_interleaved ? c.h_samp_factor : 1; | 802 | 4.68M | for (int iy = 0; iy < n_blocks_y; ++iy) { | 803 | 10.8M | for (int ix = 0; ix < n_blocks_x; ++ix) { | 804 | 7.55M | int block_y = ss.mcu_y * n_blocks_y + iy; | 805 | 7.55M | int block_x = mcu_x * n_blocks_x + ix; | 806 | 7.55M | int block_idx = block_y * c.width_in_blocks + block_x; | 807 | 7.55M | if (ss.block_scan_index == ss.next_reset_point) { | 808 | 1.35k | Flush(coding_state, bw); | 809 | 1.35k | ss.next_reset_point = get_next_reset_point(); | 810 | 1.35k | } | 811 | 7.55M | int num_zero_runs = 0; | 812 | 7.55M | if (ss.block_scan_index == ss.next_extra_zero_run_index) { | 813 | 2.17k | num_zero_runs = scan_info.extra_zero_runs[ss.extra_zero_runs_pos] | 814 | 2.17k | .num_extra_zero_runs; | 815 | 2.17k | ++ss.extra_zero_runs_pos; | 816 | 2.17k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); | 817 | 2.17k | } | 818 | 7.55M | const coeff_t* coeffs = &c.coeffs[block_idx << 6]; | 819 | 7.55M | bool ok; | 820 | 7.55M | if (kMode == 0) { | 821 | 7.55M | ok = EncodeDCTBlockSequential(coeffs, dc_huff, ac_huff, | 822 | 7.55M | num_zero_runs, | 823 | 7.55M | ss.last_dc_coeff + si.comp_idx, bw); | 824 | 7.55M | } else if (kMode == 1) { | 825 | 0 | ok = EncodeDCTBlockProgressive( | 826 | 0 | coeffs, dc_huff, ac_huff, Ss, Se, Al, num_zero_runs, | 827 | 0 | coding_state, ss.last_dc_coeff + si.comp_idx, bw); | 828 | 0 | } else { | 829 | 0 | ok = EncodeRefinementBits(coeffs, ac_huff, Ss, Se, Al, | 830 | 0 | coding_state, bw); | 831 | 0 | } | 832 | 7.55M | if (!ok) return SerializationStatus::ERROR; | 833 | 7.55M | ++ss.block_scan_index; | 834 | 7.55M | } | 835 | 3.29M | } | 836 | 1.38M | } | 837 | 674k | --ss.restarts_to_go; | 838 | 674k | } | 839 | 121k | } | 840 | 1.49k | if (ss.mcu_y < MCU_rows) { | 841 | 0 | if (!bw->healthy) return SerializationStatus::ERROR; | 842 | 0 | return SerializationStatus::NEEDS_MORE_INPUT; | 843 | 0 | } | 844 | 1.49k | Flush(coding_state, bw); | 845 | 1.49k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { | 846 | 25 | return SerializationStatus::ERROR; | 847 | 25 | } | 848 | 1.47k | BitWriterFinish(bw); | 849 | 1.47k | ss.stage = EncodeScanState::HEAD; | 850 | 1.47k | state->scan_index++; | 851 | 1.47k | if (!bw->healthy) return SerializationStatus::ERROR; | 852 | | | 853 | 306 | return SerializationStatus::DONE; | 854 | 1.47k | } |
jpeg_data_writer.cc:brunsli::internal::dec::SerializationStatus brunsli::(anonymous namespace)::DoEncodeScan<1>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*) Line | Count | Source | 700 | 3.11k | SerializationState* state) { | 701 | 3.11k | const JPEGScanInfo& scan_info = jpg.scan_info[state->scan_index]; | 702 | 3.11k | EncodeScanState& ss = state->scan_state; | 703 | | | 704 | 3.11k | const int restart_interval = | 705 | 3.11k | state->seen_dri_marker ? jpg.restart_interval : 0; | 706 | | | 707 | 3.11k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { | 708 | 3.11k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { | 709 | 3.11k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; | 710 | 3.11k | } else { | 711 | 3.11k | return -1; | 712 | 3.11k | } | 713 | 3.11k | }; | 714 | | | 715 | 3.11k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { | 716 | 3.11k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { | 717 | 3.11k | return scan_info.reset_points[ss.next_reset_point_pos++]; | 718 | 3.11k | } else { | 719 | 3.11k | return -1; | 720 | 3.11k | } | 721 | 3.11k | }; | 722 | | | 723 | 3.11k | if (ss.stage == EncodeScanState::HEAD) { | 724 | 3.11k | if (!EncodeSOS(jpg, scan_info, state)) return SerializationStatus::ERROR; | 725 | 3.08k | BitWriterInit(&ss.bw, &state->output_queue); | 726 | 3.08k | DCTCodingStateInit(&ss.coding_state); | 727 | 3.08k | ss.restarts_to_go = restart_interval; | 728 | 3.08k | ss.next_restart_marker = 0; | 729 | 3.08k | ss.block_scan_index = 0; | 730 | 3.08k | ss.extra_zero_runs_pos = 0; | 731 | 3.08k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); | 732 | 3.08k | ss.next_reset_point_pos = 0; | 733 | 3.08k | ss.next_reset_point = get_next_reset_point(); | 734 | 3.08k | ss.mcu_y = 0; | 735 | 3.08k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); | 736 | 3.08k | ss.stage = EncodeScanState::BODY; | 737 | 3.08k | } | 738 | 3.08k | BitWriter* bw = &ss.bw; | 739 | 3.08k | DCTCodingState* coding_state = &ss.coding_state; | 740 | | | 741 | 3.08k | BRUNSLI_DCHECK(ss.stage == EncodeScanState::BODY); | 742 | | | 743 | | // "Non-interleaved" means color data comes in separate scans, in other words | 744 | | // each scan can contain only one color component. | 745 | 3.08k | const bool is_interleaved = (scan_info.num_components > 1); | 746 | 3.08k | const JPEGComponent& base_component = | 747 | 3.08k | jpg.components[scan_info.components[0].comp_idx]; | 748 | | // h_group / v_group act as numerators for converting number of blocks to | 749 | | // number of MCU. In interleaved mode it is 1, so MCU is represented with | 750 | | // max_*_samp_factor blocks. In non-interleaved mode we choose numerator to | 751 | | // be the samping factor, consequently MCU is always represented with single | 752 | | // block. | 753 | 3.08k | const int h_group = is_interleaved ? 1 : base_component.h_samp_factor; | 754 | 3.08k | const int v_group = is_interleaved ? 1 : base_component.v_samp_factor; | 755 | 3.08k | const int MCUs_per_row = | 756 | 3.08k | DivCeil(jpg.width * h_group, 8 * jpg.max_h_samp_factor); | 757 | 3.08k | const int MCU_rows = DivCeil(jpg.height * v_group, 8 * jpg.max_v_samp_factor); | 758 | 3.08k | const bool is_progressive = state->is_progressive; | 759 | 3.08k | const int Al = is_progressive ? scan_info.Al : 0; | 760 | 3.08k | const int Ss = is_progressive ? scan_info.Ss : 0; | 761 | 3.08k | const int Se = is_progressive ? scan_info.Se : 63; | 762 | | | 763 | | // DC-only is defined by [0..0] spectral range. | 764 | 3.08k | const bool want_ac = ((Ss != 0) || (Se != 0)); | 765 | 3.08k | const bool complete_ac = (parsing_state.stage == Stage::DONE); | 766 | 3.08k | const bool has_ac = | 767 | 3.08k | complete_ac || HasSection(&parsing_state, kBrunsliACDataTag); | 768 | 3.08k | if (want_ac && !has_ac) return SerializationStatus::NEEDS_MORE_INPUT; | 769 | | | 770 | | // |has_ac| implies |complete_dc| but not vice versa; for the sake of | 771 | | // simplicity we pretend they are equal, because they are separated by just a | 772 | | // few bytes of input. | 773 | 3.08k | const bool complete_dc = has_ac; | 774 | 3.08k | const bool complete = want_ac ? complete_ac : complete_dc; | 775 | | // When "incomplete" |ac_dc| tracks information about current ("incomplete") | 776 | | // band parsing progress. | 777 | 3.08k | const int last_mcu_y = | 778 | 3.08k | complete ? MCU_rows : parsing_state.internal->ac_dc.next_mcu_y * v_group; | 779 | | | 780 | 135k | for (; ss.mcu_y < last_mcu_y; ++ss.mcu_y) { | 781 | 1.02M | for (int mcu_x = 0; mcu_x < MCUs_per_row; ++mcu_x) { | 782 | | // Possibly emit a restart marker. | 783 | 889k | if (restart_interval > 0 && ss.restarts_to_go == 0) { | 784 | 160k | Flush(coding_state, bw); | 785 | 160k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { | 786 | 14 | return SerializationStatus::ERROR; | 787 | 14 | } | 788 | 160k | EmitMarker(bw, 0xD0 + ss.next_restart_marker); | 789 | 160k | ss.next_restart_marker += 1; | 790 | 160k | ss.next_restart_marker &= 0x7; | 791 | 160k | ss.restarts_to_go = restart_interval; | 792 | 160k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); | 793 | 160k | } | 794 | | // Encode one MCU | 795 | 2.83M | for (size_t i = 0; i < scan_info.num_components; ++i) { | 796 | 1.94M | const JPEGComponentScanInfo& si = scan_info.components[i]; | 797 | 1.94M | const JPEGComponent& c = jpg.components[si.comp_idx]; | 798 | 1.94M | const HuffmanCodeTable& dc_huff = state->dc_huff_table[si.dc_tbl_idx]; | 799 | 1.94M | const HuffmanCodeTable& ac_huff = state->ac_huff_table[si.ac_tbl_idx]; | 800 | 1.94M | int n_blocks_y = is_interleaved ? c.v_samp_factor : 1; | 801 | 1.94M | int n_blocks_x = is_interleaved ? c.h_samp_factor : 1; | 802 | 8.39M | for (int iy = 0; iy < n_blocks_y; ++iy) { | 803 | 25.3M | for (int ix = 0; ix < n_blocks_x; ++ix) { | 804 | 18.9M | int block_y = ss.mcu_y * n_blocks_y + iy; | 805 | 18.9M | int block_x = mcu_x * n_blocks_x + ix; | 806 | 18.9M | int block_idx = block_y * c.width_in_blocks + block_x; | 807 | 18.9M | if (ss.block_scan_index == ss.next_reset_point) { | 808 | 9.61k | Flush(coding_state, bw); | 809 | 9.61k | ss.next_reset_point = get_next_reset_point(); | 810 | 9.61k | } | 811 | 18.9M | int num_zero_runs = 0; | 812 | 18.9M | if (ss.block_scan_index == ss.next_extra_zero_run_index) { | 813 | 8.81k | num_zero_runs = scan_info.extra_zero_runs[ss.extra_zero_runs_pos] | 814 | 8.81k | .num_extra_zero_runs; | 815 | 8.81k | ++ss.extra_zero_runs_pos; | 816 | 8.81k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); | 817 | 8.81k | } | 818 | 18.9M | const coeff_t* coeffs = &c.coeffs[block_idx << 6]; | 819 | 18.9M | bool ok; | 820 | 18.9M | if (kMode == 0) { | 821 | 0 | ok = EncodeDCTBlockSequential(coeffs, dc_huff, ac_huff, | 822 | 0 | num_zero_runs, | 823 | 0 | ss.last_dc_coeff + si.comp_idx, bw); | 824 | 18.9M | } else if (kMode == 1) { | 825 | 18.9M | ok = EncodeDCTBlockProgressive( | 826 | 18.9M | coeffs, dc_huff, ac_huff, Ss, Se, Al, num_zero_runs, | 827 | 18.9M | coding_state, ss.last_dc_coeff + si.comp_idx, bw); | 828 | 18.9M | } else { | 829 | 0 | ok = EncodeRefinementBits(coeffs, ac_huff, Ss, Se, Al, | 830 | 0 | coding_state, bw); | 831 | 0 | } | 832 | 18.9M | if (!ok) return SerializationStatus::ERROR; | 833 | 18.9M | ++ss.block_scan_index; | 834 | 18.9M | } | 835 | 6.44M | } | 836 | 1.94M | } | 837 | 889k | --ss.restarts_to_go; | 838 | 889k | } | 839 | 132k | } | 840 | 3.06k | if (ss.mcu_y < MCU_rows) { | 841 | 0 | if (!bw->healthy) return SerializationStatus::ERROR; | 842 | 0 | return SerializationStatus::NEEDS_MORE_INPUT; | 843 | 0 | } | 844 | 3.06k | Flush(coding_state, bw); | 845 | 3.06k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { | 846 | 12 | return SerializationStatus::ERROR; | 847 | 12 | } | 848 | 3.05k | BitWriterFinish(bw); | 849 | 3.05k | ss.stage = EncodeScanState::HEAD; | 850 | 3.05k | state->scan_index++; | 851 | 3.05k | if (!bw->healthy) return SerializationStatus::ERROR; | 852 | | | 853 | 792 | return SerializationStatus::DONE; | 854 | 3.05k | } |
jpeg_data_writer.cc:brunsli::internal::dec::SerializationStatus brunsli::(anonymous namespace)::DoEncodeScan<2>(brunsli::JPEGData const&, brunsli::internal::dec::State const&, brunsli::internal::dec::SerializationState*) Line | Count | Source | 700 | 5.31k | SerializationState* state) { | 701 | 5.31k | const JPEGScanInfo& scan_info = jpg.scan_info[state->scan_index]; | 702 | 5.31k | EncodeScanState& ss = state->scan_state; | 703 | | | 704 | 5.31k | const int restart_interval = | 705 | 5.31k | state->seen_dri_marker ? jpg.restart_interval : 0; | 706 | | | 707 | 5.31k | const auto get_next_extra_zero_run_index = [&ss, &scan_info]() -> int { | 708 | 5.31k | if (ss.extra_zero_runs_pos < scan_info.extra_zero_runs.size()) { | 709 | 5.31k | return scan_info.extra_zero_runs[ss.extra_zero_runs_pos].block_idx; | 710 | 5.31k | } else { | 711 | 5.31k | return -1; | 712 | 5.31k | } | 713 | 5.31k | }; | 714 | | | 715 | 5.31k | const auto get_next_reset_point = [&ss, &scan_info]() -> int { | 716 | 5.31k | if (ss.next_reset_point_pos < scan_info.reset_points.size()) { | 717 | 5.31k | return scan_info.reset_points[ss.next_reset_point_pos++]; | 718 | 5.31k | } else { | 719 | 5.31k | return -1; | 720 | 5.31k | } | 721 | 5.31k | }; | 722 | | | 723 | 5.31k | if (ss.stage == EncodeScanState::HEAD) { | 724 | 5.31k | if (!EncodeSOS(jpg, scan_info, state)) return SerializationStatus::ERROR; | 725 | 5.17k | BitWriterInit(&ss.bw, &state->output_queue); | 726 | 5.17k | DCTCodingStateInit(&ss.coding_state); | 727 | 5.17k | ss.restarts_to_go = restart_interval; | 728 | 5.17k | ss.next_restart_marker = 0; | 729 | 5.17k | ss.block_scan_index = 0; | 730 | 5.17k | ss.extra_zero_runs_pos = 0; | 731 | 5.17k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); | 732 | 5.17k | ss.next_reset_point_pos = 0; | 733 | 5.17k | ss.next_reset_point = get_next_reset_point(); | 734 | 5.17k | ss.mcu_y = 0; | 735 | 5.17k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); | 736 | 5.17k | ss.stage = EncodeScanState::BODY; | 737 | 5.17k | } | 738 | 5.17k | BitWriter* bw = &ss.bw; | 739 | 5.17k | DCTCodingState* coding_state = &ss.coding_state; | 740 | | | 741 | 5.17k | BRUNSLI_DCHECK(ss.stage == EncodeScanState::BODY); | 742 | | | 743 | | // "Non-interleaved" means color data comes in separate scans, in other words | 744 | | // each scan can contain only one color component. | 745 | 5.17k | const bool is_interleaved = (scan_info.num_components > 1); | 746 | 5.17k | const JPEGComponent& base_component = | 747 | 5.17k | jpg.components[scan_info.components[0].comp_idx]; | 748 | | // h_group / v_group act as numerators for converting number of blocks to | 749 | | // number of MCU. In interleaved mode it is 1, so MCU is represented with | 750 | | // max_*_samp_factor blocks. In non-interleaved mode we choose numerator to | 751 | | // be the samping factor, consequently MCU is always represented with single | 752 | | // block. | 753 | 5.17k | const int h_group = is_interleaved ? 1 : base_component.h_samp_factor; | 754 | 5.17k | const int v_group = is_interleaved ? 1 : base_component.v_samp_factor; | 755 | 5.17k | const int MCUs_per_row = | 756 | 5.17k | DivCeil(jpg.width * h_group, 8 * jpg.max_h_samp_factor); | 757 | 5.17k | const int MCU_rows = DivCeil(jpg.height * v_group, 8 * jpg.max_v_samp_factor); | 758 | 5.17k | const bool is_progressive = state->is_progressive; | 759 | 5.17k | const int Al = is_progressive ? scan_info.Al : 0; | 760 | 5.17k | const int Ss = is_progressive ? scan_info.Ss : 0; | 761 | 5.17k | const int Se = is_progressive ? scan_info.Se : 63; | 762 | | | 763 | | // DC-only is defined by [0..0] spectral range. | 764 | 5.17k | const bool want_ac = ((Ss != 0) || (Se != 0)); | 765 | 5.17k | const bool complete_ac = (parsing_state.stage == Stage::DONE); | 766 | 5.17k | const bool has_ac = | 767 | 5.17k | complete_ac || HasSection(&parsing_state, kBrunsliACDataTag); | 768 | 5.17k | if (want_ac && !has_ac) return SerializationStatus::NEEDS_MORE_INPUT; | 769 | | | 770 | | // |has_ac| implies |complete_dc| but not vice versa; for the sake of | 771 | | // simplicity we pretend they are equal, because they are separated by just a | 772 | | // few bytes of input. | 773 | 5.17k | const bool complete_dc = has_ac; | 774 | 5.17k | const bool complete = want_ac ? complete_ac : complete_dc; | 775 | | // When "incomplete" |ac_dc| tracks information about current ("incomplete") | 776 | | // band parsing progress. | 777 | 5.17k | const int last_mcu_y = | 778 | 5.17k | complete ? MCU_rows : parsing_state.internal->ac_dc.next_mcu_y * v_group; | 779 | | | 780 | 130k | for (; ss.mcu_y < last_mcu_y; ++ss.mcu_y) { | 781 | 1.58M | for (int mcu_x = 0; mcu_x < MCUs_per_row; ++mcu_x) { | 782 | | // Possibly emit a restart marker. | 783 | 1.46M | if (restart_interval > 0 && ss.restarts_to_go == 0) { | 784 | 162k | Flush(coding_state, bw); | 785 | 162k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { | 786 | 15 | return SerializationStatus::ERROR; | 787 | 15 | } | 788 | 162k | EmitMarker(bw, 0xD0 + ss.next_restart_marker); | 789 | 162k | ss.next_restart_marker += 1; | 790 | 162k | ss.next_restart_marker &= 0x7; | 791 | 162k | ss.restarts_to_go = restart_interval; | 792 | 162k | memset(ss.last_dc_coeff, 0, sizeof(ss.last_dc_coeff)); | 793 | 162k | } | 794 | | // Encode one MCU | 795 | 4.54M | for (size_t i = 0; i < scan_info.num_components; ++i) { | 796 | 3.08M | const JPEGComponentScanInfo& si = scan_info.components[i]; | 797 | 3.08M | const JPEGComponent& c = jpg.components[si.comp_idx]; | 798 | 3.08M | const HuffmanCodeTable& dc_huff = state->dc_huff_table[si.dc_tbl_idx]; | 799 | 3.08M | const HuffmanCodeTable& ac_huff = state->ac_huff_table[si.ac_tbl_idx]; | 800 | 3.08M | int n_blocks_y = is_interleaved ? c.v_samp_factor : 1; | 801 | 3.08M | int n_blocks_x = is_interleaved ? c.h_samp_factor : 1; | 802 | 18.9M | for (int iy = 0; iy < n_blocks_y; ++iy) { | 803 | 68.0M | for (int ix = 0; ix < n_blocks_x; ++ix) { | 804 | 52.1M | int block_y = ss.mcu_y * n_blocks_y + iy; | 805 | 52.1M | int block_x = mcu_x * n_blocks_x + ix; | 806 | 52.1M | int block_idx = block_y * c.width_in_blocks + block_x; | 807 | 52.1M | if (ss.block_scan_index == ss.next_reset_point) { | 808 | 17.5k | Flush(coding_state, bw); | 809 | 17.5k | ss.next_reset_point = get_next_reset_point(); | 810 | 17.5k | } | 811 | 52.1M | int num_zero_runs = 0; | 812 | 52.1M | if (ss.block_scan_index == ss.next_extra_zero_run_index) { | 813 | 1.94k | num_zero_runs = scan_info.extra_zero_runs[ss.extra_zero_runs_pos] | 814 | 1.94k | .num_extra_zero_runs; | 815 | 1.94k | ++ss.extra_zero_runs_pos; | 816 | 1.94k | ss.next_extra_zero_run_index = get_next_extra_zero_run_index(); | 817 | 1.94k | } | 818 | 52.1M | const coeff_t* coeffs = &c.coeffs[block_idx << 6]; | 819 | 52.1M | bool ok; | 820 | 52.1M | if (kMode == 0) { | 821 | 0 | ok = EncodeDCTBlockSequential(coeffs, dc_huff, ac_huff, | 822 | 0 | num_zero_runs, | 823 | 0 | ss.last_dc_coeff + si.comp_idx, bw); | 824 | 52.1M | } else if (kMode == 1) { | 825 | 0 | ok = EncodeDCTBlockProgressive( | 826 | 0 | coeffs, dc_huff, ac_huff, Ss, Se, Al, num_zero_runs, | 827 | 0 | coding_state, ss.last_dc_coeff + si.comp_idx, bw); | 828 | 52.1M | } else { | 829 | 52.1M | ok = EncodeRefinementBits(coeffs, ac_huff, Ss, Se, Al, | 830 | 52.1M | coding_state, bw); | 831 | 52.1M | } | 832 | 52.1M | if (!ok) return SerializationStatus::ERROR; | 833 | 52.1M | ++ss.block_scan_index; | 834 | 52.1M | } | 835 | 15.8M | } | 836 | 3.08M | } | 837 | 1.46M | --ss.restarts_to_go; | 838 | 1.46M | } | 839 | 125k | } | 840 | 5.15k | if (ss.mcu_y < MCU_rows) { | 841 | 0 | if (!bw->healthy) return SerializationStatus::ERROR; | 842 | 0 | return SerializationStatus::NEEDS_MORE_INPUT; | 843 | 0 | } | 844 | 5.15k | Flush(coding_state, bw); | 845 | 5.15k | if (!JumpToByteBoundary(bw, &state->pad_bits, state->pad_bits_end)) { | 846 | 27 | return SerializationStatus::ERROR; | 847 | 27 | } | 848 | 5.12k | BitWriterFinish(bw); | 849 | 5.12k | ss.stage = EncodeScanState::HEAD; | 850 | 5.12k | state->scan_index++; | 851 | 5.12k | if (!bw->healthy) return SerializationStatus::ERROR; | 852 | | | 853 | 1.14k | return SerializationStatus::DONE; | 854 | 5.12k | } |
|
855 | | |
856 | | static SerializationStatus BRUNSLI_INLINE |
857 | | EncodeScan(const JPEGData& jpg, const State& parsing_state, |
858 | 10.0k | SerializationState* state) { |
859 | 10.0k | const JPEGScanInfo& scan_info = jpg.scan_info[state->scan_index]; |
860 | 10.0k | const bool is_progressive = state->is_progressive; |
861 | 10.0k | const int Al = is_progressive ? scan_info.Al : 0; |
862 | 10.0k | const int Ah = is_progressive ? scan_info.Ah : 0; |
863 | 10.0k | const int Ss = is_progressive ? scan_info.Ss : 0; |
864 | 10.0k | const int Se = is_progressive ? scan_info.Se : 63; |
865 | 10.0k | const bool need_sequential = |
866 | 10.0k | !is_progressive || (Ah == 0 && Al == 0 && Ss == 0 && Se == 63); |
867 | 10.0k | if (need_sequential) { |
868 | 1.60k | return DoEncodeScan<0>(jpg, parsing_state, state); |
869 | 8.43k | } else if (Ah == 0) { |
870 | 3.11k | return DoEncodeScan<1>(jpg, parsing_state, state); |
871 | 5.31k | } else { |
872 | 5.31k | return DoEncodeScan<2>(jpg, parsing_state, state); |
873 | 5.31k | } |
874 | 10.0k | } |
875 | | |
876 | | SerializationStatus SerializeSection(uint8_t marker, const State& parsing_state, |
877 | | SerializationState* state, |
878 | 68.5k | const JPEGData& jpg) { |
879 | 68.5k | const auto to_status = [](bool result) { |
880 | 58.2k | return result ? SerializationStatus::DONE : SerializationStatus::ERROR; |
881 | 58.2k | }; |
882 | | // TODO(eustas): add and use marker enum |
883 | 68.5k | switch (marker) { |
884 | 7.95k | case 0xC0: |
885 | 10.2k | case 0xC1: |
886 | 19.5k | case 0xC2: |
887 | 22.7k | case 0xC9: |
888 | 25.3k | case 0xCA: |
889 | 25.3k | return to_status(EncodeSOF(jpg, marker, state)); |
890 | | |
891 | 9.47k | case 0xC4: |
892 | 9.47k | return to_status(EncodeDHT(jpg, state)); |
893 | | |
894 | 2.65k | case 0xD0: |
895 | 4.97k | case 0xD1: |
896 | 6.88k | case 0xD2: |
897 | 8.82k | case 0xD3: |
898 | 10.8k | case 0xD4: |
899 | 13.8k | case 0xD5: |
900 | 16.3k | case 0xD6: |
901 | 17.7k | case 0xD7: |
902 | 17.7k | return to_status(EncodeRestart(marker, state)); |
903 | | |
904 | 754 | case 0xD9: |
905 | 754 | return to_status(EncodeEOI(jpg, state)); |
906 | | |
907 | 10.0k | case 0xDA: |
908 | 10.0k | return EncodeScan(jpg, parsing_state, state); |
909 | | |
910 | 745 | case 0xDB: |
911 | 745 | return to_status(EncodeDQT(jpg, state)); |
912 | | |
913 | 3.67k | case 0xDD: |
914 | 3.67k | return to_status(EncodeDRI(jpg, state)); |
915 | | |
916 | 43 | case 0xE0: |
917 | 84 | case 0xE1: |
918 | 143 | case 0xE2: |
919 | 155 | case 0xE3: |
920 | 180 | case 0xE4: |
921 | 210 | case 0xE5: |
922 | 248 | case 0xE6: |
923 | 285 | case 0xE7: |
924 | 305 | case 0xE8: |
925 | 323 | case 0xE9: |
926 | 352 | case 0xEA: |
927 | 377 | case 0xEB: |
928 | 400 | case 0xEC: |
929 | 415 | case 0xED: |
930 | 434 | case 0xEE: |
931 | 453 | case 0xEF: |
932 | 453 | return to_status(EncodeAPP(jpg, marker, state)); |
933 | | |
934 | 13 | case 0xFE: |
935 | 13 | return to_status(EncodeCOM(jpg, state)); |
936 | | |
937 | 53 | case 0xFF: |
938 | 53 | return to_status(EncodeInterMarkerData(jpg, state)); |
939 | | |
940 | 251 | default: |
941 | 251 | return SerializationStatus::ERROR; |
942 | 68.5k | } |
943 | 68.5k | } |
944 | | |
945 | | void PushOutput(std::deque<OutputChunk>* in, size_t* available_out, |
946 | 78.9k | uint8_t** next_out) { |
947 | 151k | while (*available_out > 0) { |
948 | | // No more data. |
949 | 150k | if (in->empty()) return; |
950 | 72.2k | OutputChunk& chunk = in->front(); |
951 | 72.2k | size_t to_copy = std::min(*available_out, chunk.len); |
952 | 72.2k | if (to_copy > 0) { |
953 | 71.5k | memcpy(*next_out, chunk.next, to_copy); |
954 | 71.5k | *next_out += to_copy; |
955 | 71.5k | *available_out -= to_copy; |
956 | 71.5k | chunk.next += to_copy; |
957 | 71.5k | chunk.len -= to_copy; |
958 | 71.5k | } |
959 | 72.2k | if (chunk.len == 0) in->pop_front(); |
960 | 72.2k | } |
961 | 78.9k | } |
962 | | |
963 | | } // namespace |
964 | | |
965 | | // Adaptor for old API users. Will be removed once new API will support proper |
966 | | // streaming serialization. |
967 | 9.27k | bool WriteJpeg(const JPEGData& jpg, JPEGOutput out) { |
968 | 9.27k | State state; |
969 | 9.27k | state.stage = Stage::DONE; |
970 | 9.27k | std::vector<uint8_t> buffer(16384); |
971 | 9.61k | while (true) { |
972 | 9.61k | uint8_t* next_out = buffer.data(); |
973 | 9.61k | size_t available_out = buffer.size(); |
974 | 9.61k | SerializationStatus status = |
975 | 9.61k | SerializeJpeg(&state, jpg, &available_out, &next_out); |
976 | 9.61k | if (status != SerializationStatus::DONE && |
977 | 8.84k | status != SerializationStatus::NEEDS_MORE_OUTPUT) { |
978 | 8.49k | return false; |
979 | 8.49k | } |
980 | 1.11k | size_t to_write = buffer.size() - available_out; |
981 | 1.11k | if (!out.Write(buffer.data(), to_write)) return false; |
982 | 1.11k | if (status == SerializationStatus::DONE) return true; |
983 | 1.11k | } |
984 | 9.27k | } |
985 | | |
986 | | namespace internal { |
987 | | namespace dec { |
988 | | SerializationStatus SerializeJpeg(State* state, const JPEGData& jpg, |
989 | 9.61k | size_t* available_out, uint8_t** next_out) { |
990 | 9.61k | SerializationState& ss = state->internal->serialization; |
991 | | |
992 | 78.9k | const auto maybe_push_output = [&]() { |
993 | 78.9k | if (ss.stage != SerializationState::ERROR) { |
994 | 78.9k | PushOutput(&ss.output_queue, available_out, next_out); |
995 | 78.9k | } |
996 | 78.9k | }; |
997 | | |
998 | | // Push remaining output from prevoius session. |
999 | 9.61k | maybe_push_output(); |
1000 | | |
1001 | 88.2k | while (true) { |
1002 | 88.2k | switch (ss.stage) { |
1003 | 9.27k | case SerializationState::INIT: { |
1004 | | // If parsing is complete, serialization is possible. |
1005 | 9.27k | bool can_start_serialization = (state->stage == Stage::DONE); |
1006 | | // Parsing of AC/DC has started; i.e. quant/huffman/metadata is ready |
1007 | | // to be used. |
1008 | 9.27k | if (HasSection(state, kBrunsliDCDataTag) || |
1009 | 9.27k | HasSection(state, kBrunsliACDataTag)) { |
1010 | 0 | can_start_serialization = true; |
1011 | 0 | } |
1012 | 9.27k | if (!can_start_serialization) { |
1013 | 0 | return SerializationStatus::NEEDS_MORE_INPUT; |
1014 | 0 | } |
1015 | | // JpegBypass is a very simple / special case. |
1016 | 9.27k | if (jpg.version == kFallbackVersion) { |
1017 | 24 | if (jpg.original_jpg == nullptr) { |
1018 | 3 | ss.stage = SerializationState::ERROR; |
1019 | 3 | break; |
1020 | 3 | } |
1021 | | // TODO(eustas): investigate if bad things can happen when complete |
1022 | | // file is passed to parser, but it is impossible to |
1023 | | // push complete output. |
1024 | 21 | ss.output_queue.emplace_back(jpg.original_jpg, jpg.original_jpg_size); |
1025 | 21 | ss.stage = SerializationState::DONE; |
1026 | 21 | break; |
1027 | 24 | } |
1028 | | |
1029 | | // Invalid mode - fallback + something else. |
1030 | 9.24k | if ((jpg.version & 1) == kFallbackVersion) { |
1031 | 0 | ss.stage = SerializationState::ERROR; |
1032 | 0 | break; |
1033 | 0 | } |
1034 | | |
1035 | | // Valid Brunsli requires, at least, 0xD9 marker. |
1036 | | // This might happen on corrupted stream, or on unconditioned JPEGData. |
1037 | | // TODO(eustas): check D9 in the only one and is the last one. |
1038 | 9.24k | if (jpg.marker_order.empty()) { |
1039 | 0 | ss.stage = SerializationState::ERROR; |
1040 | 0 | break; |
1041 | 0 | } |
1042 | | |
1043 | 9.24k | ss.dc_huff_table.resize(kMaxHuffmanTables); |
1044 | 9.24k | ss.ac_huff_table.resize(kMaxHuffmanTables); |
1045 | 9.24k | if (jpg.has_zero_padding_bit) { |
1046 | 492 | ss.pad_bits = jpg.padding_bits.data(); |
1047 | 492 | ss.pad_bits_end = ss.pad_bits + jpg.padding_bits.size(); |
1048 | 492 | } |
1049 | | |
1050 | 9.24k | EncodeSOI(&ss); |
1051 | 9.24k | maybe_push_output(); |
1052 | 9.24k | ss.stage = SerializationState::SERIALIZE_SECTION; |
1053 | 9.24k | break; |
1054 | 9.24k | } |
1055 | | |
1056 | 69.3k | case SerializationState::SERIALIZE_SECTION: { |
1057 | 69.3k | if (ss.section_index >= jpg.marker_order.size()) { |
1058 | 754 | ss.stage = SerializationState::DONE; |
1059 | 754 | break; |
1060 | 754 | } |
1061 | 68.5k | uint8_t marker = jpg.marker_order[ss.section_index]; |
1062 | 68.5k | SerializationStatus status = SerializeSection(marker, *state, &ss, jpg); |
1063 | 68.5k | if (status == SerializationStatus::ERROR) { |
1064 | 8.49k | BRUNSLI_LOG_DEBUG() << "Failed to encode marker " << std::hex |
1065 | 0 | << marker << BRUNSLI_ENDL(); |
1066 | 8.49k | ss.stage = SerializationState::ERROR; |
1067 | 8.49k | break; |
1068 | 8.49k | } |
1069 | 60.0k | maybe_push_output(); |
1070 | 60.0k | if (status == SerializationStatus::NEEDS_MORE_INPUT) { |
1071 | 0 | return SerializationStatus::NEEDS_MORE_INPUT; |
1072 | 60.0k | } else if (status != SerializationStatus::DONE) { |
1073 | 0 | BRUNSLI_DCHECK(false); |
1074 | 0 | ss.stage = SerializationState::ERROR; |
1075 | 0 | break; |
1076 | 0 | } |
1077 | 60.0k | ++ss.section_index; |
1078 | 60.0k | break; |
1079 | 60.0k | } |
1080 | | |
1081 | 1.11k | case SerializationState::DONE: { |
1082 | 1.11k | if (!ss.output_queue.empty()) { |
1083 | 344 | return SerializationStatus::NEEDS_MORE_OUTPUT; |
1084 | 775 | } else { |
1085 | 775 | return SerializationStatus::DONE; |
1086 | 775 | } |
1087 | 1.11k | } |
1088 | | |
1089 | 8.49k | default: |
1090 | 8.49k | return SerializationStatus::ERROR; |
1091 | 88.2k | } |
1092 | 88.2k | } |
1093 | 9.61k | } |
1094 | | } // namespace dec |
1095 | | } // namespace internal |
1096 | | |
1097 | | } // namespace brunsli |