#![allow(dead_code)]
pub const NUM_I16_MODES: usize = 4;
pub const NUM_I4_MODES: usize = 10;
pub const NUM_CHROMA_MODES: usize = 4;
pub const NUM_MV_MODES: usize = 4;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum IntraMode16 {
#[default]
DcPred = 0,
VPred = 1,
HPred = 2,
TmPred = 3,
}
impl IntraMode16 {
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(Self::DcPred),
1 => Some(Self::VPred),
2 => Some(Self::HPred),
3 => Some(Self::TmPred),
_ => None,
}
}
#[must_use]
pub const fn index(self) -> usize {
self as usize
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum IntraMode4 {
#[default]
DcPred = 0,
TmPred = 1,
VPred = 2,
HPred = 3,
LdPred = 4,
RdPred = 5,
VrPred = 6,
VlPred = 7,
HdPred = 8,
HuPred = 9,
}
impl IntraMode4 {
pub const ALL: [Self; NUM_I4_MODES] = [
Self::DcPred,
Self::TmPred,
Self::VPred,
Self::HPred,
Self::LdPred,
Self::RdPred,
Self::VrPred,
Self::VlPred,
Self::HdPred,
Self::HuPred,
];
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(Self::DcPred),
1 => Some(Self::TmPred),
2 => Some(Self::VPred),
3 => Some(Self::HPred),
4 => Some(Self::LdPred),
5 => Some(Self::RdPred),
6 => Some(Self::VrPred),
7 => Some(Self::VlPred),
8 => Some(Self::HdPred),
9 => Some(Self::HuPred),
_ => None,
}
}
#[must_use]
pub const fn index(self) -> usize {
self as usize
}
#[must_use]
pub const fn is_directional(self) -> bool {
!matches!(self, Self::DcPred | Self::TmPred)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum ChromaMode {
#[default]
DcPred = 0,
VPred = 1,
HPred = 2,
TmPred = 3,
}
impl ChromaMode {
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(Self::DcPred),
1 => Some(Self::VPred),
2 => Some(Self::HPred),
3 => Some(Self::TmPred),
_ => None,
}
}
#[must_use]
pub const fn index(self) -> usize {
self as usize
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum InterMode {
#[default]
Nearest = 0,
Near = 1,
Zero = 2,
New = 3,
}
impl InterMode {
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(Self::Nearest),
1 => Some(Self::Near),
2 => Some(Self::Zero),
3 => Some(Self::New),
_ => None,
}
}
#[must_use]
pub const fn index(self) -> usize {
self as usize
}
#[must_use]
pub const fn needs_mv(self) -> bool {
matches!(self, Self::New)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum PartitionType {
#[default]
P16x16 = 0,
P16x8 = 1,
P8x16 = 2,
P8x8 = 3,
}
impl PartitionType {
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(Self::P16x16),
1 => Some(Self::P16x8),
2 => Some(Self::P8x16),
3 => Some(Self::P8x8),
_ => None,
}
}
#[must_use]
pub const fn num_partitions(self) -> usize {
match self {
Self::P16x16 => 1,
Self::P16x8 | Self::P8x16 => 2,
Self::P8x8 => 4,
}
}
#[must_use]
pub const fn partition_size(self, index: usize) -> (usize, usize) {
match self {
Self::P16x16 => (16, 16),
Self::P16x8 => (16, 8),
Self::P8x16 => (8, 16),
Self::P8x8 => (8, 8),
}
}
#[must_use]
pub const fn partition_offset(self, index: usize) -> (usize, usize) {
match self {
Self::P16x16 => (0, 0),
Self::P16x8 => match index {
0 => (0, 0),
1 => (0, 8),
_ => (0, 0),
},
Self::P8x16 => match index {
0 => (0, 0),
1 => (8, 0),
_ => (0, 0),
},
Self::P8x8 => match index {
0 => (0, 0),
1 => (8, 0),
2 => (0, 8),
3 => (8, 8),
_ => (0, 0),
},
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum RefFrame {
#[default]
Last = 0,
Golden = 1,
AltRef = 2,
}
impl RefFrame {
#[must_use]
pub const fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(Self::Last),
1 => Some(Self::Golden),
2 => Some(Self::AltRef),
_ => None,
}
}
#[must_use]
pub const fn index(self) -> usize {
self as usize
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MacroblockType {
Intra16(IntraMode16, ChromaMode),
Intra4 {
modes: [IntraMode4; 16],
chroma_mode: ChromaMode,
},
Inter {
partition: PartitionType,
ref_frame: RefFrame,
modes: [InterMode; 4],
},
}
impl MacroblockType {
#[must_use]
pub const fn is_intra(&self) -> bool {
matches!(self, Self::Intra16(_, _) | Self::Intra4 { .. })
}
#[must_use]
pub const fn is_inter(&self) -> bool {
matches!(self, Self::Inter { .. })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intra_mode_16() {
assert_eq!(IntraMode16::from_u8(0), Some(IntraMode16::DcPred));
assert_eq!(IntraMode16::from_u8(3), Some(IntraMode16::TmPred));
assert_eq!(IntraMode16::from_u8(4), None);
assert_eq!(IntraMode16::DcPred.index(), 0);
assert_eq!(IntraMode16::TmPred.index(), 3);
}
#[test]
fn test_intra_mode_4() {
assert_eq!(IntraMode4::from_u8(0), Some(IntraMode4::DcPred));
assert_eq!(IntraMode4::from_u8(9), Some(IntraMode4::HuPred));
assert_eq!(IntraMode4::from_u8(10), None);
assert!(!IntraMode4::DcPred.is_directional());
assert!(!IntraMode4::TmPred.is_directional());
assert!(IntraMode4::VPred.is_directional());
assert!(IntraMode4::HuPred.is_directional());
assert_eq!(IntraMode4::ALL.len(), NUM_I4_MODES);
}
#[test]
fn test_chroma_mode() {
assert_eq!(ChromaMode::from_u8(0), Some(ChromaMode::DcPred));
assert_eq!(ChromaMode::from_u8(3), Some(ChromaMode::TmPred));
assert_eq!(ChromaMode::from_u8(4), None);
assert_eq!(ChromaMode::VPred.index(), 1);
}
#[test]
fn test_inter_mode() {
assert_eq!(InterMode::from_u8(0), Some(InterMode::Nearest));
assert_eq!(InterMode::from_u8(3), Some(InterMode::New));
assert_eq!(InterMode::from_u8(4), None);
assert!(!InterMode::Nearest.needs_mv());
assert!(!InterMode::Zero.needs_mv());
assert!(InterMode::New.needs_mv());
}
#[test]
fn test_partition_type() {
assert_eq!(PartitionType::from_u8(0), Some(PartitionType::P16x16));
assert_eq!(PartitionType::from_u8(3), Some(PartitionType::P8x8));
assert_eq!(PartitionType::from_u8(4), None);
assert_eq!(PartitionType::P16x16.num_partitions(), 1);
assert_eq!(PartitionType::P16x8.num_partitions(), 2);
assert_eq!(PartitionType::P8x8.num_partitions(), 4);
}
#[test]
fn test_partition_size() {
assert_eq!(PartitionType::P16x16.partition_size(0), (16, 16));
assert_eq!(PartitionType::P16x8.partition_size(0), (16, 8));
assert_eq!(PartitionType::P8x16.partition_size(0), (8, 16));
assert_eq!(PartitionType::P8x8.partition_size(0), (8, 8));
}
#[test]
fn test_partition_offset() {
assert_eq!(PartitionType::P16x16.partition_offset(0), (0, 0));
assert_eq!(PartitionType::P16x8.partition_offset(0), (0, 0));
assert_eq!(PartitionType::P16x8.partition_offset(1), (0, 8));
assert_eq!(PartitionType::P8x16.partition_offset(0), (0, 0));
assert_eq!(PartitionType::P8x16.partition_offset(1), (8, 0));
assert_eq!(PartitionType::P8x8.partition_offset(0), (0, 0));
assert_eq!(PartitionType::P8x8.partition_offset(1), (8, 0));
assert_eq!(PartitionType::P8x8.partition_offset(2), (0, 8));
assert_eq!(PartitionType::P8x8.partition_offset(3), (8, 8));
}
#[test]
fn test_ref_frame() {
assert_eq!(RefFrame::from_u8(0), Some(RefFrame::Last));
assert_eq!(RefFrame::from_u8(2), Some(RefFrame::AltRef));
assert_eq!(RefFrame::from_u8(3), None);
assert_eq!(RefFrame::Last.index(), 0);
assert_eq!(RefFrame::Golden.index(), 1);
assert_eq!(RefFrame::AltRef.index(), 2);
}
#[test]
fn test_macroblock_type() {
let intra16 = MacroblockType::Intra16(IntraMode16::DcPred, ChromaMode::DcPred);
assert!(intra16.is_intra());
assert!(!intra16.is_inter());
let intra4 = MacroblockType::Intra4 {
modes: [IntraMode4::DcPred; 16],
chroma_mode: ChromaMode::DcPred,
};
assert!(intra4.is_intra());
assert!(!intra4.is_inter());
let inter = MacroblockType::Inter {
partition: PartitionType::P16x16,
ref_frame: RefFrame::Last,
modes: [InterMode::Zero; 4],
};
assert!(!inter.is_intra());
assert!(inter.is_inter());
}
#[test]
fn test_constants() {
assert_eq!(NUM_I16_MODES, 4);
assert_eq!(NUM_I4_MODES, 10);
assert_eq!(NUM_CHROMA_MODES, 4);
assert_eq!(NUM_MV_MODES, 4);
}
}