use std::sync::Arc;
use tracing::debug;
use crate::{
model::{InputConstraints, InputType},
params::{
Parameter, ParameterData, PresetParameter, SelectOption,
macros::select_non_default_custom_value,
},
visitors::{CommandBuilder, HWAccel, VisitorContext},
};
pub(crate) struct VideoScale;
impl VideoScale {
pub(crate) const ID: &'static str = "scale";
pub(crate) const NAME: &'static str = "Video Scale";
const DEFAULT: &'static str = "0";
const VARIANTS: [&str; 7] = ["144", "240", "360", "0", "480", "720", "1080"];
pub fn new_parameter() -> Parameter {
Parameter::new(
Self::ID,
Self::NAME,
ParameterData::CustomSelect {
options: SelectOption::from_slice(&Self::VARIANTS),
selected_index: 3,
value: Self::DEFAULT.to_owned(),
constraints: InputConstraints {
length: 4,
input_type: InputType::PositiveInteger,
},
validator: Arc::new(Self::validate),
formatter: Some(Arc::new(Self::format_value)),
},
)
}
fn validate(value: &str) -> Result<String, &str> {
Self::validate_range(value)
.and_then(Self::validate_divisible_by_2)
.map(|num| num.to_string())
}
fn validate_range(value: &str) -> Result<i32, &str> {
if let Ok(num) = value.parse::<i32>()
&& (num == 0 || (64..=8192).contains(&num))
{
Ok(num)
} else {
Err("Invalid value. Expected a number in range 64..8192, or 0 - original")
}
}
fn validate_divisible_by_2<'a>(num: i32) -> Result<i32, &'a str> {
if num % 2 == 0 {
Ok(num)
} else {
Err("Invalid value. Expected a number divisible by 2")
}
}
fn format_value(value: &str) -> String {
if value == Self::DEFAULT {
"original".to_owned()
} else {
format!("{}p", value)
}
}
pub fn build_command(cb: &mut CommandBuilder, data: &ParameterData) {
if let Some(value) = select_non_default_custom_value!(data) {
debug!(value, "build_command");
#[cfg(target_os = "windows")]
{
if (cb.hwaccel == HWAccel::Nvenc) && (cb.video_filters.is_empty()) {
cb.video_filters.push(format!("scale_cuda=-2:{}", &value));
} else {
cb.video_filters.push(format!("scale=-2:{}", &value));
}
}
#[cfg(target_os = "linux")]
{
if (cb.hwaccel == HWAccel::Nvenc) && (cb.video_filters.is_empty()) {
cb.video_filters.push(format!("scale_cuda=-2:{}", value));
} else if cb.hwaccel == HWAccel::Vaapi {
cb.video_filters.push(format!("scale_vaapi=-2:{}", value));
} else {
cb.video_filters.push(format!("scale=-2:{}", value));
}
}
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
{
cb.video_filters.push(format!("scale=-2:{}", &value));
}
}
}
}
impl<'a> PresetParameter<'a> for VideoScale {
fn apply_preset(_ctx: &VisitorContext, data: &mut ParameterData, preset_value: &str) {
if Self::validate(preset_value).is_ok() {
Self::set_parameter_value(data, preset_value);
}
}
fn save_preset(_ctx: &VisitorContext, data: &'a ParameterData) -> Option<String> {
select_non_default_custom_value!(data).cloned()
}
}