use std::fmt;
use vacc_core::encoder::EncoderConfig as CoreEncoderConfig;
use vacc_image::ImageConfig;
use crate::backend::Backend;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DecoderConfig {
order: Vec<Backend>,
image: ImageConfig,
gpu: bool,
}
impl DecoderConfig {
pub fn new(order: impl IntoIterator<Item = Backend>) -> Self {
let mut seen = [false; 4];
let mut out = Vec::new();
for b in order {
let idx = match b {
Backend::Vulkan => 0,
Backend::Nvdec => 1,
Backend::Vaapi => 2,
Backend::Software => 3,
};
if !seen[idx] {
seen[idx] = true;
out.push(b);
}
}
Self { order: out, image: ImageConfig::default(), gpu: false }
}
pub fn with_image(mut self, image: ImageConfig) -> Self {
self.image = image;
self
}
pub fn with_gpu(mut self) -> Self {
self.gpu = true;
self
}
pub const fn gpu(&self) -> bool {
self.gpu
}
pub fn default_order() -> Self {
Self::new(Backend::ALL)
}
pub fn only(backend: Backend) -> Self {
Self::new([backend])
}
pub fn order(&self) -> &[Backend] {
&self.order
}
pub fn is_empty(&self) -> bool {
self.order.is_empty()
}
pub const fn image(&self) -> ImageConfig {
self.image
}
}
impl Default for DecoderConfig {
fn default() -> Self {
Self::default_order()
}
}
impl FromIterator<Backend> for DecoderConfig {
fn from_iter<I: IntoIterator<Item = Backend>>(iter: I) -> Self {
Self::new(iter)
}
}
impl fmt::Display for DecoderConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let names: Vec<&str> = self.order.iter().map(|b| b.name()).collect();
f.write_str(&names.join(" -> "))?;
if !self.image.is_noop() {
write!(f, " [image")?;
if let Some(s) = self.image.scale {
write!(f, " scale={}x{}:{}", s.width, s.height, filter_name(s.filter))?;
}
if let Some(r) = self.image.rgb {
write!(f, " rgb={}", if r == vacc_image::RgbChannels::Rgb24 { "rgb24" } else { "rgba32" })?;
}
f.write_str("]")?;
}
if self.gpu {
f.write_str(" [gpu]")?;
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct EncoderConfig {
params: CoreEncoderConfig,
order: Vec<Backend>,
}
impl EncoderConfig {
pub fn new(params: CoreEncoderConfig) -> Self {
Self { params, order: Backend::ENCODE_ALL.to_vec() }
}
pub fn with_backends(mut self, order: impl IntoIterator<Item = Backend>) -> Self {
let mut seen = [false; 4];
let mut out = Vec::new();
for b in order {
let idx = match b {
Backend::Vulkan => 0,
Backend::Nvdec => 1,
Backend::Vaapi => 2,
Backend::Software => 3,
};
if !seen[idx] {
seen[idx] = true;
out.push(b);
}
}
self.order = out;
self
}
pub fn only(backend: Backend, params: CoreEncoderConfig) -> Self {
Self::new(params).with_backends([backend])
}
pub const fn params(&self) -> &CoreEncoderConfig {
&self.params
}
pub fn into_params(self) -> CoreEncoderConfig {
self.params
}
pub fn order(&self) -> &[Backend] {
&self.order
}
pub fn is_empty(&self) -> bool {
self.order.is_empty()
}
}
impl Default for EncoderConfig {
fn default() -> Self {
Self::new(CoreEncoderConfig::default())
}
}
impl fmt::Display for EncoderConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let names: Vec<&str> = self.order.iter().map(|b| b.name()).collect();
write!(f, "{} ({}x{} qp={} {}fps)", names.join(" -> "), self.params.width, self.params.height, self.params.qp, self.params.fps_num)
}
}
fn filter_name(filter: vacc_image::Interpolation) -> &'static str {
match filter {
vacc_image::Interpolation::Nearest => "nearest",
vacc_image::Interpolation::Box => "box",
vacc_image::Interpolation::Bilinear => "bilinear",
vacc_image::Interpolation::Bicubic => "bicubic",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_order_is_vulkan_nvdec_vaapi_software() {
let cfg = DecoderConfig::default();
assert_eq!(
cfg.order(),
&[Backend::Vulkan, Backend::Nvdec, Backend::Vaapi, Backend::Software]
);
assert_eq!(cfg.to_string(), "vulkan -> nvdec -> vaapi -> software");
}
#[test]
fn new_dedups_preserving_order() {
let cfg = DecoderConfig::new([
Backend::Software,
Backend::Nvdec,
Backend::Software,
Backend::Vulkan,
]);
assert_eq!(cfg.order(), &[Backend::Software, Backend::Nvdec, Backend::Vulkan]);
}
#[test]
fn only_single_backend() {
let cfg = DecoderConfig::only(Backend::Vaapi);
assert_eq!(cfg.order(), &[Backend::Vaapi]);
}
}