#[derive(Debug, Clone)]
pub enum PixelData {
U8(Vec<u8>),
U16(Vec<u16>),
}
impl PixelData {
pub fn as_u8(&self) -> Option<&[u8]> {
match self {
PixelData::U8(v) => Some(v),
PixelData::U16(_) => None,
}
}
pub fn as_u16(&self) -> Option<&[u16]> {
match self {
PixelData::U16(v) => Some(v),
PixelData::U8(_) => None,
}
}
pub fn len(&self) -> usize {
match self {
PixelData::U8(v) => v.len(),
PixelData::U16(v) => v.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub trait Pixel: Copy + Clone + Default + Send + Sync + Sized + 'static {
fn from_i32_clamped(val: i32, bit_depth: u8) -> Self;
fn to_i32(self) -> i32;
fn zero() -> Self;
fn extract_slice(data: &PixelData) -> &[Self];
fn extract_slice_mut(data: &mut PixelData) -> &mut [Self];
fn wrap_vec(v: Vec<Self>) -> PixelData;
}
impl Pixel for u8 {
#[inline(always)]
fn from_i32_clamped(val: i32, _bit_depth: u8) -> Self {
val.clamp(0, 255) as u8
}
#[inline(always)]
fn to_i32(self) -> i32 {
self as i32
}
#[inline(always)]
fn zero() -> Self {
0
}
#[inline(always)]
fn extract_slice(data: &PixelData) -> &[Self] {
match data {
PixelData::U8(v) => v,
PixelData::U16(_) => panic!("PixelData::U16 accessed as u8"),
}
}
#[inline(always)]
fn extract_slice_mut(data: &mut PixelData) -> &mut [Self] {
match data {
PixelData::U8(v) => v,
PixelData::U16(_) => panic!("PixelData::U16 accessed as u8"),
}
}
#[inline(always)]
fn wrap_vec(v: Vec<Self>) -> PixelData {
PixelData::U8(v)
}
}
impl Pixel for u16 {
#[inline(always)]
fn from_i32_clamped(val: i32, bit_depth: u8) -> Self {
let max = (1i32 << bit_depth) - 1;
val.clamp(0, max) as u16
}
#[inline(always)]
fn to_i32(self) -> i32 {
self as i32
}
#[inline(always)]
fn zero() -> Self {
0
}
#[inline(always)]
fn extract_slice(data: &PixelData) -> &[Self] {
match data {
PixelData::U16(v) => v,
PixelData::U8(_) => panic!("PixelData::U8 accessed as u16"),
}
}
#[inline(always)]
fn extract_slice_mut(data: &mut PixelData) -> &mut [Self] {
match data {
PixelData::U16(v) => v,
PixelData::U8(_) => panic!("PixelData::U8 accessed as u16"),
}
}
#[inline(always)]
fn wrap_vec(v: Vec<Self>) -> PixelData {
PixelData::U16(v)
}
}
#[inline(always)]
pub fn max_pixel_val(bit_depth: u8) -> i32 {
(1i32 << bit_depth) - 1
}
#[inline(always)]
pub fn default_ref_sample(bit_depth: u8) -> i32 {
1i32 << (bit_depth - 1)
}
#[inline(always)]
pub fn mc_shift(bit_depth: u8) -> u8 {
14 - bit_depth
}
#[inline(always)]
pub fn mc_offset(bit_depth: u8) -> i32 {
1i32 << (mc_shift(bit_depth) - 1)
}
#[inline(always)]
pub fn bipred_shift(bit_depth: u8) -> u8 {
14 - bit_depth + 1
}
#[inline(always)]
pub fn bipred_offset(bit_depth: u8) -> i32 {
1i32 << (bipred_shift(bit_depth) - 1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u8_pixel_clamp() {
assert_eq!(u8::from_i32_clamped(128, 8), 128u8);
assert_eq!(u8::from_i32_clamped(-5, 8), 0u8);
assert_eq!(u8::from_i32_clamped(300, 8), 255u8);
}
#[test]
fn u16_pixel_clamp_10bit() {
assert_eq!(u16::from_i32_clamped(512, 10), 512u16);
assert_eq!(u16::from_i32_clamped(-5, 10), 0u16);
assert_eq!(u16::from_i32_clamped(2000, 10), 1023u16);
}
#[test]
fn u16_pixel_clamp_12bit() {
assert_eq!(u16::from_i32_clamped(2048, 12), 2048u16);
assert_eq!(u16::from_i32_clamped(5000, 12), 4095u16);
}
#[test]
fn mc_shift_values() {
assert_eq!(mc_shift(8), 6);
assert_eq!(mc_shift(10), 4);
assert_eq!(mc_shift(12), 2);
}
#[test]
fn mc_offset_values() {
assert_eq!(mc_offset(8), 32);
assert_eq!(mc_offset(10), 8);
assert_eq!(mc_offset(12), 2);
}
#[test]
fn bipred_shift_values() {
assert_eq!(bipred_shift(8), 7);
assert_eq!(bipred_shift(10), 5);
assert_eq!(bipred_shift(12), 3);
}
#[test]
fn default_ref_sample_values() {
assert_eq!(default_ref_sample(8), 128);
assert_eq!(default_ref_sample(10), 512);
assert_eq!(default_ref_sample(12), 2048);
}
#[test]
fn max_pixel_values() {
assert_eq!(max_pixel_val(8), 255);
assert_eq!(max_pixel_val(10), 1023);
assert_eq!(max_pixel_val(12), 4095);
}
}