diff --git a/src/ffmpeg.rs b/src/ffmpeg.rs index dbaa463..2ec0192 100644 --- a/src/ffmpeg.rs +++ b/src/ffmpeg.rs @@ -39,6 +39,23 @@ pub struct VideoMeta { pub duration_us: usize, } +#[derive(Default, Clone, Copy)] +pub enum Codec { + AV1, + #[default] + VP9, +} + +impl From for Codec { + fn from(value: String) -> Self { + match value.as_str() { + "AV1" => Self::AV1, + "VP9" => Self::VP9, + _ => Default::default(), + } + } +} + pub async fn get_video_meta(path: &Path) -> Result { let output = Command::new("ffprobe") .args([ @@ -74,25 +91,26 @@ pub async fn get_video_meta(path: &Path) -> Result { }) } -pub async fn convert_video(path: &Path, sender: Sender) -> Result { +pub async fn convert_video( + path: &Path, + out_filename: Option, + out_codec: Codec, + merge_tracks: bool, + sender: Sender, +) -> Result { let out_path = PathBuf::from("/tmp/out.webm"); + let codec_args: &[&str] = match out_codec { + Codec::AV1 => &["-c:v", "libsvtav1"], + Codec::VP9 => &["-c:v", "libvpx-vp9", "-row-mt", "1"], + }; + let mut child = Command::new("ffmpeg") .arg("-i") .arg(path) - .args([ - "-c:a", - "libopus", - "-b:a", - "96k", - "-c:v", - "libsvtav1", - "-loglevel", - "error", - "-progress", - "-", - "-nostats", - ]) + .args(["-c:a", "libopus", "-b:a", "96k"]) + .args(codec_args) + .args(["-loglevel", "error", "-progress", "-", "-nostats"]) .arg(&out_path) .stdout(Stdio::piped()) .spawn()?; diff --git a/src/main.rs b/src/main.rs index 72aed87..fb0be26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,7 @@ impl Config { enum Message { OpenFilePicker, SetOutFilename(String), + SetOutCodec(String), SetMergeTracks(bool), SetFolder(ZiplineFolder), StartTheProcess, @@ -83,6 +84,7 @@ struct UploadInfo { config: Config, video_path: Option, out_filename: Option, + out_codec: ffmpeg::Codec, merge_tracks: bool, folder: Option, } @@ -94,6 +96,7 @@ struct Tyrolienne { total: usize, video_path: Option, out_filename: Option, + out_codec: ffmpeg::Codec, merge_tracks: bool, folder: Option, dialog: Controller, @@ -112,6 +115,7 @@ impl Tyrolienne { UploadInfo { config: self.config.clone(), out_filename: self.out_filename.clone(), + out_codec: self.out_codec, merge_tracks: self.merge_tracks, video_path: self.video_path.clone(), folder: self.folder.clone(), @@ -170,6 +174,20 @@ impl AsyncComponent for Tyrolienne { connect_changed[sender] => move |e| sender.input(Message::SetOutFilename(e.text().into())), }, + adw::ComboRow { + set_title: "Output video codec", + set_model: Some(>k::StringList::new(&["VP9", "AV1"])), + connect_selected_item_notify[sender] => move |r| { + println!("{:?}", r.selected_item()); + if let Some(item) = r + .selected_item() + .and_then(|i| i.downcast::().ok()) + { + sender.input(Message::SetOutCodec(item.into())); + } + } + }, + adw::SwitchRow { set_title: "Merge audio tracks", set_active: true, @@ -180,7 +198,7 @@ impl AsyncComponent for Tyrolienne { set_title: "Zipline folder", set_model: Some(&folder_store), set_expression: Some(&folder_expression), - connect_activated[sender] => move |r| { + connect_selected_item_notify[sender] => move |r| { if let Some(item) = r .selected_item() .and_then(|i| i.downcast::().ok()) @@ -230,6 +248,7 @@ impl AsyncComponent for Tyrolienne { total: 1, video_path: None, out_filename: None, + out_codec: ffmpeg::Codec::VP9, merge_tracks: true, folder: None, dialog: Dialog::builder() @@ -293,6 +312,7 @@ impl AsyncComponent for Tyrolienne { Message::SetOutFilename(name) => { self.out_filename = if name.is_empty() { None } else { Some(name) } } + Message::SetOutCodec(codec) => self.out_codec = codec.into(), Message::SetMergeTracks(m) => self.merge_tracks = m, Message::SetFolder(folder) => { self.folder = (folder.id != GtkZiplineFolder::NONE_ID).then_some(folder) @@ -406,7 +426,14 @@ async fn the_process(app: UploadInfo, sender: &Sender) -> Resul let video_meta = ffmpeg::get_video_meta(video_path).await?; sender.emit(ProgressMessage::SetTotal(video_meta.duration_us)); - let out_path = ffmpeg::convert_video(video_path, sender.clone()).await?; + let out_path = ffmpeg::convert_video( + video_path, + app.out_filename, + app.out_codec, + app.merge_tracks, + sender.clone(), + ) + .await?; sender.emit(ProgressMessage::SetStep(Step::Uploading)); if let Some(folder) = app.folder.as_ref() {