/src/libjxl/lib/jpegli/bit_writer.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #ifndef LIB_JPEGLI_BIT_WRITER_H_ |
7 | | #define LIB_JPEGLI_BIT_WRITER_H_ |
8 | | |
9 | | #include <stdint.h> |
10 | | #include <string.h> |
11 | | |
12 | | #include "lib/jpegli/common.h" |
13 | | #include "lib/jxl/base/byte_order.h" |
14 | | #include "lib/jxl/base/compiler_specific.h" |
15 | | |
16 | | namespace jpegli { |
17 | | |
18 | | // Handles the packing of bits into output bytes. |
19 | | struct JpegBitWriter { |
20 | | j_compress_ptr cinfo; |
21 | | uint8_t* data; |
22 | | size_t len; |
23 | | size_t pos; |
24 | | size_t output_pos; |
25 | | uint64_t put_buffer; |
26 | | int free_bits; |
27 | | bool healthy; |
28 | | }; |
29 | | |
30 | | void JpegBitWriterInit(j_compress_ptr cinfo); |
31 | | |
32 | | bool EmptyBitWriterBuffer(JpegBitWriter* bw); |
33 | | |
34 | | void JumpToByteBoundary(JpegBitWriter* bw); |
35 | | |
36 | | // Returns non-zero if and only if x has a zero byte, i.e. one of |
37 | | // x & 0xff, x & 0xff00, ..., x & 0xff00000000000000 is zero. |
38 | 0 | static JXL_INLINE uint64_t HasZeroByte(uint64_t x) { |
39 | 0 | return (x - 0x0101010101010101ULL) & ~x & 0x8080808080808080ULL; |
40 | 0 | } Unexecuted instantiation: common.cc:jpegli::HasZeroByte(unsigned long) Unexecuted instantiation: color_transform.cc:jpegli::HasZeroByte(unsigned long) |
41 | | |
42 | | /** |
43 | | * Writes the given byte to the output, writes an extra zero if byte is 0xFF. |
44 | | * |
45 | | * This method is "careless" - caller must make sure that there is enough |
46 | | * space in the output buffer. Emits up to 2 bytes to buffer. |
47 | | */ |
48 | 0 | static JXL_INLINE void EmitByte(JpegBitWriter* bw, int byte) { |
49 | 0 | bw->data[bw->pos++] = byte; |
50 | 0 | if (byte == 0xFF) bw->data[bw->pos++] = 0; |
51 | 0 | } Unexecuted instantiation: common.cc:jpegli::EmitByte(jpegli::JpegBitWriter*, int) Unexecuted instantiation: color_transform.cc:jpegli::EmitByte(jpegli::JpegBitWriter*, int) |
52 | | |
53 | 0 | static JXL_INLINE void DischargeBitBuffer(JpegBitWriter* bw) { |
54 | 0 | // At this point we are ready to emit the bytes of put_buffer to the output. |
55 | 0 | // The JPEG format requires that after every 0xff byte in the entropy |
56 | 0 | // coded section, there is a zero byte, therefore we first check if any of |
57 | 0 | // the bytes of put_buffer is 0xFF. |
58 | 0 | if (HasZeroByte(~bw->put_buffer)) { |
59 | 0 | // We have a 0xFF byte somewhere, examine each byte and append a zero |
60 | 0 | // byte if necessary. |
61 | 0 | EmitByte(bw, (bw->put_buffer >> 56) & 0xFF); |
62 | 0 | EmitByte(bw, (bw->put_buffer >> 48) & 0xFF); |
63 | 0 | EmitByte(bw, (bw->put_buffer >> 40) & 0xFF); |
64 | 0 | EmitByte(bw, (bw->put_buffer >> 32) & 0xFF); |
65 | 0 | EmitByte(bw, (bw->put_buffer >> 24) & 0xFF); |
66 | 0 | EmitByte(bw, (bw->put_buffer >> 16) & 0xFF); |
67 | 0 | EmitByte(bw, (bw->put_buffer >> 8) & 0xFF); |
68 | 0 | EmitByte(bw, (bw->put_buffer >> 0) & 0xFF); |
69 | 0 | } else { |
70 | 0 | // We don't have any 0xFF bytes, output all 8 bytes without checking. |
71 | 0 | StoreBE64(bw->put_buffer, bw->data + bw->pos); |
72 | 0 | bw->pos += 8; |
73 | 0 | } |
74 | 0 | } Unexecuted instantiation: common.cc:jpegli::DischargeBitBuffer(jpegli::JpegBitWriter*) Unexecuted instantiation: color_transform.cc:jpegli::DischargeBitBuffer(jpegli::JpegBitWriter*) |
75 | | |
76 | 0 | static JXL_INLINE void WriteBits(JpegBitWriter* bw, int nbits, uint64_t bits) { |
77 | 0 | // This is an optimization; if everything goes well, |
78 | 0 | // then |nbits| is positive; if non-existing Huffman symbol is going to be |
79 | 0 | // encoded, its length should be zero; later encoder could check the |
80 | 0 | // "health" of JpegBitWriter. |
81 | 0 | if (nbits == 0) { |
82 | 0 | bw->healthy = false; |
83 | 0 | return; |
84 | 0 | } |
85 | 0 | bw->free_bits -= nbits; |
86 | 0 | if (bw->free_bits < 0) { |
87 | 0 | bw->put_buffer <<= (bw->free_bits + nbits); |
88 | 0 | bw->put_buffer |= (bits >> -bw->free_bits); |
89 | 0 | DischargeBitBuffer(bw); |
90 | 0 | bw->free_bits += 64; |
91 | 0 | bw->put_buffer = nbits; |
92 | 0 | } |
93 | 0 | bw->put_buffer <<= nbits; |
94 | 0 | bw->put_buffer |= bits; |
95 | 0 | } Unexecuted instantiation: common.cc:jpegli::WriteBits(jpegli::JpegBitWriter*, int, unsigned long) Unexecuted instantiation: color_transform.cc:jpegli::WriteBits(jpegli::JpegBitWriter*, int, unsigned long) |
96 | | |
97 | | } // namespace jpegli |
98 | | #endif // LIB_JPEGLI_BIT_WRITER_H_ |