Commit 8057ee7c authored by Romain Vimont's avatar Romain Vimont Committed by Luca Barbato
Browse files

Make plane generic over pixel component type

In order to support both u8 and u16 for plane components, make the Plane
structure generic over the component type. As a consequence, many other
structures and functions also become generic.

Some functions are not u8-compatible yet, although they have been make
generic over the component type to make the compilation work. They
assert that the size of the generic parameter is 16 bits wide.

For this reason, the root context structure is unconditionally created
as Context<u16> for now.
parent bc358bf7
......@@ -49,7 +49,7 @@ fn write_b_bench(b: &mut Bencher, tx_size: TxSize, qindex: usize) {
..Default::default()
};
let sequence = Sequence::new(&Default::default());
let mut fi = FrameInvariants::new(config, sequence);
let mut fi = FrameInvariants::<u16>::new(config, sequence);
let mut w = ec::WriterEncoder::new();
let fc = CDFContext::new(fi.base_q_idx);
let bc = BlockContext::new(fi.sb_width * 16, fi.sb_height * 16);
......@@ -120,7 +120,7 @@ fn cdef_frame_bench(b: &mut Bencher, width: usize, height: usize) {
..Default::default()
};
let sequence = Sequence::new(&Default::default());
let fi = FrameInvariants::new(config, sequence);
let fi = FrameInvariants::<u16>::new(config, sequence);
let mut bc = BlockContext::new(fi.sb_width * 16, fi.sb_height * 16);
let mut fs = FrameState::new(&fi);
......@@ -148,7 +148,7 @@ fn cfl_rdo_bench(b: &mut Bencher, bsize: BlockSize) {
..Default::default()
};
let sequence = Sequence::new(&Default::default());
let fi = FrameInvariants::new(config, sequence );
let fi = FrameInvariants::<u16>::new(config, sequence);
let mut fs = FrameState::new(&fi);
let offset = BlockOffset { x: 1, y: 1 };
b.iter(|| rdo_cfl_alpha(&mut fs, &offset, bsize, fi.sequence.bit_depth, fi.sequence.chroma_sampling))
......
......@@ -13,18 +13,19 @@ use crate::partition::BlockSize::*;
use crate::plane::*;
use rand::{ChaChaRng, Rng, SeedableRng};
use rav1e::me;
use rav1e::Pixel;
fn fill_plane(ra: &mut ChaChaRng, plane: &mut Plane) {
fn fill_plane<T: Pixel>(ra: &mut ChaChaRng, plane: &mut Plane<T>) {
let stride = plane.cfg.stride;
for row in plane.data.chunks_mut(stride) {
for pixel in row {
let v: u8 = ra.gen();
*pixel = v as u16;
*pixel = T::cast_from(v);
}
}
}
fn new_plane(ra: &mut ChaChaRng, width: usize, height: usize) -> Plane {
fn new_plane<T: Pixel>(ra: &mut ChaChaRng, width: usize, height: usize) -> Plane<T> {
let mut p = Plane::new(width, height, 0, 0, 128 + 8, 128 + 8);
fill_plane(ra, &mut p);
......@@ -39,8 +40,8 @@ fn bench_get_sad(b: &mut Bencher, bs: &BlockSize) {
let w = 640;
let h = 480;
let bit_depth = 10;
let input_plane = new_plane(&mut ra, w, h);
let rec_plane = new_plane(&mut ra, w, h);
let input_plane = new_plane::<u16>(&mut ra, w, h);
let rec_plane = new_plane::<u16>(&mut ra, w, h);
let po = PlaneOffset { x: 0, y: 0 };
let plane_org = input_plane.slice(&po);
......
......@@ -16,6 +16,7 @@ use crate::rate::FRAME_NSUBTYPES;
use crate::rate::FRAME_SUBTYPE_I;
use crate::rate::FRAME_SUBTYPE_P;
use crate::scenechange::SceneChangeDetector;
use crate::util::Pixel;
use self::EncoderStatus::*;
use std::{cmp, fmt, io};
......@@ -437,7 +438,7 @@ impl Config {
Ok(())
}
pub fn new_context(&self) -> Context {
pub fn new_context<T: Pixel>(&self) -> Context<T> {
#[cfg(feature = "aom")]
unsafe {
av1_rtcd();
......@@ -483,16 +484,16 @@ impl Config {
}
}
pub struct Context {
pub struct Context<T: Pixel> {
// timebase: Rational,
frame_count: u64,
limit: u64,
pub(crate) idx: u64,
frames_processed: u64,
/// Maps frame *number* to frames
frame_q: BTreeMap<u64, Option<Arc<Frame>>>, // packet_q: VecDeque<Packet>
frame_q: BTreeMap<u64, Option<Arc<Frame<T>>>>, // packet_q: VecDeque<Packet>
/// Maps frame *idx* to frame data
frame_data: BTreeMap<u64, FrameInvariants>,
frame_data: BTreeMap<u64, FrameInvariants<T>>,
/// A list of keyframe *numbers* in this encode. Needed so that we don't
/// need to keep all of the frame_data in memory for the whole life of the encode.
keyframes: BTreeSet<u64>,
......@@ -500,7 +501,7 @@ pub struct Context {
packet_data: Vec<u8>,
segment_start_idx: u64,
segment_start_frame: u64,
keyframe_detector: SceneChangeDetector,
keyframe_detector: SceneChangeDetector<T>,
pub config: Config,
rc_state: RCState,
maybe_prev_log_base_q: Option<i64>,
......@@ -519,16 +520,16 @@ pub enum EncoderStatus {
ParseError
}
pub struct Packet {
pub struct Packet<T: Pixel> {
pub data: Vec<u8>,
pub rec: Option<Frame>,
pub rec: Option<Frame<T>>,
pub number: u64,
pub frame_type: FrameType,
/// PSNR for Y, U, and V planes
pub psnr: Option<(f64, f64, f64)>,
}
impl fmt::Display for Packet {
impl<T: Pixel> fmt::Display for Packet<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
......@@ -540,8 +541,8 @@ impl fmt::Display for Packet {
}
}
impl Context {
pub fn new_frame(&self) -> Arc<Frame> {
impl<T: Pixel> Context<T> {
pub fn new_frame(&self) -> Arc<Frame<T>> {
Arc::new(Frame::new(
self.config.enc.width,
self.config.enc.height,
......@@ -551,7 +552,8 @@ impl Context {
pub fn send_frame<F>(&mut self, frame: F) -> Result<(), EncoderStatus>
where
F: Into<Option<Arc<Frame>>>
F: Into<Option<Arc<Frame<T>>>>,
T: Pixel,
{
let idx = self.frame_count;
self.frame_q.insert(idx, frame.into());
......@@ -559,7 +561,7 @@ impl Context {
Ok(())
}
pub fn get_frame(&self, frame_number: u64) -> Arc<Frame> {
pub fn get_frame(&self, frame_number: u64) -> Arc<Frame<T>> {
// Clones only the arc, so low cost overhead
self.frame_q.get(&frame_number).as_ref().unwrap().as_ref().unwrap().clone()
}
......@@ -628,7 +630,7 @@ impl Context {
end_of_subgop
}
fn build_frame_properties(&mut self, idx: u64) -> (FrameInvariants, bool) {
fn build_frame_properties(&mut self, idx: u64) -> (FrameInvariants<T>, bool) {
if idx == 0 {
let seq = Sequence::new(&self.config.enc);
......@@ -711,7 +713,7 @@ impl Context {
(fi, true)
}
pub fn receive_packet(&mut self) -> Result<Packet, EncoderStatus> {
pub fn receive_packet(&mut self) -> Result<Packet<T>, EncoderStatus> {
let idx = {
let mut idx = self.idx;
while !self.set_frame_properties(idx) {
......@@ -794,7 +796,7 @@ impl Context {
ret
}
fn finalize_packet(&mut self, rec: Option<Frame>, fi: &FrameInvariants) -> Result<Packet, EncoderStatus> {
fn finalize_packet(&mut self, rec: Option<Frame<T>>, fi: &FrameInvariants<T>) -> Result<Packet<T>, EncoderStatus> {
let data = self.packet_data.clone();
self.packet_data.clear();
if write_temporal_delimiter(&mut self.packet_data).is_err() {
......@@ -972,8 +974,8 @@ pub struct FirstPassFrame {
frame_type: FrameType,
}
impl From<&FrameInvariants> for FirstPassFrame {
fn from(fi: &FrameInvariants) -> FirstPassFrame {
impl<T: Pixel> From<&FrameInvariants<T>> for FirstPassFrame {
fn from(fi: &FrameInvariants<T>) -> FirstPassFrame {
FirstPassFrame {
number: fi.number,
frame_type: fi.frame_type,
......
......@@ -463,8 +463,8 @@ pub struct FrameSummary {
pub psnr: Option<(f64, f64, f64)>,
}
impl From<Packet> for FrameSummary {
fn from(packet: Packet) -> Self {
impl<T: Pixel> From<Packet<T>> for FrameSummary {
fn from(packet: Packet<T>) -> Self {
Self {
size: packet.data.len(),
number: packet.number,
......
......@@ -6,7 +6,7 @@ pub mod y4m;
pub trait Decoder {
fn get_video_details(&self) -> VideoDetails;
fn read_frame(&mut self, cfg: &VideoDetails) -> Result<Frame, DecodeError>;
fn read_frame<T: Pixel>(&mut self, cfg: &VideoDetails) -> Result<Frame<T>, DecodeError>;
}
#[derive(Debug)]
......
......@@ -7,6 +7,7 @@ use crate::decoder::VideoDetails;
use crate::ChromaSamplePosition;
use crate::ChromaSampling;
use crate::encoder::Frame;
use rav1e::*;
impl Decoder for y4m::Decoder<'_, Box<dyn Read>> {
fn get_video_details(&self) -> VideoDetails {
......@@ -28,11 +29,11 @@ impl Decoder for y4m::Decoder<'_, Box<dyn Read>> {
}
}
fn read_frame(&mut self, cfg: &VideoDetails) -> Result<Frame, DecodeError> {
fn read_frame<T: Pixel>(&mut self, cfg: &VideoDetails) -> Result<Frame<T>, DecodeError> {
let bytes = self.get_bytes_per_sample();
self.read_frame()
.map(|frame| {
let mut f = Frame::new(cfg.width, cfg.height, cfg.chroma_sampling);
let mut f: Frame<T> = Frame::new(cfg.width, cfg.height, cfg.chroma_sampling);
let (chroma_period, _) = cfg.chroma_sampling.sampling_period();
......
......@@ -10,10 +10,11 @@
use crate::decoder::VideoDetails;
use std::io::Write;
use std::slice;
use rav1e::*;
pub use ivf::*;
pub fn write_y4m_frame(y4m_enc: &mut y4m::Encoder<'_, Box<dyn Write>>, rec: &rav1e::Frame, y4m_details: VideoDetails) {
pub fn write_y4m_frame<T: Pixel>(y4m_enc: &mut y4m::Encoder<'_, Box<dyn Write>>, rec: &rav1e::Frame<T>, y4m_details: VideoDetails) {
let pitch_y = if y4m_details.bit_depth > 8 { y4m_details.width * 2 } else { y4m_details.width };
let chroma_sampling_period = y4m_details.chroma_sampling.sampling_period();
let (pitch_uv, height_uv) = (
......@@ -47,7 +48,7 @@ pub fn write_y4m_frame(y4m_enc: &mut y4m::Encoder<'_, Box<dyn Write>>, rec: &rav
}
} else {
line_out.copy_from_slice(
&line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_y]
&line.iter().map(|&v| u8::cast_from(v)).collect::<Vec<u8>>()[..pitch_y]
);
}
}
......@@ -65,7 +66,7 @@ pub fn write_y4m_frame(y4m_enc: &mut y4m::Encoder<'_, Box<dyn Write>>, rec: &rav
}
} else {
line_out.copy_from_slice(
&line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_uv]
&line.iter().map(|&v| u8::cast_from(v)).collect::<Vec<u8>>()[..pitch_uv]
);
}
}
......@@ -83,7 +84,7 @@ pub fn write_y4m_frame(y4m_enc: &mut y4m::Encoder<'_, Box<dyn Write>>, rec: &rav
}
} else {
line_out.copy_from_slice(
&line.iter().map(|&v| v as u8).collect::<Vec<u8>>()[..pitch_uv]
&line.iter().map(|&v| u8::cast_from(v)).collect::<Vec<u8>>()[..pitch_uv]
);
}
}
......
......@@ -29,7 +29,7 @@ use crate::decoder::VideoDetails;
use std::fs::File;
use std::io::BufWriter;
fn read_frame_batch<D: Decoder>(ctx: &mut Context, decoder: &mut D, video_info: VideoDetails) {
fn read_frame_batch<T: Pixel, D: Decoder>(ctx: &mut Context<T>, decoder: &mut D, video_info: VideoDetails) {
loop {
if ctx.needs_more_lookahead() {
match decoder.read_frame(&video_info) {
......@@ -58,8 +58,8 @@ fn read_frame_batch<D: Decoder>(ctx: &mut Context, decoder: &mut D, video_info:
// Encode and write a frame.
// Returns frame information in a `Result`.
fn process_frame(
ctx: &mut Context,
fn process_frame<T: Pixel>(
ctx: &mut Context<T>,
output_file: &mut dyn Write,
y4m_dec: &mut y4m::Decoder<'_, Box<dyn Read>>,
mut y4m_enc: Option<&mut y4m::Encoder<'_, Box<dyn Write>>>,
......@@ -78,7 +78,7 @@ fn process_frame(
Ok(frame_summaries)
}
fn write_stats_file(ctx: &Context, filename: &Path) -> Result<(), io::Error> {
fn write_stats_file<T: Pixel>(ctx: &Context<T>, filename: &Path) -> Result<(), io::Error> {
let file = File::create(filename)?;
let writer = BufWriter::new(file);
serde_json::to_writer(writer, &ctx.first_pass_data).expect("Serialization should not fail");
......@@ -112,7 +112,8 @@ fn main() {
enc: cli.enc
};
let mut ctx = cfg.new_context();
// FIXME for now, unconditionally create Context<u16>
let mut ctx: Context<u16> = cfg.new_context();
let stderr = io::stderr();
let mut err = stderr.lock();
......
......@@ -13,9 +13,10 @@ use crate::context::*;
use crate::Frame;
use crate::FrameInvariants;
use crate::plane::*;
use crate::util::{clamp, msb};
use crate::util::{clamp, msb, Pixel, CastFromPrimitive};
use std::cmp;
use std::mem;
pub struct CdefDirections {
dir: [[u8; 8]; 8],
......@@ -54,15 +55,16 @@ fn first_max_element(elems: &[i32]) -> (usize, i32) {
// in a particular direction. Since each direction have the same sum(x^2) term,
// that term is never computed. See Section 2, step 2, of:
// http://jmvalin.ca/notes/intra_paint.pdf
fn cdef_find_dir(img: &[u16], stride: usize, var: &mut i32, coeff_shift: i32) -> i32 {
fn cdef_find_dir<T: Pixel>(img: &[T], stride: usize, var: &mut i32, coeff_shift: usize) -> i32 {
let mut cost: [i32; 8] = [0; 8];
let mut partial: [[i32; 15]; 8] = [[0; 15]; 8];
for i in 0..8 {
for j in 0..8 {
let p: i32 = img[i * stride + j].as_();
// We subtract 128 here to reduce the maximum range of the squared
// partial sums.
debug_assert!((img[i * stride + j] >> coeff_shift) <= 255);
let x = (img[i * stride + j] as i32 >> coeff_shift) - 128;
debug_assert!(p >> coeff_shift <= 255);
let x = (p >> coeff_shift) - 128;
partial[0][i + j] += x;
partial[1][i + j / 2] += x;
partial[2][i] += x;
......@@ -125,11 +127,13 @@ fn constrain(diff: i32, threshold: i32, damping: i32) -> i32 {
// Unlike the AOM code, our block addressing points to the UL corner
// of the 2-pixel padding around the block, not the block itself.
// The destination is unpadded.
unsafe fn cdef_filter_block(dst: &mut [u16], dstride: isize, input: &[u16],
istride: isize, pri_strength: i32, sec_strength: i32,
dir: usize, pri_damping: i32, sec_damping: i32,
xsize: isize, ysize: isize, coeff_shift: i32) {
unsafe fn cdef_filter_block<T: Pixel>(
dst: &mut [T], dstride: isize, input: &[T],
istride: isize, pri_strength: i32, sec_strength: i32,
dir: usize, pri_damping: i32, sec_damping: i32,
xsize: isize, ysize: isize, coeff_shift: i32
) {
assert!(mem::size_of::<T>() == 2, "only implemented for u16 for now");
let cdef_pri_taps = [[4, 2], [3, 3]];
let cdef_sec_taps = [[2, 1], [2, 1]];
let pri_taps = cdef_pri_taps[((pri_strength >> coeff_shift) & 1) as usize];
......@@ -155,12 +159,13 @@ unsafe fn cdef_filter_block(dst: &mut [u16], dstride: isize, input: &[u16],
for k in 0..2usize {
let p0 = *ptr_in.offset(cdef_directions[dir][k]);
let p1 = *ptr_in.offset(-cdef_directions[dir][k]);
sum += pri_taps[k] * constrain(p0 as i32 - x as i32, pri_strength, pri_damping);
sum += pri_taps[k] * constrain(p1 as i32 - x as i32, pri_strength, pri_damping);
if p0 != CDEF_VERY_LARGE {
sum += pri_taps[k] * constrain(i32::cast_from(p0) - i32::cast_from(x), pri_strength, pri_damping);
sum += pri_taps[k] * constrain(i32::cast_from(p1) - i32::cast_from(x), pri_strength, pri_damping);
// FIXME this is just to make it compile, but it's incorrect if T == u8
if p0 != T::cast_from(CDEF_VERY_LARGE) {
max = cmp::max(p0, max);
}
if p1 != CDEF_VERY_LARGE {
if p1 != T::cast_from(CDEF_VERY_LARGE) {
max = cmp::max(p1, max);
}
min = cmp::min(p0, min);
......@@ -169,29 +174,29 @@ unsafe fn cdef_filter_block(dst: &mut [u16], dstride: isize, input: &[u16],
let s1 = *ptr_in.offset(-cdef_directions[(dir + 2) & 7][k]);
let s2 = *ptr_in.offset(cdef_directions[(dir + 6) & 7][k]);
let s3 = *ptr_in.offset(-cdef_directions[(dir + 6) & 7][k]);
if s0 != CDEF_VERY_LARGE {
if s0 != T::cast_from(CDEF_VERY_LARGE) {
max = cmp::max(s0, max);
}
if s1 != CDEF_VERY_LARGE {
if s1 != T::cast_from(CDEF_VERY_LARGE) {
max = cmp::max(s1, max);
}
if s2 != CDEF_VERY_LARGE {
if s2 != T::cast_from(CDEF_VERY_LARGE) {
max = cmp::max(s2, max);
}
if s3 != CDEF_VERY_LARGE {
if s3 != T::cast_from(CDEF_VERY_LARGE) {
max = cmp::max(s3, max);
}
min = cmp::min(s0, min);
min = cmp::min(s1, min);
min = cmp::min(s2, min);
min = cmp::min(s3, min);
sum += sec_taps[k] * constrain(s0 as i32 - x as i32, sec_strength, sec_damping);
sum += sec_taps[k] * constrain(s1 as i32 - x as i32, sec_strength, sec_damping);
sum += sec_taps[k] * constrain(s2 as i32 - x as i32, sec_strength, sec_damping);
sum += sec_taps[k] * constrain(s3 as i32 - x as i32, sec_strength, sec_damping);
sum += sec_taps[k] * constrain(i32::cast_from(s0) - i32::cast_from(x), sec_strength, sec_damping);
sum += sec_taps[k] * constrain(i32::cast_from(s1) - i32::cast_from(x), sec_strength, sec_damping);
sum += sec_taps[k] * constrain(i32::cast_from(s2) - i32::cast_from(x), sec_strength, sec_damping);
sum += sec_taps[k] * constrain(i32::cast_from(s3) - i32::cast_from(x), sec_strength, sec_damping);
}
*ptr_out = clamp(x as i32 + ((8 + sum - (sum < 0) as i32) >> 4), min as i32,
max as i32) as u16;
let v = T::cast_from(i32::cast_from(x) + ((8 + sum - (sum < 0) as i32) >> 4));
*ptr_out = clamp(v, min, max);
}
}
}
......@@ -206,12 +211,14 @@ fn adjust_strength(strength: i32, var: i32) -> i32 {
// in_frame is padded. Blocks are not scanned outside the block
// boundaries (padding is untouched here).
pub fn cdef_analyze_superblock(in_frame: &mut Frame,
bc_global: &mut BlockContext,
sbo: &SuperBlockOffset,
sbo_global: &SuperBlockOffset,
bit_depth: usize) -> CdefDirections {
let coeff_shift = bit_depth as i32 - 8;
pub fn cdef_analyze_superblock<T: Pixel>(
in_frame: &mut Frame<T>,
bc_global: &mut BlockContext,
sbo: &SuperBlockOffset,
sbo_global: &SuperBlockOffset,
bit_depth: usize,
) -> CdefDirections {
let coeff_shift = bit_depth as usize - 8;
let mut dir: CdefDirections = CdefDirections {dir: [[0; 8]; 8], var: [[0; 8]; 8]};
// Each direction block is 8x8 in y, and direction computation only looks at y
for by in 0..8 {
......@@ -244,7 +251,7 @@ pub fn cdef_analyze_superblock(in_frame: &mut Frame,
}
pub fn cdef_sb_frame(fi: &FrameInvariants, f: &Frame) -> Frame {
pub fn cdef_sb_frame<T: Pixel>(fi: &FrameInvariants<T>, f: &Frame<T>) -> Frame<T> {
let sb_size = if fi.sequence.use_128x128_superblock {128} else {64};
Frame {
......@@ -259,8 +266,11 @@ pub fn cdef_sb_frame(fi: &FrameInvariants, f: &Frame) -> Frame {
}
}
pub fn cdef_sb_padded_frame_copy(fi: &FrameInvariants, sbo: &SuperBlockOffset,
f: &Frame, pad: usize) -> Frame {
pub fn cdef_sb_padded_frame_copy<T: Pixel>(
fi: &FrameInvariants<T>, sbo: &SuperBlockOffset,
f: &Frame<T>, pad: usize
) -> Frame<T> {
assert!(mem::size_of::<T>() == 2, "only implemented for u16 for now");
let ipad = pad as isize;
let sb_size = if fi.sequence.use_128x128_superblock {128} else {64};
let mut out = Frame {
......@@ -285,7 +295,10 @@ pub fn cdef_sb_padded_frame_copy(fi: &FrameInvariants, sbo: &SuperBlockOffset,
let out_row = out_slice.as_mut_slice();
if offset.y + y < ipad || offset.y+y >= h + ipad {
// above or below the frame, fill with flag
for x in 0..(sb_size>>xdec) + pad*2 { out_row[x] = CDEF_VERY_LARGE; }
for x in 0..(sb_size>>xdec) + pad*2 {
// FIXME for now, T == u16
out_row[x] = T::cast_from(CDEF_VERY_LARGE);
}
} else {
let in_slice = f.planes[p].slice(&PlaneOffset {x:0, y:offset.y + y - ipad});
let in_row = in_slice.as_slice();
......@@ -296,7 +309,8 @@ pub fn cdef_sb_padded_frame_copy(fi: &FrameInvariants, sbo: &SuperBlockOffset,
if offset.x + x >= ipad && offset.x + x < w + ipad {
out_row[x as usize] = in_row[(offset.x + x - ipad) as usize]
} else {
out_row[x as usize] = CDEF_VERY_LARGE;
// FIXME for now, T == u16
out_row[x as usize] = T::cast_from(CDEF_VERY_LARGE);
}
}
} else {
......@@ -314,14 +328,16 @@ pub fn cdef_sb_padded_frame_copy(fi: &FrameInvariants, sbo: &SuperBlockOffset,
// We assume in is padded, and the area we'll write out is at least as
// large as the unpadded area of in
// cdef_index is taken from the block context
pub fn cdef_filter_superblock(fi: &FrameInvariants,
in_frame: &mut Frame,
out_frame: &mut Frame,
bc_global: &mut BlockContext,
sbo: &SuperBlockOffset,
sbo_global: &SuperBlockOffset,
cdef_index: u8,
cdef_dirs: &CdefDirections) {
pub fn cdef_filter_superblock<T: Pixel>(
fi: &FrameInvariants<T>,
in_frame: &mut Frame<T>,
out_frame: &mut Frame<T>,
bc_global: &mut BlockContext,
sbo: &SuperBlockOffset,
sbo_global: &SuperBlockOffset,
cdef_index: u8,
cdef_dirs: &CdefDirections,
) {
let coeff_shift = fi.sequence.bit_depth as i32 - 8;
let cdef_damping = fi.cdef_damping as i32;
let cdef_y_strength = fi.cdef_y_strengths[cdef_index as usize];
......@@ -398,8 +414,8 @@ pub fn cdef_filter_superblock(fi: &FrameInvariants,
// CDEF parameters are stored for each 64 by 64 block of pixels.
// The CDEF filter is applied on each 8 by 8 block of pixels.
// Reference: http://av1-spec.argondesign.com/av1-spec/av1-spec.html#cdef-process
pub fn cdef_filter_frame(fi: &FrameInvariants, rec: &mut Frame, bc: &mut BlockContext) {
pub fn cdef_filter_frame<T: Pixel>(fi: &FrameInvariants<T>, rec: &mut Frame<T>, bc: &mut BlockContext) {
assert!(mem::size_of::<T>() == 2, "only implemented for u16 for now");
// Each filter block is 64x64, except right and/or bottom for non-multiple-of-64 sizes.
// FIXME: 128x128 SB support will break this, we need FilterBlockOffset etc.
let fb_width = (rec.planes[0].cfg.width + 63) / 64;
......@@ -426,15 +442,16 @@ pub fn cdef_filter_frame(fi: &FrameInvariants, rec: &mut Frame, bc: &mut BlockCo
{
let mut cdef_slice = cdef_frame.planes[p].mut_slice(&PlaneOffset { x: 0, y: row as isize });
let cdef_row = &mut cdef_slice.as_mut_slice()[..2];
cdef_row[0] = CDEF_VERY_LARGE;
cdef_row[1] = CDEF_VERY_LARGE;
// FIXME this is just to make it compile, but it's incorrect if T == u8
cdef_row[0] = T::cast_from(CDEF_VERY_LARGE);
cdef_row[1] = T::cast_from(CDEF_VERY_LARGE);
}
// pad out end of current row
{
let mut cdef_slice = cdef_frame.planes[p].mut_slice(&PlaneOffset { x: rec_w as isize + 2, y: row as isize });
let cdef_row = &mut cdef_slice.as_mut_slice()[..padded_px[p][0]-rec_w-2];
for x in cdef_row {
*x = CDEF_VERY_LARGE;
*x = T::cast_from(CDEF_VERY_LARGE);
}
}
// copy current row from rec if we're in data, or pad if we're in first two rows/last N rows
......@@ -443,7 +460,7 @@ pub fn cdef_filter_frame(fi: &FrameInvariants, rec: &mut Frame, bc: &mut BlockCo
let cdef_row = &mut cdef_slice.as_mut_slice()[..rec_w];
if row < 2 || row >= rec_h+2 {
for x in cdef_row {
*x = CDEF_VERY_LARGE;
*x = T::cast_from(CDEF_VERY_LARGE);
}
} else {
let rec_stride = rec.planes[p].cfg.stride;
......
......@@ -25,7 +25,7 @@ use crate::lrf::*;
use crate::plane::*;
use crate::scan_order::*;
use crate::token_cdfs::*;
use crate::util::{clamp, msb};
use crate::util::{clamp, msb, Pixel};
use std::*;
......@@ -2137,12 +2137,12 @@ impl ContextWriter {
}
}
fn add_extra_mv_candidate(
fn add_extra_mv_candidate<T: Pixel>(
&self,
blk: &Block,
ref_frames: [usize; 2],
mv_stack: &mut Vec<CandidateMV>,
fi: &FrameInvariants,
fi: &FrameInvariants<T>,
is_compound: bool,
ref_id_count: &mut [usize; 2],
ref_id_mvs: &mut [[MotionVector; 2]; 2],
......@@ -2320,8 +2320,10 @@ impl ContextWriter {
}
}
fn setup_mvref_list(&mut self, bo: &BlockOffset, ref_frames: [usize; 2], mv_stack: &mut Vec<CandidateMV>,
bsize: BlockSize, fi: &FrameInvariants, is_compound: bool) -> usize {
fn setup_mvref_list<T: Pixel>(
&mut self, bo: &BlockOffset, ref_frames: [usize; 2], mv_stack: &mut Vec<CandidateMV>,
bsize: BlockSize, fi: &FrameInvariants<T>, is_compound: bool
) -> usize {
let (_rf, _rf_num) = self.get_mvref_ref_frames(INTRA_FRAME);
let target_n4_h = bsize.height_mi();
......@@ -2536,9 +2538,11 @@ impl ContextWriter {
mode_context
}
pub fn find_mvrefs(&mut self, bo: &BlockOffset, ref_frames: [usize; 2],
mv_stack: &mut Vec<CandidateMV>, bsize: BlockSize,
fi: &FrameInvariants, is_compound: bool) -> usize {