Skip to content

Commit ed31499

Browse files
committed
Add bitrate input type
1 parent ae592d3 commit ed31499

4 files changed

Lines changed: 91 additions & 8 deletions

File tree

src/model.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use std::sync::Arc;
1+
use std::{
2+
fmt::{Display, Formatter},
3+
str::FromStr,
4+
sync::Arc,
5+
};
26

37
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48
pub(crate) enum Pane {
@@ -15,6 +19,50 @@ pub(crate) struct TrimData {
1519
pub(crate) precise: bool,
1620
}
1721

22+
#[derive(Debug, PartialEq)]
23+
pub(crate) enum BitrateType {
24+
K,
25+
M,
26+
}
27+
pub(crate) struct Bitrate(pub u32, pub BitrateType);
28+
29+
impl Display for BitrateType {
30+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
31+
write!(f, "{}", if *self == BitrateType::K { "k" } else { "M" })
32+
}
33+
}
34+
35+
impl Display for Bitrate {
36+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37+
if self.0 == 0 {
38+
write!(f, "0")
39+
} else {
40+
write!(f, "{}{}", self.0, self.1)
41+
}
42+
}
43+
}
44+
45+
impl FromStr for Bitrate {
46+
type Err = &'static str;
47+
fn from_str(s: &str) -> Result<Self, Self::Err> {
48+
let s = s.trim();
49+
let (value_str, unit_str) = s
50+
.find(|c: char| !c.is_ascii_digit())
51+
.map_or((s, ""), |idx| s.split_at(idx));
52+
if value_str.is_empty() {
53+
Ok(Bitrate(0, BitrateType::K))
54+
} else {
55+
let value = value_str.parse::<u32>().map_err(|_| "Invalid value")?;
56+
let unit = match unit_str.to_ascii_lowercase().as_str() {
57+
"" | "k" | "K" => BitrateType::K,
58+
"m" | "M" => BitrateType::M,
59+
_ => return Err("Invalid unit"),
60+
};
61+
Ok(Bitrate(value, unit))
62+
}
63+
}
64+
}
65+
1866
pub(crate) type ValidationCallback = Arc<dyn Fn(&str) -> Result<String, &str> + Send + Sync>;
1967
pub(crate) type ValueFormatter = Arc<dyn Fn(&str) -> String + Send + Sync>;
2068

@@ -23,6 +71,7 @@ pub(crate) enum InputType {
2371
Integer,
2472
PositiveInteger,
2573
PositiveDecimal,
74+
Bitrate,
2675
}
2776

2877
#[derive(Debug, Clone, Copy)]

src/params/parameter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl Parameter {
208208
name: Arc::from(self.name.clone()), // todo: global param name to Arc
209209
value: value.clone(),
210210
constraints: *constraints,
211-
validator: Arc::clone(&validator),
211+
validator: Arc::clone(validator),
212212
}));
213213
}
214214
ParameterData::Trim(data) => {

src/params/video_bitrate.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use std::sync::Arc;
2+
13
use crate::{
2-
params::{Parameter, ParameterData, SelectOption, macros::select_non_default_option},
4+
model::{Bitrate, BitrateType, InputConstraints, InputType},
5+
params::{Parameter, ParameterData, SelectOption, macros::select_non_default_custom_value},
36
visitors::CommandBuilder,
47
};
58

@@ -8,26 +11,54 @@ pub(crate) struct VideoBitrate;
811
impl VideoBitrate {
912
pub(crate) const ID: &'static str = "vbitrate";
1013
pub(crate) const NAME: &'static str = "Video Bitrate";
11-
const DEFAULT: &'static str = "auto";
14+
const DEFAULT: &'static str = "0";
1215
const VARIANTS: [&str; 12] = [
13-
"16k", "32k", "auto", "64k", "128k", "256k", "512k", "1M", "2M", "4M", "8M", "16M",
16+
"16k", "32k", "0", "64k", "128k", "256k", "512k", "1M", "2M", "4M", "8M", "16M",
1417
];
1518

1619
pub fn new_parameter() -> Parameter {
1720
Parameter::new(
1821
Self::ID,
1922
Self::NAME,
20-
ParameterData::Select {
23+
ParameterData::CustomSelect {
2124
options: SelectOption::from_slice(&Self::VARIANTS),
2225
selected_index: 2,
26+
value: Self::DEFAULT.to_owned(),
27+
constraints: InputConstraints {
28+
length: 5,
29+
input_type: InputType::Bitrate,
30+
},
31+
validator: Arc::new(Self::validate),
32+
formatter: Some(Arc::new(Self::format_value)),
2333
},
2434
)
2535
}
2636

37+
fn validate(value: &str) -> Result<String, &str> {
38+
if let Ok(bitrate) = value.parse::<Bitrate>()
39+
&& let Bitrate(value, unit) = &bitrate
40+
&& (*value == 0
41+
|| ((4..=9999).contains(value) && *unit == BitrateType::K)
42+
|| ((1..=999).contains(value) && *unit == BitrateType::M))
43+
{
44+
Ok(bitrate.to_string())
45+
} else {
46+
Err("Invalid value. Expected a number in range 4k..999M, or 0 - auto")
47+
}
48+
}
49+
50+
fn format_value(value: &str) -> String {
51+
if value == Self::DEFAULT {
52+
"auto".to_owned()
53+
} else {
54+
value.to_owned()
55+
}
56+
}
57+
2758
pub fn build_command(cb: &mut CommandBuilder, data: &ParameterData) {
28-
if let Some(option) = select_non_default_option!(data) {
59+
if let Some(value) = select_non_default_custom_value!(data) {
2960
cb.args.push("-b:v".into());
30-
cb.args.push(option.value.clone());
61+
cb.args.push(Self::format_value(value));
3162
}
3263
}
3364
}

src/ui/modal_custom_select.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ impl KeyboardHandler for CustomSelectModal {
8282
| (InputType::PositiveDecimal, '0'..='9' | '.') => {
8383
self.input.handle_event(&Event::Key(key));
8484
}
85+
(InputType::Bitrate, '0'..='9' | 'k' | 'K' | 'm' | 'M') => {
86+
self.input.handle_event(&Event::Key(key));
87+
}
8588
_ => {}
8689
}
8790
}

0 commit comments

Comments
 (0)