allow preprocessing to keep stereo; asks which files to use
This commit is contained in:
parent
f4adda912a
commit
5c50b33251
3 changed files with 47 additions and 11 deletions
33
src/main.rs
33
src/main.rs
|
@ -37,12 +37,17 @@ struct Args {
|
||||||
course: String,
|
course: String,
|
||||||
|
|
||||||
/// The memory limit for external tools like ffmpeg.
|
/// The memory limit for external tools like ffmpeg.
|
||||||
#[clap(short, long, default_value = "8G")]
|
#[clap(short, long, default_value = "12G")]
|
||||||
mem_limit: String,
|
mem_limit: String,
|
||||||
|
|
||||||
/// Transcode the final video clip down to the minimum resolution specified.
|
/// Transcode the final video clip down to the minimum resolution specified.
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
transcode: Option<Resolution>
|
transcode: Option<Resolution>,
|
||||||
|
|
||||||
|
/// Treat the audio as stereo. By default, only one channel from the input stereo will
|
||||||
|
/// be used, assuming either the other channel is backup or the same as the used.
|
||||||
|
#[clap(short, long, default_value = "false")]
|
||||||
|
stereo: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! resolutions {
|
macro_rules! resolutions {
|
||||||
|
@ -133,6 +138,7 @@ struct ProjectLecture {
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
struct ProjectSource {
|
struct ProjectSource {
|
||||||
files: Vec<String>,
|
files: Vec<String>,
|
||||||
|
stereo: bool,
|
||||||
|
|
||||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||||
start: Option<Time>,
|
start: Option<Time>,
|
||||||
|
@ -171,6 +177,18 @@ struct ProjectProgress {
|
||||||
transcoded: BTreeSet<Resolution>
|
transcoded: BTreeSet<Resolution>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ask(question: impl Display) -> String {
|
||||||
|
let mut stdout = io::stdout().lock();
|
||||||
|
let mut stdin = io::stdin().lock();
|
||||||
|
|
||||||
|
writeln!(stdout, "{question}").unwrap();
|
||||||
|
let mut line = String::new();
|
||||||
|
write!(stdout, "> ").unwrap();
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
stdin.read_line(&mut line).unwrap();
|
||||||
|
line.trim().to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
fn ask_time(question: impl Display) -> Time {
|
fn ask_time(question: impl Display) -> Time {
|
||||||
let mut stdout = io::stdout().lock();
|
let mut stdout = io::stdout().lock();
|
||||||
let mut stdin = io::stdin().lock();
|
let mut stdin = io::stdin().lock();
|
||||||
|
@ -212,7 +230,9 @@ fn main() {
|
||||||
let entry = entry.unwrap();
|
let entry = entry.unwrap();
|
||||||
let name = entry.file_name();
|
let name = entry.file_name();
|
||||||
let lower = name.to_ascii_lowercase();
|
let lower = name.to_ascii_lowercase();
|
||||||
if (lower.ends_with(".mp4") || lower.ends_with(".mts"))
|
if (lower.ends_with(".mp4")
|
||||||
|
|| lower.ends_with(".mts")
|
||||||
|
|| lower.ends_with(".mkv"))
|
||||||
&& entry.file_type().unwrap().is_file()
|
&& entry.file_type().unwrap().is_file()
|
||||||
{
|
{
|
||||||
files.push(String::from(name));
|
files.push(String::from(name));
|
||||||
|
@ -220,12 +240,19 @@ fn main() {
|
||||||
}
|
}
|
||||||
files.sort_unstable();
|
files.sort_unstable();
|
||||||
assert!(!files.is_empty());
|
assert!(!files.is_empty());
|
||||||
|
|
||||||
println!("I found the following source files: {files:?}");
|
println!("I found the following source files: {files:?}");
|
||||||
|
files = ask("Which source files would you like to use? (specify multiple files separated by whitespace)")
|
||||||
|
.split_ascii_whitespace()
|
||||||
|
.map(String::from)
|
||||||
|
.collect();
|
||||||
|
assert!(!files.is_empty());
|
||||||
|
|
||||||
let project = Project {
|
let project = Project {
|
||||||
lecture: ProjectLecture { course, date },
|
lecture: ProjectLecture { course, date },
|
||||||
source: ProjectSource {
|
source: ProjectSource {
|
||||||
files,
|
files,
|
||||||
|
stereo: args.stereo,
|
||||||
start: None,
|
start: None,
|
||||||
end: None,
|
end: None,
|
||||||
fast: Vec::new(),
|
fast: Vec::new(),
|
||||||
|
|
|
@ -157,7 +157,9 @@ enum FfmpegFilter {
|
||||||
filters: Vec<Filter>,
|
filters: Vec<Filter>,
|
||||||
output: Cow<'static, str>
|
output: Cow<'static, str>
|
||||||
},
|
},
|
||||||
Loudnorm,
|
Loudnorm {
|
||||||
|
stereo: bool
|
||||||
|
},
|
||||||
Rescale(Resolution)
|
Rescale(Resolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,10 +218,14 @@ impl Ffmpeg {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_loudnorm(&mut self) -> &mut Self {
|
pub fn enable_loudnorm(&mut self, loudnorm_stereo: bool) -> &mut Self {
|
||||||
match &mut self.filter {
|
match &mut self.filter {
|
||||||
FfmpegFilter::None => self.filter = FfmpegFilter::Loudnorm,
|
FfmpegFilter::None => {
|
||||||
FfmpegFilter::Loudnorm => {},
|
self.filter = FfmpegFilter::Loudnorm {
|
||||||
|
stereo: loudnorm_stereo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FfmpegFilter::Loudnorm { stereo } if *stereo == loudnorm_stereo => {},
|
||||||
_ => panic!("An incompatible type of filter has been set before")
|
_ => panic!("An incompatible type of filter has been set before")
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -228,7 +234,6 @@ impl Ffmpeg {
|
||||||
pub fn rescale_video(&mut self, res: Resolution) -> &mut Self {
|
pub fn rescale_video(&mut self, res: Resolution) -> &mut Self {
|
||||||
match &mut self.filter {
|
match &mut self.filter {
|
||||||
FfmpegFilter::None => self.filter = FfmpegFilter::Rescale(res),
|
FfmpegFilter::None => self.filter = FfmpegFilter::Rescale(res),
|
||||||
FfmpegFilter::Loudnorm => {},
|
|
||||||
_ => panic!("An incompatible type of filter has been set before")
|
_ => panic!("An incompatible type of filter has been set before")
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -243,7 +248,7 @@ impl Ffmpeg {
|
||||||
let (vdec, venc, aenc) = match &self.filter {
|
let (vdec, venc, aenc) = match &self.filter {
|
||||||
FfmpegFilter::None => (false, false, false),
|
FfmpegFilter::None => (false, false, false),
|
||||||
FfmpegFilter::Filters { .. } => (false, true, true),
|
FfmpegFilter::Filters { .. } => (false, true, true),
|
||||||
FfmpegFilter::Loudnorm => (false, false, true),
|
FfmpegFilter::Loudnorm { .. } => (false, false, true),
|
||||||
FfmpegFilter::Rescale(_) => (true, true, false)
|
FfmpegFilter::Rescale(_) => (true, true, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -286,7 +291,7 @@ impl Ffmpeg {
|
||||||
cmd.arg("-map").arg("[v]");
|
cmd.arg("-map").arg("[v]");
|
||||||
cmd.arg("-map").arg(channel('a', &output));
|
cmd.arg("-map").arg(channel('a', &output));
|
||||||
},
|
},
|
||||||
FfmpegFilter::Loudnorm => {
|
FfmpegFilter::Loudnorm { stereo: false } => {
|
||||||
cmd.arg("-af").arg(concat!(
|
cmd.arg("-af").arg(concat!(
|
||||||
"pan=mono|c0=FR,",
|
"pan=mono|c0=FR,",
|
||||||
"loudnorm=dual_mono=true:print_format=summary,",
|
"loudnorm=dual_mono=true:print_format=summary,",
|
||||||
|
@ -294,6 +299,10 @@ impl Ffmpeg {
|
||||||
"aformat=sample_rates=48000"
|
"aformat=sample_rates=48000"
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
FfmpegFilter::Loudnorm { stereo: true } => {
|
||||||
|
cmd.arg("-af")
|
||||||
|
.arg("loudnorm=print_format=summary,aformat=sample_rates=48000");
|
||||||
|
},
|
||||||
FfmpegFilter::Rescale(res) => {
|
FfmpegFilter::Rescale(res) => {
|
||||||
cmd.arg("-vf").arg(if vaapi {
|
cmd.arg("-vf").arg(if vaapi {
|
||||||
format!("scale_vaapi=w={}:h={}", res.width(), res.height())
|
format!("scale_vaapi=w={}:h={}", res.width(), res.height())
|
||||||
|
|
|
@ -211,7 +211,7 @@ impl<'a> Renderer<'a> {
|
||||||
concat: true,
|
concat: true,
|
||||||
..FfmpegInput::new(recording_txt)
|
..FfmpegInput::new(recording_txt)
|
||||||
});
|
});
|
||||||
ffmpeg.enable_loudnorm();
|
ffmpeg.enable_loudnorm(project.source.stereo);
|
||||||
ffmpeg.run()?;
|
ffmpeg.run()?;
|
||||||
|
|
||||||
let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?;
|
let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?;
|
||||||
|
|
Loading…
Reference in a new issue