fix: conditionally disable audio track merging

This commit is contained in:
uku 2025-05-19 19:24:11 +02:00
parent 0475c52529
commit dd2616f0e5
Signed by: uku
SSH key fingerprint: SHA256:4P0aN6M8ajKukNi6aPOaX0LacanGYtlfjmN+m/sHY/o
2 changed files with 30 additions and 13 deletions

View file

@ -23,9 +23,10 @@ struct FfprobeOut {
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct StreamInfo { #[serde(tag = "codec_type", rename_all = "lowercase")]
width: usize, enum StreamInfo {
height: usize, Video { width: usize, height: usize },
Audio,
} }
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
@ -37,6 +38,7 @@ struct FormatInfo {
pub struct VideoMeta { pub struct VideoMeta {
pub width: usize, pub width: usize,
pub height: usize, pub height: usize,
pub audio_streams: usize,
pub duration_us: usize, pub duration_us: usize,
} }
@ -62,10 +64,8 @@ pub async fn get_video_meta(path: &Path) -> Result<VideoMeta> {
.args([ .args([
"-v", "-v",
"error", "error",
"-select_streams",
"v:0",
"-show_entries", "-show_entries",
"stream=width,height : format=duration", "stream=width,height,codec_type : format=duration",
"-of", "-of",
"json", "json",
]) ])
@ -77,17 +77,28 @@ pub async fn get_video_meta(path: &Path) -> Result<VideoMeta> {
let str = String::from_utf8(output.stdout)?; let str = String::from_utf8(output.stdout)?;
let output: FfprobeOut = serde_json::from_str(&str)?; let output: FfprobeOut = serde_json::from_str(&str)?;
let stream = output let (width, height) = output
.streams .streams
.first() .iter()
.find_map(|s| match s {
StreamInfo::Video { width, height } => Some((*width, *height)),
_ => None,
})
.wrap_err("could not get stream information from ffprobe")?; .wrap_err("could not get stream information from ffprobe")?;
let audio_streams = output
.streams
.iter()
.filter(|s| matches!(s, StreamInfo::Audio))
.count();
let duration_sec = output.format.duration.parse::<f64>()?; let duration_sec = output.format.duration.parse::<f64>()?;
let duration_us = (duration_sec * 1_000_000.0).ceil() as usize; let duration_us = (duration_sec * 1_000_000.0).ceil() as usize;
Ok(VideoMeta { Ok(VideoMeta {
width: stream.width, width,
height: stream.height, height,
audio_streams,
duration_us, duration_us,
}) })
} }
@ -115,7 +126,6 @@ pub async fn convert_video(
Codec::VP9 => &["-c:v", "libvpx-vp9", "-row-mt", "1"], Codec::VP9 => &["-c:v", "libvpx-vp9", "-row-mt", "1"],
}; };
// TODO: maybe check if the video has 2 audio tracks? or at least use a "fail-safe" method
let merge_args: &[&str] = if merge_tracks { let merge_args: &[&str] = if merge_tracks {
&["-ac", "2", "-filter_complex", "amerge=inputs=2"] &["-ac", "2", "-filter_complex", "amerge=inputs=2"]
} else { } else {

View file

@ -94,6 +94,7 @@ struct Tyrolienne {
step: Step, step: Step,
progress: usize, progress: usize,
total: usize, total: usize,
can_merge: bool,
video_path: Option<PathBuf>, video_path: Option<PathBuf>,
out_filename: Option<String>, out_filename: Option<String>,
out_codec: ffmpeg::Codec, out_codec: ffmpeg::Codec,
@ -116,7 +117,7 @@ impl Tyrolienne {
config: self.config.clone(), config: self.config.clone(),
out_filename: self.out_filename.clone(), out_filename: self.out_filename.clone(),
out_codec: self.out_codec, out_codec: self.out_codec,
merge_tracks: self.merge_tracks, merge_tracks: self.can_merge && self.merge_tracks,
video_path: self.video_path.clone(), video_path: self.video_path.clone(),
folder: self.folder.clone(), folder: self.folder.clone(),
} }
@ -190,7 +191,10 @@ impl AsyncComponent for Tyrolienne {
adw::SwitchRow { adw::SwitchRow {
set_title: "Merge audio tracks", set_title: "Merge audio tracks",
set_active: true, #[watch]
set_sensitive: model.can_merge,
#[watch]
set_active: model.can_merge && model.merge_tracks,
connect_active_notify[sender] => move |s| sender.input(Message::SetMergeTracks(s.is_active())), connect_active_notify[sender] => move |s| sender.input(Message::SetMergeTracks(s.is_active())),
}, },
@ -246,6 +250,7 @@ impl AsyncComponent for Tyrolienne {
step: Step::Waiting, step: Step::Waiting,
progress: 0, progress: 0,
total: 1, total: 1,
can_merge: false,
video_path: None, video_path: None,
out_filename: None, out_filename: None,
out_codec: ffmpeg::Codec::VP9, out_codec: ffmpeg::Codec::VP9,
@ -306,6 +311,8 @@ impl AsyncComponent for Tyrolienne {
.await; .await;
if let Some(file) = file { if let Some(file) = file {
let meta = ffmpeg::get_video_meta(file.path()).await;
self.can_merge = meta.map(|m| m.audio_streams == 2).unwrap_or(false);
self.video_path = Some(file.path().to_owned()); self.video_path = Some(file.path().to_owned());
} }
} }