ffmpeg: process all subtitle streams

This commit is contained in:
prj-2501 2023-06-20 00:08:34 +05:30
parent 58345767dc
commit be4b4fb8fe

View File

@ -54,7 +54,7 @@ struct FFprobeOutput {
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct FFprobeStream { struct FFprobeStream {
codec_type: String, // video,audio,subtitle index: i32, // stream index
} }
#[async_trait] #[async_trait]
@ -80,17 +80,13 @@ impl WritingFileAdapter for FFmpegAdapter {
} }
let inp_fname = filepath_hint; let inp_fname = filepath_hint;
let spawn_fail = |e| map_exe_error(e, "ffprobe", "Make sure you have ffmpeg installed."); let spawn_fail = |e| map_exe_error(e, "ffprobe", "Make sure you have ffmpeg installed.");
let has_subtitles = { let subtitle_streams = {
let probe = Command::new("ffprobe") let probe = Command::new("ffprobe")
.args(vec![ .args(vec![
"-v", "-v", "error", // show all errors
"error", "-select_streams", "s", // show only subtitle streams
"-select_streams", "-of", "json", // use json as output format
"s", "-show_entries", "stream=index", // show index of subtitle streams
"-of",
"json",
"-show_entries",
"stream=codec_type",
]) ])
.arg("-i") .arg("-i")
.arg(&inp_fname) .arg(&inp_fname)
@ -105,7 +101,7 @@ impl WritingFileAdapter for FFmpegAdapter {
)); ));
} }
let p: FFprobeOutput = serde_json::from_slice(&probe.stdout)?; let p: FFprobeOutput = serde_json::from_slice(&probe.stdout)?;
!p.streams.is_empty() p.streams
}; };
{ {
// extract file metadata (especially chapter names in a greppable format) // extract file metadata (especially chapter names in a greppable format)
@ -138,31 +134,34 @@ impl WritingFileAdapter for FFmpegAdapter {
return Err(format_err!("ffprobe failed: {:?}", exit)); return Err(format_err!("ffprobe failed: {:?}", exit));
} }
} }
if has_subtitles { if subtitle_streams.len() > 0 {
// extract subtitles for probe_stream in subtitle_streams.iter() {
let mut cmd = Command::new("ffmpeg"); // extract subtitles
cmd.arg("-hide_banner") let mut cmd = Command::new("ffmpeg");
.arg("-loglevel") cmd.arg("-hide_banner")
.arg("panic") .arg("-loglevel").arg("panic")
.arg("-i") .arg("-i")
.arg(&inp_fname) .arg(&inp_fname)
.arg("-f") .arg("-map")
.arg("webvtt") .arg(format!("0:{}", probe_stream.index.to_string())) // 0 for first input
.arg("-"); .arg("-f")
let mut cmd = cmd.stdout(Stdio::piped()).spawn().map_err(spawn_fail)?; .arg("webvtt")
let stdo = cmd.stdout.as_mut().expect("is piped"); .arg("-");
let time_re = Regex::new(r".*\d.*-->.*\d.*").unwrap(); let mut cmd = cmd.stdout(Stdio::piped()).spawn().map_err(spawn_fail)?;
let mut time: String = "".to_owned(); let stdo = cmd.stdout.as_mut().expect("is piped");
// rewrite subtitle times so they are shown as a prefix in every line let time_re = Regex::new(r".*\d.*-->.*\d.*").unwrap();
let mut lines = BufReader::new(stdo).lines(); let mut time: String = "".to_owned();
while let Some(line) = lines.next_line().await? { // rewrite subtitle times so they are shown as a prefix in every line
// 09:55.195 --> 09:56.730 let mut lines = BufReader::new(stdo).lines();
if time_re.is_match(&line) { while let Some(line) = lines.next_line().await? {
time = line.to_owned(); // 09:55.195 --> 09:56.730
} else if line.is_empty() { if time_re.is_match(&line) {
async_writeln!(oup)?; time = line.to_owned();
} else { } else if line.is_empty() {
async_writeln!(oup, "{time}: {line}")?; async_writeln!(oup)?;
} else {
async_writeln!(oup, "{time}: {line}")?;
}
} }
} }
} }