// 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. use crate::{ bit_reader::BitReader, entropy_coding::{context_map::*, decode::unpack_signed}, error::{Error, Result}, frame::coeff_order::NUM_ORDERS, util::ShiftRightCeil, }; pub const NON_ZERO_BUCKETS: usize = 37; pub const ZERO_DENSITY_CONTEXT_COUNT: usize = 458; pub const COEFF_FREQ_CONTEXT: [usize; 64] = [ 0xBAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, ]; pub const COEFF_NUM_NONZERO_CONTEXT: [usize; 64] = [ 0xBAD, 0, 31, 62, 62, 93, 93, 93, 93, 123, 123, 123, 123, 152, 152, 152, 152, 152, 152, 152, 152, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, ]; #[inline] pub fn zero_density_context( nonzeros_left: usize, k: usize, log_num_blocks: usize, prev: usize, ) -> usize { let nonzeros_left_norm = nonzeros_left.shrc(log_num_blocks); let k_norm = k >> log_num_blocks; debug_assert!((1..64).contains(&k_norm)); debug_assert!((1..64).contains(&nonzeros_left_norm)); (COEFF_NUM_NONZERO_CONTEXT[nonzeros_left_norm & 63] + COEFF_FREQ_CONTEXT[k_norm & 63]) * 2 + prev } #[derive(Debug)] pub struct BlockContextMap { pub lf_thresholds: [Vec; 3], pub qf_thresholds: Vec, pub context_map: Vec, pub num_lf_contexts: usize, pub num_contexts: usize, } impl BlockContextMap { pub fn num_ac_contexts(&self) -> usize { self.num_contexts * (NON_ZERO_BUCKETS + ZERO_DENSITY_CONTEXT_COUNT) } pub fn read(br: &mut BitReader) -> Result { if br.read(1)? == 1 { Ok(BlockContextMap { lf_thresholds: [vec![], vec![], vec![]], qf_thresholds: vec![], context_map: vec![ 0, 1, 2, 2, 3, 3, 4, 5, 6, 6, 6, 6, 6, // 7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14, // 7, 8, 9, 9, 10, 11, 12, 13, 14, 14, 14, 14, 14, // ], num_lf_contexts: 1, num_contexts: 15, }) } else { let mut num_lf_contexts: usize = 1; let mut lf_thresholds: [Vec; 3] = [vec![], vec![], vec![]]; for thr in lf_thresholds.iter_mut() { let num_lf_thresholds = br.read(4)? as usize; let mut v: Vec = vec![0; num_lf_thresholds]; for val in v.iter_mut() { let uval = match br.read(2)? { 0 => br.read(4)?, 1 => br.read(8)? + 16, 2 => br.read(16)? + 272, _ => br.read(32)? + 65808, }; *val = unpack_signed(uval as u32) } *thr = v; num_lf_contexts *= num_lf_thresholds + 1; } let num_qf_thresholds = br.read(4)? as usize; let mut qf_thresholds: Vec = vec![0; num_qf_thresholds]; for val in qf_thresholds.iter_mut() { *val = match br.read(2)? { 0 => br.read(2)?, 1 => br.read(3)? + 4, 2 => br.read(5)? + 12, _ => br.read(8)? + 44, } as u32 + 1; } if num_lf_contexts * (num_qf_thresholds + 1) > 64 { return Err(Error::BlockContextMapSizeTooBig( num_lf_contexts, num_qf_thresholds, )); } let context_map_size = 3 * NUM_ORDERS * num_lf_contexts * (num_qf_thresholds + 1); let context_map = decode_context_map(context_map_size, br)?; assert_eq!(context_map.len(), context_map_size); let num_contexts = *context_map.iter().max().unwrap() as usize + 1; if num_contexts > 16 { Err(Error::TooManyBlockContexts) } else { Ok(BlockContextMap { lf_thresholds, qf_thresholds, context_map, num_lf_contexts, num_contexts, }) } } } pub fn block_context(&self, lf_idx: usize, qf: u32, shape_id: usize, c: usize) -> usize { let mut qf_idx: usize = 0; for t in &self.qf_thresholds { if qf > *t { qf_idx += 1; } } let mut idx = if c < 2 { c ^ 1 } else { 2 }; idx = idx * NUM_ORDERS + shape_id; idx = idx * (self.qf_thresholds.len() + 1) + qf_idx; idx = idx * self.num_lf_contexts + lf_idx; self.context_map[idx] as usize } pub fn nonzero_context(&self, nonzeros: usize, block_context: usize) -> usize { let context: usize = if nonzeros < 8 { nonzeros } else if nonzeros < 64 { 4 + nonzeros / 2 } else { 36 }; context * self.num_contexts + block_context } pub fn zero_density_context_offset(&self, block_context: usize) -> usize { self.num_contexts * NON_ZERO_BUCKETS + ZERO_DENSITY_CONTEXT_COUNT * block_context } }