use super::super::*;
use crate::av2::tiling::TiledEncodeRequest;
use crate::av2::tiling::tile_grid_for;
impl Av2Encoder {
pub fn encode_yuv444<T: Pixel>(
&self,
planar_image: &PlanarImage<T>,
color: &Cicp,
) -> Result<Av2Frame, EncodeError> {
planar_image.validate_444()?;
let width = planar_image.width;
let height = planar_image.height;
validate_dims(width as u32, height as u32)?;
let y = &planar_image.planes[0];
let cb = &planar_image.planes[1];
let cr = &planar_image.planes[2];
if self.base_q_idx == 0 {
if let Some((log2c, log2r)) =
tile_grid_for(self.tune.tile_cols, self.tune.tile_rows, width, height)
{
return Ok(self.encode_444_lossless_tiled(planar_image, color, log2c, log2r));
}
return self.encode_yuv444_lossless(planar_image, color, self.threads);
}
let to_plane = |s: &[T]| s.iter().map(|p| p.to_f32()).collect::<Vec<f32>>();
let (yf, cbf, crf) = (to_plane(y), to_plane(cb), to_plane(cr));
let core_planes = super::lossy::Core444Planes {
y: &yf,
u: &cbf,
v: &crf,
};
let (pw, ph) = (sb_align(width), sb_align(height));
let config = self.config(Layout::I444);
let multithreaded = Self::resolve_threads(self.threads) > 1;
let video = self.video_mode.load(std::sync::atomic::Ordering::Relaxed);
if let Some((log2c, log2r)) =
tile_grid_for(self.tune.tile_cols, self.tune.tile_rows, width, height)
{
return Ok(self.encode_444_tiled(&TiledEncodeRequest {
y: &yf,
u: &cbf,
v: &crf,
width,
height,
config: &config,
color,
log2_cols: log2c,
log2_rows: log2r,
threads: self.threads,
}));
}
let mut rec = replay::DecisionRecord::new();
let mut enc = self.encode_444_core(
core_planes,
width,
height,
None,
None,
crate::av2::replay::DecideMode::Capture(&mut rec),
);
if self.tune.cdef
&& self.base_q_idx != 0
&& let Some(dec) = enc.cdef_decided.clone()
{
let cur = crate::av2::replay::DecisionCursor::new(&rec);
enc = self.encode_444_core(
core_planes,
width,
height,
None,
Some(&dec),
crate::av2::replay::DecideMode::Replay(cur),
);
} else if multithreaded && !video {
let cur = crate::av2::replay::DecisionCursor::new(&rec);
enc = self.encode_444_core(
core_planes,
width,
height,
None,
None,
crate::av2::replay::DecideMode::Replay(cur),
);
}
Ok(self.finish(enc, &config, pw, ph, width, height, color))
}
pub fn encode_image_444<T: Pixel>(
&self,
img: &PlanarImage<T>,
color: &Cicp,
) -> Result<Av2Frame, EncodeError> {
img.validate_444()?;
validate_dims(img.width as u32, img.height as u32)?;
let bd = img.bit_depth;
let maxv = (1i32 << bd.bits()) - 1;
let off_q = (1i32 << (bd.bits() - 1)) << Q;
let mx_i = maxv;
let n = img.planes[0].len();
let mut effective_color = *color;
let (y, cb, cr) = if self.base_q_idx == 0 {
effective_color.matrix = crate::color::MatrixCoefficients::Identity;
let y = img.planes[0].iter().map(|x| x.to_i32()).collect::<Vec<_>>();
let cb = img.planes[1].iter().map(|x| x.to_i32()).collect::<Vec<_>>();
let cr = img.planes[2].iter().map(|x| x.to_i32()).collect::<Vec<_>>();
(y, cb, cr)
} else {
let (mut y, mut cb, mut cr) = (vec![0i32; n], vec![0i32; n], vec![0i32; n]);
for (((((yv, cbv), crv), &rr), &gg), &bb) in y
.iter_mut()
.zip(cb.iter_mut())
.zip(cr.iter_mut())
.zip(img.planes[2].iter())
.zip(img.planes[0].iter())
.zip(img.planes[1].iter())
{
let (ri, gi, bi) = (rr.to_i32(), gg.to_i32(), bb.to_i32());
*yv = ((Y_R * ri + Y_G * gi + Y_B * bi + HALF) >> Q).clamp(0, mx_i);
*cbv = ((CB_R * ri + CB_G * gi + CB_B * bi + off_q + HALF) >> Q).clamp(0, mx_i);
*crv = ((CR_R * ri + CR_G * gi + CR_B * bi + off_q + HALF) >> Q).clamp(0, mx_i);
}
(y, cb, cr)
};
self.encode_yuv444(
&PlanarImage {
width: img.width,
height: img.height,
bit_depth: img.bit_depth,
planes: [y, cb, cr, Vec::new()],
},
&effective_color,
)
}
}