use std::io;
use scuffle_bytes_util::BitReader;
use scuffle_expgolomb::BitReaderExpGolombExt;
const TABLE_7_5: [i64; 16] = [16; 16];
#[rustfmt::skip]
const TABLE_7_6_02: [i64; 64] = [
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 17, 16, 17, 18,
17, 18, 18, 17, 18, 21, 19, 20, 21, 20, 19, 21, 24, 22, 22, 24,
24, 22, 22, 24, 25, 25, 27, 30, 27, 25, 25, 29, 31, 35, 35, 31,
29, 36, 41, 44, 41, 36, 47, 54, 54, 47, 65, 70, 65, 88, 88, 115,
];
#[rustfmt::skip]
const TABLE_7_6_35: [i64; 64] = [
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18,
18, 18, 18, 18, 18, 20, 20, 20, 20, 20, 20, 20, 24, 24, 24, 24,
24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 28, 28, 28, 28, 28,
28, 33, 33, 33, 33, 33, 41, 41, 41, 41, 54, 54, 54, 71, 71, 91,
];
const TABLE_7_6: [[i64; 64]; 6] = [
TABLE_7_6_02,
TABLE_7_6_02,
TABLE_7_6_02,
TABLE_7_6_35,
TABLE_7_6_35,
TABLE_7_6_35,
];
#[derive(Debug, Clone, PartialEq)]
pub struct ScalingListData {
pub scaling_list: [[[i64; 64]; 6]; 4],
}
impl ScalingListData {
pub(crate) fn parse<R: io::Read>(bit_reader: &mut BitReader<R>) -> io::Result<Self> {
let mut scaling_list = [[[0; 64]; 6]; 4];
for (size_id, scaling_column) in scaling_list.iter_mut().enumerate() {
let mut matrix_id = 0;
while matrix_id < 6 {
let scaling_list_pred_mode_flag = bit_reader.read_bit()?;
if !scaling_list_pred_mode_flag {
let scaling_list_pred_matrix_id_delta = bit_reader.read_exp_golomb()? as usize;
if scaling_list_pred_matrix_id_delta == 0 {
if size_id == 0 {
scaling_column[matrix_id][0..16].copy_from_slice(&TABLE_7_5);
} else {
let end = usize::min(63, (1 << (4 + (size_id << 1))) - 1);
scaling_column[matrix_id][0..end].copy_from_slice(&TABLE_7_6[matrix_id][0..end]);
}
} else {
if size_id == 0 {
scaling_column[matrix_id][0..16].copy_from_slice(&TABLE_7_5);
} else {
let ref_matrix_id =
matrix_id - scaling_list_pred_matrix_id_delta * (if size_id == 3 { 3 } else { 1 });
let end = usize::min(63, (1 << (4 + (size_id << 1))) - 1);
scaling_column[matrix_id][0..end].copy_from_slice(&TABLE_7_6[ref_matrix_id][0..end]);
}
}
} else {
let mut next_coef = 8;
let coef_num = usize::min(64, 1 << (4 + (size_id << 1)));
if size_id > 1 {
let scaling_list_dc_coef_minus8 = bit_reader.read_signed_exp_golomb()?;
next_coef = scaling_list_dc_coef_minus8 + 8;
}
for i in 0..coef_num {
let scaling_list_delta_coef = bit_reader.read_signed_exp_golomb()?;
next_coef = (next_coef + scaling_list_delta_coef + 256) % 256;
scaling_column[matrix_id][i] = next_coef;
}
}
matrix_id += if size_id == 3 { 3 } else { 1 };
}
}
Ok(Self { scaling_list })
}
}