use std::fmt;
use crate::format::{MediaType, PixelFormat};
pub const DEFAULT_PRIORITY: i32 = 100;
#[derive(Clone, Debug)]
pub struct CodecCapabilities {
pub decode: bool,
pub encode: bool,
pub media_type: MediaType,
pub intra_only: bool,
pub lossy: bool,
pub lossless: bool,
pub hardware_accelerated: bool,
pub implementation: String,
pub max_width: Option<u32>,
pub max_height: Option<u32>,
pub max_bitrate: Option<u64>,
pub max_sample_rate: Option<u32>,
pub max_channels: Option<u16>,
pub priority: i32,
pub accepted_pixel_formats: Vec<PixelFormat>,
}
impl CodecCapabilities {
pub fn audio(implementation: impl Into<String>) -> Self {
Self {
decode: false,
encode: false,
media_type: MediaType::Audio,
intra_only: true, lossy: false,
lossless: false,
hardware_accelerated: false,
implementation: implementation.into(),
max_width: None,
max_height: None,
max_bitrate: None,
max_sample_rate: None,
max_channels: None,
priority: DEFAULT_PRIORITY,
accepted_pixel_formats: Vec::new(),
}
}
pub fn video(implementation: impl Into<String>) -> Self {
Self {
decode: false,
encode: false,
media_type: MediaType::Video,
intra_only: false,
lossy: false,
lossless: false,
hardware_accelerated: false,
implementation: implementation.into(),
max_width: None,
max_height: None,
max_bitrate: None,
max_sample_rate: None,
max_channels: None,
priority: DEFAULT_PRIORITY,
accepted_pixel_formats: Vec::new(),
}
}
pub fn flag_string(&self) -> String {
let mut s = String::with_capacity(6);
s.push(if self.decode { 'D' } else { '.' });
s.push(if self.encode { 'E' } else { '.' });
s.push(match self.media_type {
MediaType::Video => 'V',
MediaType::Audio => 'A',
MediaType::Subtitle => 'S',
MediaType::Data => 'D',
MediaType::Unknown => '.',
});
s.push(if self.intra_only { 'I' } else { '.' });
s.push(if self.lossy { 'L' } else { '.' });
s.push(if self.lossless { 'S' } else { '.' });
s
}
pub fn with_decode(mut self) -> Self {
self.decode = true;
self
}
pub fn with_encode(mut self) -> Self {
self.encode = true;
self
}
pub fn with_intra_only(mut self, v: bool) -> Self {
self.intra_only = v;
self
}
pub fn with_lossy(mut self, v: bool) -> Self {
self.lossy = v;
self
}
pub fn with_lossless(mut self, v: bool) -> Self {
self.lossless = v;
self
}
pub fn with_hardware(mut self, v: bool) -> Self {
self.hardware_accelerated = v;
self
}
pub fn with_priority(mut self, p: i32) -> Self {
self.priority = p;
self
}
pub fn with_max_size(mut self, w: u32, h: u32) -> Self {
self.max_width = Some(w);
self.max_height = Some(h);
self
}
pub fn with_max_bitrate(mut self, br: u64) -> Self {
self.max_bitrate = Some(br);
self
}
pub fn with_max_sample_rate(mut self, sr: u32) -> Self {
self.max_sample_rate = Some(sr);
self
}
pub fn with_max_channels(mut self, ch: u16) -> Self {
self.max_channels = Some(ch);
self
}
pub fn with_pixel_format(mut self, fmt: PixelFormat) -> Self {
self.accepted_pixel_formats.push(fmt);
self
}
pub fn with_pixel_formats(mut self, fmts: Vec<PixelFormat>) -> Self {
self.accepted_pixel_formats = fmts;
self
}
}
impl fmt::Display for CodecCapabilities {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.flag_string(), self.implementation)
}
}
#[derive(Clone, Debug, Default)]
pub struct CodecPreferences {
pub prefer: Vec<String>,
pub exclude: Vec<String>,
pub no_hardware: bool,
pub boost: i32,
}
impl CodecPreferences {
pub fn excludes(&self, caps: &CodecCapabilities) -> bool {
self.exclude.iter().any(|n| n == &caps.implementation)
|| (self.no_hardware && caps.hardware_accelerated)
}
pub fn effective_priority(&self, caps: &CodecCapabilities) -> i32 {
if self.prefer.iter().any(|n| n == &caps.implementation) {
caps.priority - self.boost.max(0)
} else {
caps.priority
}
}
}