summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jpegli/bit_writer.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jpegli/bit_writer.h')
-rw-r--r--third_party/jpeg-xl/lib/jpegli/bit_writer.h107
1 files changed, 107 insertions, 0 deletions
diff --git a/third_party/jpeg-xl/lib/jpegli/bit_writer.h b/third_party/jpeg-xl/lib/jpegli/bit_writer.h
new file mode 100644
index 0000000000..0affcdabd3
--- /dev/null
+++ b/third_party/jpeg-xl/lib/jpegli/bit_writer.h
@@ -0,0 +1,107 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef LIB_JPEGLI_BIT_WRITER_H_
+#define LIB_JPEGLI_BIT_WRITER_H_
+
+/* clang-format off */
+#include <stdio.h>
+#include <jpeglib.h>
+#include <stdint.h>
+#include <string.h>
+/* clang-format on */
+
+#include "lib/jxl/base/compiler_specific.h"
+
+namespace jpegli {
+
+// Handles the packing of bits into output bytes.
+struct JpegBitWriter {
+ j_compress_ptr cinfo;
+ uint8_t* data;
+ size_t len;
+ size_t pos;
+ size_t output_pos;
+ uint64_t put_buffer;
+ int free_bits;
+ bool healthy;
+};
+
+void JpegBitWriterInit(j_compress_ptr cinfo);
+
+bool EmptyBitWriterBuffer(JpegBitWriter* bw);
+
+void JumpToByteBoundary(JpegBitWriter* bw);
+
+// Returns non-zero if and only if x has a zero byte, i.e. one of
+// x & 0xff, x & 0xff00, ..., x & 0xff00000000000000 is zero.
+static JXL_INLINE uint64_t HasZeroByte(uint64_t x) {
+ return (x - 0x0101010101010101ULL) & ~x & 0x8080808080808080ULL;
+}
+
+/**
+ * Writes the given byte to the output, writes an extra zero if byte is 0xFF.
+ *
+ * This method is "careless" - caller must make sure that there is enough
+ * space in the output buffer. Emits up to 2 bytes to buffer.
+ */
+static JXL_INLINE void EmitByte(JpegBitWriter* bw, int byte) {
+ bw->data[bw->pos++] = byte;
+ if (byte == 0xFF) bw->data[bw->pos++] = 0;
+}
+
+static JXL_INLINE void DischargeBitBuffer(JpegBitWriter* bw) {
+ // At this point we are ready to emit the bytes of put_buffer to the output.
+ // The JPEG format requires that after every 0xff byte in the entropy
+ // coded section, there is a zero byte, therefore we first check if any of
+ // the bytes of put_buffer is 0xFF.
+ if (HasZeroByte(~bw->put_buffer)) {
+ // We have a 0xFF byte somewhere, examine each byte and append a zero
+ // byte if necessary.
+ EmitByte(bw, (bw->put_buffer >> 56) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 48) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 40) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 32) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 24) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 16) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 8) & 0xFF);
+ EmitByte(bw, (bw->put_buffer >> 0) & 0xFF);
+ } else {
+ // We don't have any 0xFF bytes, output all 6 bytes without checking.
+ bw->data[bw->pos] = (bw->put_buffer >> 56) & 0xFF;
+ bw->data[bw->pos + 1] = (bw->put_buffer >> 48) & 0xFF;
+ bw->data[bw->pos + 2] = (bw->put_buffer >> 40) & 0xFF;
+ bw->data[bw->pos + 3] = (bw->put_buffer >> 32) & 0xFF;
+ bw->data[bw->pos + 4] = (bw->put_buffer >> 24) & 0xFF;
+ bw->data[bw->pos + 5] = (bw->put_buffer >> 16) & 0xFF;
+ bw->data[bw->pos + 6] = (bw->put_buffer >> 8) & 0xFF;
+ bw->data[bw->pos + 7] = (bw->put_buffer >> 0) & 0xFF;
+ bw->pos += 8;
+ }
+}
+
+static JXL_INLINE void WriteBits(JpegBitWriter* bw, int nbits, uint64_t bits) {
+ // This is an optimization; if everything goes well,
+ // then |nbits| is positive; if non-existing Huffman symbol is going to be
+ // encoded, its length should be zero; later encoder could check the
+ // "health" of JpegBitWriter.
+ if (nbits == 0) {
+ bw->healthy = false;
+ return;
+ }
+ bw->free_bits -= nbits;
+ if (bw->free_bits < 0) {
+ bw->put_buffer <<= (bw->free_bits + nbits);
+ bw->put_buffer |= (bits >> -bw->free_bits);
+ DischargeBitBuffer(bw);
+ bw->free_bits += 64;
+ bw->put_buffer = nbits;
+ }
+ bw->put_buffer <<= nbits;
+ bw->put_buffer |= bits;
+}
+
+} // namespace jpegli
+#endif // LIB_JPEGLI_BIT_WRITER_H_