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,
|
||||
|
||||
/// The memory limit for external tools like ffmpeg.
|
||||
#[clap(short, long, default_value = "8G")]
|
||||
#[clap(short, long, default_value = "12G")]
|
||||
mem_limit: String,
|
||||
|
||||
/// Transcode the final video clip down to the minimum resolution specified.
|
||||
#[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 {
|
||||
|
@ -133,6 +138,7 @@ struct ProjectLecture {
|
|||
#[derive(Deserialize, Serialize)]
|
||||
struct ProjectSource {
|
||||
files: Vec<String>,
|
||||
stereo: bool,
|
||||
|
||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||
start: Option<Time>,
|
||||
|
@ -171,6 +177,18 @@ struct ProjectProgress {
|
|||
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 {
|
||||
let mut stdout = io::stdout().lock();
|
||||
let mut stdin = io::stdin().lock();
|
||||
|
@ -212,7 +230,9 @@ fn main() {
|
|||
let entry = entry.unwrap();
|
||||
let name = entry.file_name();
|
||||
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()
|
||||
{
|
||||
files.push(String::from(name));
|
||||
|
@ -220,12 +240,19 @@ fn main() {
|
|||
}
|
||||
files.sort_unstable();
|
||||
assert!(!files.is_empty());
|
||||
|
||||
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 {
|
||||
lecture: ProjectLecture { course, date },
|
||||
source: ProjectSource {
|
||||
files,
|
||||
stereo: args.stereo,
|
||||
start: None,
|
||||
end: None,
|
||||
fast: Vec::new(),
|
||||
|
|
|
@ -157,7 +157,9 @@ enum FfmpegFilter {
|
|||
filters: Vec<Filter>,
|
||||
output: Cow<'static, str>
|
||||
},
|
||||
Loudnorm,
|
||||
Loudnorm {
|
||||
stereo: bool
|
||||
},
|
||||
Rescale(Resolution)
|
||||
}
|
||||
|
||||
|
@ -216,10 +218,14 @@ impl Ffmpeg {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn enable_loudnorm(&mut self) -> &mut Self {
|
||||
pub fn enable_loudnorm(&mut self, loudnorm_stereo: bool) -> &mut Self {
|
||||
match &mut self.filter {
|
||||
FfmpegFilter::None => self.filter = FfmpegFilter::Loudnorm,
|
||||
FfmpegFilter::Loudnorm => {},
|
||||
FfmpegFilter::None => {
|
||||
self.filter = FfmpegFilter::Loudnorm {
|
||||
stereo: loudnorm_stereo
|
||||
}
|
||||
},
|
||||
FfmpegFilter::Loudnorm { stereo } if *stereo == loudnorm_stereo => {},
|
||||
_ => panic!("An incompatible type of filter has been set before")
|
||||
}
|
||||
self
|
||||
|
@ -228,7 +234,6 @@ impl Ffmpeg {
|
|||
pub fn rescale_video(&mut self, res: Resolution) -> &mut Self {
|
||||
match &mut self.filter {
|
||||
FfmpegFilter::None => self.filter = FfmpegFilter::Rescale(res),
|
||||
FfmpegFilter::Loudnorm => {},
|
||||
_ => panic!("An incompatible type of filter has been set before")
|
||||
}
|
||||
self
|
||||
|
@ -243,7 +248,7 @@ impl Ffmpeg {
|
|||
let (vdec, venc, aenc) = match &self.filter {
|
||||
FfmpegFilter::None => (false, false, false),
|
||||
FfmpegFilter::Filters { .. } => (false, true, true),
|
||||
FfmpegFilter::Loudnorm => (false, false, true),
|
||||
FfmpegFilter::Loudnorm { .. } => (false, false, true),
|
||||
FfmpegFilter::Rescale(_) => (true, true, false)
|
||||
};
|
||||
|
||||
|
@ -286,7 +291,7 @@ impl Ffmpeg {
|
|||
cmd.arg("-map").arg("[v]");
|
||||
cmd.arg("-map").arg(channel('a', &output));
|
||||
},
|
||||
FfmpegFilter::Loudnorm => {
|
||||
FfmpegFilter::Loudnorm { stereo: false } => {
|
||||
cmd.arg("-af").arg(concat!(
|
||||
"pan=mono|c0=FR,",
|
||||
"loudnorm=dual_mono=true:print_format=summary,",
|
||||
|
@ -294,6 +299,10 @@ impl Ffmpeg {
|
|||
"aformat=sample_rates=48000"
|
||||
));
|
||||
},
|
||||
FfmpegFilter::Loudnorm { stereo: true } => {
|
||||
cmd.arg("-af")
|
||||
.arg("loudnorm=print_format=summary,aformat=sample_rates=48000");
|
||||
},
|
||||
FfmpegFilter::Rescale(res) => {
|
||||
cmd.arg("-vf").arg(if vaapi {
|
||||
format!("scale_vaapi=w={}:h={}", res.width(), res.height())
|
||||
|
|
|
@ -211,7 +211,7 @@ impl<'a> Renderer<'a> {
|
|||
concat: true,
|
||||
..FfmpegInput::new(recording_txt)
|
||||
});
|
||||
ffmpeg.enable_loudnorm();
|
||||
ffmpeg.enable_loudnorm(project.source.stereo);
|
||||
ffmpeg.run()?;
|
||||
|
||||
let width = ffprobe_video("stream=width", &recording_mkv)?.parse()?;
|
||||
|
|
Loading…
Reference in a new issue