bitstream.cc (15335B)
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 #include "lib/jpegli/bitstream.h" 7 8 #include <cmath> 9 10 #include "lib/jpegli/bit_writer.h" 11 #include "lib/jpegli/error.h" 12 #include "lib/jpegli/memory_manager.h" 13 14 namespace jpegli { 15 16 void WriteOutput(j_compress_ptr cinfo, const uint8_t* buf, size_t bufsize) { 17 size_t pos = 0; 18 while (pos < bufsize) { 19 if (cinfo->dest->free_in_buffer == 0 && 20 !(*cinfo->dest->empty_output_buffer)(cinfo)) { 21 JPEGLI_ERROR("Destination suspension is not supported in markers."); 22 } 23 size_t len = std::min<size_t>(cinfo->dest->free_in_buffer, bufsize - pos); 24 memcpy(cinfo->dest->next_output_byte, buf + pos, len); 25 pos += len; 26 cinfo->dest->free_in_buffer -= len; 27 cinfo->dest->next_output_byte += len; 28 } 29 } 30 31 void WriteOutput(j_compress_ptr cinfo, const std::vector<uint8_t>& bytes) { 32 WriteOutput(cinfo, bytes.data(), bytes.size()); 33 } 34 35 void WriteOutput(j_compress_ptr cinfo, std::initializer_list<uint8_t> bytes) { 36 WriteOutput(cinfo, bytes.begin(), bytes.size()); 37 } 38 39 void EncodeAPP0(j_compress_ptr cinfo) { 40 WriteOutput(cinfo, 41 {0xff, 0xe0, 0, 16, 'J', 'F', 'I', 'F', '\0', 42 cinfo->JFIF_major_version, cinfo->JFIF_minor_version, 43 cinfo->density_unit, static_cast<uint8_t>(cinfo->X_density >> 8), 44 static_cast<uint8_t>(cinfo->X_density & 0xff), 45 static_cast<uint8_t>(cinfo->Y_density >> 8), 46 static_cast<uint8_t>(cinfo->Y_density & 0xff), 0, 0}); 47 } 48 49 void EncodeAPP14(j_compress_ptr cinfo) { 50 uint8_t color_transform = cinfo->jpeg_color_space == JCS_YCbCr ? 1 51 : cinfo->jpeg_color_space == JCS_YCCK ? 2 52 : 0; 53 WriteOutput(cinfo, {0xff, 0xee, 0, 14, 'A', 'd', 'o', 'b', 'e', 0, 100, 0, 0, 54 0, 0, color_transform}); 55 } 56 57 void WriteFileHeader(j_compress_ptr cinfo) { 58 WriteOutput(cinfo, {0xFF, 0xD8}); // SOI 59 if (cinfo->write_JFIF_header) { 60 EncodeAPP0(cinfo); 61 } 62 if (cinfo->write_Adobe_marker) { 63 EncodeAPP14(cinfo); 64 } 65 } 66 67 bool EncodeDQT(j_compress_ptr cinfo, bool write_all_tables) { 68 uint8_t data[4 + NUM_QUANT_TBLS * (1 + 2 * DCTSIZE2)]; // 520 bytes 69 size_t pos = 0; 70 data[pos++] = 0xFF; 71 data[pos++] = 0xDB; 72 pos += 2; // Length will be filled in later. 73 74 int send_table[NUM_QUANT_TBLS] = {}; 75 if (write_all_tables) { 76 for (int i = 0; i < NUM_QUANT_TBLS; ++i) { 77 if (cinfo->quant_tbl_ptrs[i]) send_table[i] = 1; 78 } 79 } else { 80 for (int c = 0; c < cinfo->num_components; ++c) { 81 send_table[cinfo->comp_info[c].quant_tbl_no] = 1; 82 } 83 } 84 85 bool is_baseline = true; 86 for (int i = 0; i < NUM_QUANT_TBLS; ++i) { 87 if (!send_table[i]) continue; 88 JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[i]; 89 if (quant_table == nullptr) { 90 JPEGLI_ERROR("Missing quant table %d", i); 91 } 92 int precision = 0; 93 for (UINT16 q : quant_table->quantval) { 94 if (q > 255) { 95 precision = 1; 96 is_baseline = false; 97 } 98 } 99 if (quant_table->sent_table) { 100 continue; 101 } 102 data[pos++] = (precision << 4) + i; 103 for (size_t j = 0; j < DCTSIZE2; ++j) { 104 int val_idx = kJPEGNaturalOrder[j]; 105 int val = quant_table->quantval[val_idx]; 106 if (val == 0) { 107 JPEGLI_ERROR("Invalid quantval 0."); 108 } 109 if (precision) { 110 data[pos++] = val >> 8; 111 } 112 data[pos++] = val & 0xFFu; 113 } 114 quant_table->sent_table = TRUE; 115 } 116 if (pos > 4) { 117 data[2] = (pos - 2) >> 8u; 118 data[3] = (pos - 2) & 0xFFu; 119 WriteOutput(cinfo, data, pos); 120 } 121 return is_baseline; 122 } 123 124 void EncodeSOF(j_compress_ptr cinfo, bool is_baseline) { 125 if (cinfo->data_precision != kJpegPrecision) { 126 JPEGLI_ERROR("Unsupported data precision %d", cinfo->data_precision); 127 } 128 const uint8_t marker = cinfo->progressive_mode ? 0xc2 129 : is_baseline ? 0xc0 130 : 0xc1; 131 const size_t n_comps = cinfo->num_components; 132 const size_t marker_len = 8 + 3 * n_comps; 133 std::vector<uint8_t> data(marker_len + 2); 134 size_t pos = 0; 135 data[pos++] = 0xFF; 136 data[pos++] = marker; 137 data[pos++] = marker_len >> 8u; 138 data[pos++] = marker_len & 0xFFu; 139 data[pos++] = kJpegPrecision; 140 data[pos++] = cinfo->image_height >> 8u; 141 data[pos++] = cinfo->image_height & 0xFFu; 142 data[pos++] = cinfo->image_width >> 8u; 143 data[pos++] = cinfo->image_width & 0xFFu; 144 data[pos++] = n_comps; 145 for (size_t i = 0; i < n_comps; ++i) { 146 jpeg_component_info* comp = &cinfo->comp_info[i]; 147 data[pos++] = comp->component_id; 148 data[pos++] = ((comp->h_samp_factor << 4u) | (comp->v_samp_factor)); 149 const uint32_t quant_idx = comp->quant_tbl_no; 150 if (cinfo->quant_tbl_ptrs[quant_idx] == nullptr) { 151 JPEGLI_ERROR("Invalid component quant table index %u.", quant_idx); 152 } 153 data[pos++] = quant_idx; 154 } 155 WriteOutput(cinfo, data); 156 } 157 158 void WriteFrameHeader(j_compress_ptr cinfo) { 159 jpeg_comp_master* m = cinfo->master; 160 bool is_baseline = EncodeDQT(cinfo, /*write_all_tables=*/false); 161 if (cinfo->progressive_mode || cinfo->arith_code || 162 cinfo->data_precision != 8) { 163 is_baseline = false; 164 } 165 for (size_t i = 0; i < m->num_huffman_tables; ++i) { 166 int slot_id = m->slot_id_map[i]; 167 if (slot_id > 0x11 || (slot_id > 0x01 && slot_id < 0x10)) { 168 is_baseline = false; 169 } 170 } 171 EncodeSOF(cinfo, is_baseline); 172 } 173 174 void EncodeDRI(j_compress_ptr cinfo) { 175 WriteOutput(cinfo, {0xFF, 0xDD, 0, 4, 176 static_cast<uint8_t>(cinfo->restart_interval >> 8), 177 static_cast<uint8_t>(cinfo->restart_interval & 0xFF)}); 178 } 179 180 void EncodeDHT(j_compress_ptr cinfo, size_t offset, size_t num) { 181 jpeg_comp_master* m = cinfo->master; 182 size_t marker_len = 2; 183 for (size_t i = 0; i < num; ++i) { 184 const JHUFF_TBL& table = m->huffman_tables[offset + i]; 185 if (table.sent_table) continue; 186 marker_len += kJpegHuffmanMaxBitLength + 1; 187 for (size_t j = 0; j <= kJpegHuffmanMaxBitLength; ++j) { 188 marker_len += table.bits[j]; 189 } 190 } 191 std::vector<uint8_t> data(marker_len + 2); 192 size_t pos = 0; 193 data[pos++] = 0xFF; 194 data[pos++] = 0xC4; 195 data[pos++] = marker_len >> 8u; 196 data[pos++] = marker_len & 0xFFu; 197 for (size_t i = 0; i < num; ++i) { 198 const JHUFF_TBL& table = m->huffman_tables[offset + i]; 199 if (table.sent_table) continue; 200 size_t total_count = 0; 201 for (size_t i = 0; i <= kJpegHuffmanMaxBitLength; ++i) { 202 total_count += table.bits[i]; 203 } 204 data[pos++] = m->slot_id_map[offset + i]; 205 for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) { 206 data[pos++] = table.bits[i]; 207 } 208 for (size_t i = 0; i < total_count; ++i) { 209 data[pos++] = table.huffval[i]; 210 } 211 } 212 if (marker_len > 2) { 213 WriteOutput(cinfo, data); 214 } 215 } 216 217 void EncodeSOS(j_compress_ptr cinfo, int scan_index) { 218 jpeg_comp_master* m = cinfo->master; 219 const jpeg_scan_info* scan_info = &cinfo->scan_info[scan_index]; 220 const size_t marker_len = 6 + 2 * scan_info->comps_in_scan; 221 std::vector<uint8_t> data(marker_len + 2); 222 size_t pos = 0; 223 data[pos++] = 0xFF; 224 data[pos++] = 0xDA; 225 data[pos++] = marker_len >> 8u; 226 data[pos++] = marker_len & 0xFFu; 227 data[pos++] = scan_info->comps_in_scan; 228 for (int i = 0; i < scan_info->comps_in_scan; ++i) { 229 int comp_idx = scan_info->component_index[i]; 230 data[pos++] = cinfo->comp_info[comp_idx].component_id; 231 int dc_slot_id = m->slot_id_map[m->context_map[comp_idx]]; 232 int ac_context = m->ac_ctx_offset[scan_index] + i; 233 int ac_slot_id = m->slot_id_map[m->context_map[ac_context]]; 234 data[pos++] = (dc_slot_id << 4u) + (ac_slot_id - 16); 235 } 236 data[pos++] = scan_info->Ss; 237 data[pos++] = scan_info->Se; 238 data[pos++] = ((scan_info->Ah << 4u) | (scan_info->Al)); 239 WriteOutput(cinfo, data); 240 } 241 242 void WriteScanHeader(j_compress_ptr cinfo, int scan_index) { 243 jpeg_comp_master* m = cinfo->master; 244 const jpeg_scan_info* scan_info = &cinfo->scan_info[scan_index]; 245 cinfo->restart_interval = m->scan_token_info[scan_index].restart_interval; 246 if (cinfo->restart_interval != m->last_restart_interval) { 247 EncodeDRI(cinfo); 248 m->last_restart_interval = cinfo->restart_interval; 249 } 250 size_t num_dht = 0; 251 if (scan_index == 0) { 252 // For the first scan we emit all DC and at most 4 AC Huffman codes. 253 for (size_t i = 0, num_ac = 0; i < m->num_huffman_tables; ++i) { 254 if (m->slot_id_map[i] >= 16 && num_ac++ >= 4) break; 255 ++num_dht; 256 } 257 } else if (scan_info->Ss > 0) { 258 // For multi-scan sequential and progressive DC scans we have already 259 // emitted all Huffman codes that we need before the first scan. For 260 // progressive AC scans we only need at most one new Huffman code. 261 if (m->context_map[m->ac_ctx_offset[scan_index]] == m->next_dht_index) { 262 num_dht = 1; 263 } 264 } 265 if (num_dht > 0) { 266 EncodeDHT(cinfo, m->next_dht_index, num_dht); 267 m->next_dht_index += num_dht; 268 } 269 EncodeSOS(cinfo, scan_index); 270 } 271 272 void WriteBlock(const int32_t* JXL_RESTRICT symbols, 273 const int32_t* JXL_RESTRICT extra_bits, const int num_nonzeros, 274 const bool emit_eob, 275 const HuffmanCodeTable* JXL_RESTRICT dc_code, 276 const HuffmanCodeTable* JXL_RESTRICT ac_code, 277 JpegBitWriter* JXL_RESTRICT bw) { 278 int symbol = symbols[0]; 279 WriteBits(bw, dc_code->depth[symbol], dc_code->code[symbol] | extra_bits[0]); 280 for (int i = 1; i < num_nonzeros; ++i) { 281 symbol = symbols[i]; 282 if (symbol > 255) { 283 WriteBits(bw, ac_code->depth[0xf0], ac_code->code[0xf0]); 284 symbol -= 256; 285 if (symbol > 255) { 286 WriteBits(bw, ac_code->depth[0xf0], ac_code->code[0xf0]); 287 symbol -= 256; 288 if (symbol > 255) { 289 WriteBits(bw, ac_code->depth[0xf0], ac_code->code[0xf0]); 290 symbol -= 256; 291 } 292 } 293 } 294 WriteBits(bw, ac_code->depth[symbol], 295 ac_code->code[symbol] | extra_bits[i]); 296 } 297 if (emit_eob) { 298 WriteBits(bw, ac_code->depth[0], ac_code->code[0]); 299 } 300 } 301 302 namespace { 303 304 JXL_INLINE void EmitMarker(JpegBitWriter* bw, int marker) { 305 bw->data[bw->pos++] = 0xFF; 306 bw->data[bw->pos++] = marker; 307 } 308 309 void WriteTokens(j_compress_ptr cinfo, int scan_index, JpegBitWriter* bw) { 310 jpeg_comp_master* m = cinfo->master; 311 HuffmanCodeTable* coding_tables = &m->coding_tables[0]; 312 int next_restart_marker = 0; 313 const ScanTokenInfo& sti = m->scan_token_info[scan_index]; 314 size_t num_token_arrays = m->cur_token_array + 1; 315 size_t total_tokens = 0; 316 size_t restart_idx = 0; 317 size_t next_restart = sti.restarts[restart_idx]; 318 uint8_t* context_map = m->context_map; 319 for (size_t i = 0; i < num_token_arrays; ++i) { 320 Token* tokens = m->token_arrays[i].tokens; 321 size_t num_tokens = m->token_arrays[i].num_tokens; 322 if (sti.token_offset < total_tokens + num_tokens && 323 total_tokens < sti.token_offset + sti.num_tokens) { 324 size_t start_ix = 325 total_tokens < sti.token_offset ? sti.token_offset - total_tokens : 0; 326 size_t end_ix = std::min(sti.token_offset + sti.num_tokens - total_tokens, 327 num_tokens); 328 size_t cycle_len = bw->len / 8; 329 size_t next_cycle = cycle_len; 330 for (size_t i = start_ix; i < end_ix; ++i) { 331 if (total_tokens + i == next_restart) { 332 JumpToByteBoundary(bw); 333 EmitMarker(bw, 0xD0 + next_restart_marker); 334 next_restart_marker += 1; 335 next_restart_marker &= 0x7; 336 next_restart = sti.restarts[++restart_idx]; 337 } 338 Token t = tokens[i]; 339 const HuffmanCodeTable* code = &coding_tables[context_map[t.context]]; 340 WriteBits(bw, code->depth[t.symbol], code->code[t.symbol] | t.bits); 341 if (--next_cycle == 0) { 342 if (!EmptyBitWriterBuffer(bw)) { 343 JPEGLI_ERROR( 344 "Output suspension is not supported in " 345 "finish_compress"); 346 } 347 next_cycle = cycle_len; 348 } 349 } 350 } 351 total_tokens += num_tokens; 352 } 353 } 354 355 void WriteACRefinementTokens(j_compress_ptr cinfo, int scan_index, 356 JpegBitWriter* bw) { 357 jpeg_comp_master* m = cinfo->master; 358 const ScanTokenInfo& sti = m->scan_token_info[scan_index]; 359 const uint8_t context = m->ac_ctx_offset[scan_index]; 360 const HuffmanCodeTable* code = &m->coding_tables[m->context_map[context]]; 361 size_t cycle_len = bw->len / 64; 362 size_t next_cycle = cycle_len; 363 size_t refbit_idx = 0; 364 size_t eobrun_idx = 0; 365 size_t restart_idx = 0; 366 size_t next_restart = sti.restarts[restart_idx]; 367 int next_restart_marker = 0; 368 for (size_t i = 0; i < sti.num_tokens; ++i) { 369 if (i == next_restart) { 370 JumpToByteBoundary(bw); 371 EmitMarker(bw, 0xD0 + next_restart_marker); 372 next_restart_marker += 1; 373 next_restart_marker &= 0x7; 374 next_restart = sti.restarts[++restart_idx]; 375 } 376 RefToken t = sti.tokens[i]; 377 int symbol = t.symbol & 253; 378 uint16_t bits = 0; 379 if ((symbol & 1) == 0) { 380 int r = symbol >> 4; 381 if (r > 0 && r < 15) { 382 bits = sti.eobruns[eobrun_idx++]; 383 } 384 } else { 385 bits = (t.symbol >> 1) & 1; 386 } 387 WriteBits(bw, code->depth[symbol], code->code[symbol] | bits); 388 for (int j = 0; j < t.refbits; ++j) { 389 WriteBits(bw, 1, sti.refbits[refbit_idx++]); 390 } 391 if (--next_cycle == 0) { 392 if (!EmptyBitWriterBuffer(bw)) { 393 JPEGLI_ERROR("Output suspension is not supported in finish_compress"); 394 } 395 next_cycle = cycle_len; 396 } 397 } 398 } 399 400 void WriteDCRefinementBits(j_compress_ptr cinfo, int scan_index, 401 JpegBitWriter* bw) { 402 jpeg_comp_master* m = cinfo->master; 403 const ScanTokenInfo& sti = m->scan_token_info[scan_index]; 404 size_t restart_idx = 0; 405 size_t next_restart = sti.restarts[restart_idx]; 406 int next_restart_marker = 0; 407 size_t cycle_len = bw->len * 4; 408 size_t next_cycle = cycle_len; 409 size_t refbit_idx = 0; 410 for (size_t i = 0; i < sti.num_tokens; ++i) { 411 if (i == next_restart) { 412 JumpToByteBoundary(bw); 413 EmitMarker(bw, 0xD0 + next_restart_marker); 414 next_restart_marker += 1; 415 next_restart_marker &= 0x7; 416 next_restart = sti.restarts[++restart_idx]; 417 } 418 WriteBits(bw, 1, sti.refbits[refbit_idx++]); 419 if (--next_cycle == 0) { 420 if (!EmptyBitWriterBuffer(bw)) { 421 JPEGLI_ERROR( 422 "Output suspension is not supported in " 423 "finish_compress"); 424 } 425 next_cycle = cycle_len; 426 } 427 } 428 } 429 430 } // namespace 431 432 void WriteScanData(j_compress_ptr cinfo, int scan_index) { 433 const jpeg_scan_info* scan_info = &cinfo->scan_info[scan_index]; 434 JpegBitWriter* bw = &cinfo->master->bw; 435 if (scan_info->Ah == 0) { 436 WriteTokens(cinfo, scan_index, bw); 437 } else if (scan_info->Ss > 0) { 438 WriteACRefinementTokens(cinfo, scan_index, bw); 439 } else { 440 WriteDCRefinementBits(cinfo, scan_index, bw); 441 } 442 if (!bw->healthy) { 443 JPEGLI_ERROR("Unknown Huffman coded symbol found in scan %d", scan_index); 444 } 445 JumpToByteBoundary(bw); 446 if (!EmptyBitWriterBuffer(bw)) { 447 JPEGLI_ERROR("Output suspension is not supported in finish_compress"); 448 } 449 } 450 451 } // namespace jpegli