use std::ffi::c_int;
use crate::{Error, I420Image, ImageSize, checked_buf_size, require_c_int, sys};
pub fn i420_psnr(
src_a: &I420Image<'_>,
src_b: &I420Image<'_>,
size: ImageSize,
) -> Result<f64, Error> {
src_a.validate(size, "I420Psnr")?;
src_b.validate(size, "I420Psnr")?;
let result = unsafe {
sys::I420Psnr(
src_a.y.as_ptr(),
src_a.y_stride as c_int,
src_a.u.as_ptr(),
src_a.u_stride as c_int,
src_a.v.as_ptr(),
src_a.v_stride as c_int,
src_b.y.as_ptr(),
src_b.y_stride as c_int,
src_b.u.as_ptr(),
src_b.u_stride as c_int,
src_b.v.as_ptr(),
src_b.v_stride as c_int,
size.width as c_int,
size.height as c_int,
)
};
Ok(result)
}
pub fn i420_ssim(
src_a: &I420Image<'_>,
src_b: &I420Image<'_>,
size: ImageSize,
) -> Result<f64, Error> {
src_a.validate(size, "I420Ssim")?;
src_b.validate(size, "I420Ssim")?;
let result = unsafe {
sys::I420Ssim(
src_a.y.as_ptr(),
src_a.y_stride as c_int,
src_a.u.as_ptr(),
src_a.u_stride as c_int,
src_a.v.as_ptr(),
src_a.v_stride as c_int,
src_b.y.as_ptr(),
src_b.y_stride as c_int,
src_b.u.as_ptr(),
src_b.u_stride as c_int,
src_b.v.as_ptr(),
src_b.v_stride as c_int,
size.width as c_int,
size.height as c_int,
)
};
Ok(result)
}
pub fn calc_frame_psnr(
src_a: &[u8],
src_a_stride: usize,
src_b: &[u8],
src_b_stride: usize,
size: ImageSize,
) -> Result<f64, Error> {
require_c_int(size.width, "CalcFramePsnr", "width exceeds c_int range")?;
require_c_int(size.height, "CalcFramePsnr", "height exceeds c_int range")?;
require_c_int(
src_a_stride,
"CalcFramePsnr",
"stride A exceeds c_int range",
)?;
require_c_int(
src_b_stride,
"CalcFramePsnr",
"stride B exceeds c_int range",
)?;
if src_a_stride < size.width {
return Err(Error::with_reason(
-1,
"CalcFramePsnr",
"stride A smaller than width",
));
}
if src_b_stride < size.width {
return Err(Error::with_reason(
-1,
"CalcFramePsnr",
"stride B smaller than width",
));
}
let a_size = checked_buf_size(
src_a_stride,
size.height,
"CalcFramePsnr",
"buffer A size overflow",
)?;
if src_a.len() < a_size {
return Err(Error::with_reason(
-1,
"CalcFramePsnr",
"source A buffer too small",
));
}
let b_size = checked_buf_size(
src_b_stride,
size.height,
"CalcFramePsnr",
"buffer B size overflow",
)?;
if src_b.len() < b_size {
return Err(Error::with_reason(
-1,
"CalcFramePsnr",
"source B buffer too small",
));
}
let result = unsafe {
sys::CalcFramePsnr(
src_a.as_ptr(),
src_a_stride as c_int,
src_b.as_ptr(),
src_b_stride as c_int,
size.width as c_int,
size.height as c_int,
)
};
Ok(result)
}
pub fn calc_frame_ssim(
src_a: &[u8],
src_a_stride: usize,
src_b: &[u8],
src_b_stride: usize,
size: ImageSize,
) -> Result<f64, Error> {
require_c_int(size.width, "CalcFrameSsim", "width exceeds c_int range")?;
require_c_int(size.height, "CalcFrameSsim", "height exceeds c_int range")?;
require_c_int(
src_a_stride,
"CalcFrameSsim",
"stride A exceeds c_int range",
)?;
require_c_int(
src_b_stride,
"CalcFrameSsim",
"stride B exceeds c_int range",
)?;
if src_a_stride < size.width {
return Err(Error::with_reason(
-1,
"CalcFrameSsim",
"stride A smaller than width",
));
}
if src_b_stride < size.width {
return Err(Error::with_reason(
-1,
"CalcFrameSsim",
"stride B smaller than width",
));
}
let a_size = checked_buf_size(
src_a_stride,
size.height,
"CalcFrameSsim",
"buffer A size overflow",
)?;
if src_a.len() < a_size {
return Err(Error::with_reason(
-1,
"CalcFrameSsim",
"source A buffer too small",
));
}
let b_size = checked_buf_size(
src_b_stride,
size.height,
"CalcFrameSsim",
"buffer B size overflow",
)?;
if src_b.len() < b_size {
return Err(Error::with_reason(
-1,
"CalcFrameSsim",
"source B buffer too small",
));
}
let result = unsafe {
sys::CalcFrameSsim(
src_a.as_ptr(),
src_a_stride as c_int,
src_b.as_ptr(),
src_b_stride as c_int,
size.width as c_int,
size.height as c_int,
)
};
Ok(result)
}
pub fn compute_sum_square_error(src_a: &[u8], src_b: &[u8], count: usize) -> Result<u64, Error> {
require_c_int(count, "ComputeSumSquareError", "count exceeds c_int range")?;
if src_a.len() < count {
return Err(Error::with_reason(
-1,
"ComputeSumSquareError",
"source A buffer too small",
));
}
if src_b.len() < count {
return Err(Error::with_reason(
-1,
"ComputeSumSquareError",
"source B buffer too small",
));
}
let result =
unsafe { sys::ComputeSumSquareError(src_a.as_ptr(), src_b.as_ptr(), count as c_int) };
Ok(result)
}
pub fn compute_sum_square_error_plane(
src_a: &[u8],
src_a_stride: usize,
src_b: &[u8],
src_b_stride: usize,
size: ImageSize,
) -> Result<u64, Error> {
require_c_int(
size.width,
"ComputeSumSquareErrorPlane",
"width exceeds c_int range",
)?;
require_c_int(
size.height,
"ComputeSumSquareErrorPlane",
"height exceeds c_int range",
)?;
require_c_int(
src_a_stride,
"ComputeSumSquareErrorPlane",
"stride A exceeds c_int range",
)?;
require_c_int(
src_b_stride,
"ComputeSumSquareErrorPlane",
"stride B exceeds c_int range",
)?;
if src_a_stride < size.width {
return Err(Error::with_reason(
-1,
"ComputeSumSquareErrorPlane",
"stride A smaller than width",
));
}
if src_b_stride < size.width {
return Err(Error::with_reason(
-1,
"ComputeSumSquareErrorPlane",
"stride B smaller than width",
));
}
let a_size = checked_buf_size(
src_a_stride,
size.height,
"ComputeSumSquareErrorPlane",
"buffer A size overflow",
)?;
if src_a.len() < a_size {
return Err(Error::with_reason(
-1,
"ComputeSumSquareErrorPlane",
"source A buffer too small",
));
}
let b_size = checked_buf_size(
src_b_stride,
size.height,
"ComputeSumSquareErrorPlane",
"buffer B size overflow",
)?;
if src_b.len() < b_size {
return Err(Error::with_reason(
-1,
"ComputeSumSquareErrorPlane",
"source B buffer too small",
));
}
let result = unsafe {
sys::ComputeSumSquareErrorPlane(
src_a.as_ptr(),
src_a_stride as c_int,
src_b.as_ptr(),
src_b_stride as c_int,
size.width as c_int,
size.height as c_int,
)
};
Ok(result)
}
pub fn sum_square_error_to_psnr(sse: u64, count: u64) -> f64 {
unsafe { sys::SumSquareErrorToPsnr(sse, count) }
}
pub fn compute_hamming_distance(src_a: &[u8], src_b: &[u8]) -> Result<u64, Error> {
let count = src_a.len().min(src_b.len());
require_c_int(count, "ComputeHammingDistance", "count exceeds c_int range")?;
let result =
unsafe { sys::ComputeHammingDistance(src_a.as_ptr(), src_b.as_ptr(), count as c_int) };
Ok(result)
}
pub fn hash_djb2(src: &[u8], seed: u32) -> u32 {
unsafe { sys::HashDjb2(src.as_ptr(), src.len() as u64, seed) }
}