use super::bitwriter::BoolEncoder;
use crate::block::{INTRA_MODE_TREE, PARTITION_SPLIT, PARTITION_TREE};
use crate::decode::SEGMENT_TREE;
pub fn write_partition(
enc: &mut BoolEncoder,
partition: usize,
probs: &[u8; 3],
has_rows: bool,
has_cols: bool,
) {
if has_rows && has_cols {
enc.write_tree(&PARTITION_TREE, probs, partition as i32);
} else if !has_rows && has_cols {
enc.write_bool((partition == PARTITION_SPLIT) as u32, probs[1]);
} else if has_rows && !has_cols {
enc.write_bool((partition == PARTITION_SPLIT) as u32, probs[2]);
}
}
pub fn write_intra_mode(enc: &mut BoolEncoder, mode: u8, probs: &[u8; 9]) {
enc.write_tree(&INTRA_MODE_TREE, probs, mode as i32);
}
pub fn write_selected_tx_size(
enc: &mut BoolEncoder,
tx_size: u8,
tx_probs: &[u8],
max_tx_size: usize,
) {
let t = tx_size as usize;
enc.write_bool((t >= 1) as u32, tx_probs[0]);
if t >= 1 && max_tx_size >= 2 {
enc.write_bool((t >= 2) as u32, tx_probs[1]);
if t >= 2 && max_tx_size >= 3 {
enc.write_bool((t >= 3) as u32, tx_probs[2]);
}
}
}
pub fn write_skip(enc: &mut BoolEncoder, skip: bool, prob: u8) {
enc.write_bool(skip as u32, prob);
}
pub fn write_segment_id(enc: &mut BoolEncoder, seg_id: u8, tree_probs: &[u8; 7]) {
enc.write_tree(&SEGMENT_TREE, tree_probs, seg_id as i32);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bits::BoolDecoder;
use crate::block::{
read_intra_mode, read_partition, read_selected_tx_size, PARTITION_HORZ, PARTITION_VERT,
};
use crate::token::read_tree;
#[test]
fn partition_roundtrips_including_edges() {
let probs = [120u8, 90, 200];
for part in 0..4usize {
let mut enc = BoolEncoder::new();
write_partition(&mut enc, part, &probs, true, true);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(read_partition(&mut bd, &probs, true, true), part);
}
for part in [PARTITION_HORZ, PARTITION_SPLIT] {
let mut enc = BoolEncoder::new();
write_partition(&mut enc, part, &probs, false, true);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(read_partition(&mut bd, &probs, false, true), part);
}
for part in [PARTITION_VERT, PARTITION_SPLIT] {
let mut enc = BoolEncoder::new();
write_partition(&mut enc, part, &probs, true, false);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(read_partition(&mut bd, &probs, true, false), part);
}
let mut enc = BoolEncoder::new();
write_partition(&mut enc, PARTITION_SPLIT, &probs, false, false);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(
read_partition(&mut bd, &probs, false, false),
PARTITION_SPLIT
);
}
#[test]
fn intra_mode_roundtrips_all_modes() {
let probs = [80u8, 100, 120, 140, 90, 110, 130, 150, 70];
for mode in 0..10u8 {
let mut enc = BoolEncoder::new();
write_intra_mode(&mut enc, mode, &probs);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(read_intra_mode(&mut bd, &probs), mode);
}
}
#[test]
fn tx_size_roundtrips_every_depth() {
let tx_probs = [100u8, 130, 160];
for max in 1..=3usize {
for tx in 0..=max as u8 {
let mut enc = BoolEncoder::new();
write_selected_tx_size(&mut enc, tx, &tx_probs, max);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(read_selected_tx_size(&mut bd, &tx_probs, max), tx);
}
}
}
#[test]
fn segment_id_roundtrips() {
let tree_probs = [120u8, 90, 200, 100, 130, 160, 80];
for seg in 0..8u8 {
let mut enc = BoolEncoder::new();
write_segment_id(&mut enc, seg, &tree_probs);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(read_tree(&mut bd, &SEGMENT_TREE, &tree_probs) as u8, seg);
}
}
#[test]
fn skip_roundtrips() {
for skip in [false, true] {
for prob in [1u8, 64, 128, 200, 255] {
let mut enc = BoolEncoder::new();
write_skip(&mut enc, skip, prob);
let bytes = enc.finish();
let mut bd = BoolDecoder::new(&bytes).unwrap();
assert_eq!(bd.read_bool(prob) != 0, skip);
}
}
}
}