use anyhow::{bail, Result};
use std::os::raw::c_uint;
use crate::frame::{PixelFormat, TransferFn};
use super::constants::{NV_ENC_BUFFER_FORMAT_IYUV, NV_ENC_BUFFER_FORMAT_YUV420_10BIT};
pub(super) fn nvenc_buffer_format_for(fmt: PixelFormat) -> Result<c_uint> {
match fmt {
PixelFormat::Yuv420p => Ok(NV_ENC_BUFFER_FORMAT_IYUV),
PixelFormat::Yuv420p10le => Ok(NV_ENC_BUFFER_FORMAT_YUV420_10BIT),
other => bail!(
"NVENC AV1 expects Yuv420p or Yuv420p10le, got {other:?} \
(4:2:2 / 4:4:4 / RGB / alpha not supported on this backend)"
),
}
}
pub(super) const fn pixel_bit_depth_minus8_for(fmt: PixelFormat) -> u32 {
match fmt {
PixelFormat::Yuv420p10le => 2,
_ => 0,
}
}
pub(super) fn transfer_to_h273(tf: TransferFn) -> u32 {
match tf {
TransferFn::Bt709 => 1,
TransferFn::Bt470Bg => 4,
TransferFn::Linear => 8,
TransferFn::St2084 => 16,
TransferFn::AribStdB67 => 18,
TransferFn::Unspecified => 1,
}
}
pub(super) fn fps_to_rational(fps: f64) -> (u32, u32) {
const EXACT: &[(f64, u32, u32)] = &[
(23.976, 24_000, 1001),
(24.0, 24, 1),
(25.0, 25, 1),
(29.97, 30_000, 1001),
(30.0, 30, 1),
(48.0, 48, 1),
(50.0, 50, 1),
(59.94, 60_000, 1001),
(60.0, 60, 1),
];
for &(f, n, d) in EXACT {
if (fps - f).abs() < 1e-3 {
return (n, d);
}
}
if (fps - fps.round()).abs() < 1e-6 && fps > 0.0 {
return (fps.round() as u32, 1);
}
let k = (fps * 1001.0).round();
if (k / 1001.0 - fps).abs() < 1e-4 && k > 0.0 {
let k_u = k as u32;
return (k_u, 1001);
}
let num = (fps * 1000.0).round().max(1.0) as u32;
(num, 1000)
}
const _: () = assert!(pixel_bit_depth_minus8_for(PixelFormat::Yuv420p10le) == 2);
const _: () = assert!(pixel_bit_depth_minus8_for(PixelFormat::Yuv420p) == 0);