use faster seeking in ffmpeg

This commit is contained in:
Luna 2023-06-11 23:00:12 -03:00
parent 1875d3fd48
commit 61250ffaa2

View file

@ -171,18 +171,21 @@ async fn fetch_frame_as_image(
input_path: &str,
output_path: &str,
frame_index: usize,
frame_rate: f64, // X/1sec
) -> anyhow::Result<()> {
let frame_index_param = format!("select=eq(n\\,{})", frame_index);
let timeline_index: f64 = frame_index as f64 / frame_rate;
let timeline_index_param = format!("{:.5}", timeline_index);
let builder = ffmpeg_cli::FfmpegBuilder::new()
.stderr(Stdio::piped())
.option(Parameter::Single("nostdin"))
.option(Parameter::Single("y"))
.input(ffmpeg_cli::File::new(input_path))
.output(
ffmpeg_cli::File::new(output_path)
.option(Parameter::KeyValue("vf", &frame_index_param))
.option(Parameter::KeyValue("vframes", "1")),
);
// fast seeking with -ss instead of select filter
.input(
ffmpeg_cli::File::new(input_path)
.option(Parameter::KeyValue("ss", &timeline_index_param)),
)
.output(ffmpeg_cli::File::new(output_path).option(Parameter::KeyValue("vframes", "1")));
log::debug!("running {:?}", builder);
let ffmpeg = builder.run().await.unwrap();
@ -259,36 +262,41 @@ async fn upload_file(
let frame_rate_str = stream.r_frame_rate.clone();
let parts = frame_rate_str.split("/").into_iter().collect::<Vec<_>>();
let frame_rate =
parts.get(0).unwrap().parse::<u32>()? / parts.get(1).unwrap().parse::<u32>()?;
let frame_rate: f64 =
parts.get(0).unwrap().parse::<f64>()? / parts.get(1).unwrap().parse::<f64>()?;
let total_length_in_seconds = total_frame_count / frame_rate;
let wanted_frame_skip_seconds = match total_length_in_seconds {
let total_length_in_seconds = total_frame_count as f64 / frame_rate;
let wanted_frame_skip_seconds = match total_length_in_seconds as usize {
0..=10 => 2,
11..=60 => 10,
61..=120 => 15,
121.. => 20,
};
let wanted_frame_skip = (wanted_frame_skip_seconds * frame_rate).try_into().unwrap();
121..=300 => 20,
301.. => 30,
_ => 33,
} as f64;
let wanted_frame_skip = wanted_frame_skip_seconds * frame_rate;
let temporary_frame_dir = tempfile::tempdir()?;
let temporary_frame_path =
format!("{}/frame.png", temporary_frame_dir.path().to_string_lossy());
log::info!("path: '{}'", &temporary_frame_path);
log::info!("frame path: '{}'", &temporary_frame_path);
log::info!("wanted_frame_skip: {}", &wanted_frame_skip_seconds);
for frame_number in (0..total_frame_count).step_by(wanted_frame_skip) {
for frame_number in (0..total_frame_count).step_by(wanted_frame_skip as usize) {
log::info!("extracting frame {:?}", frame_number);
fetch_frame_as_image(
temp_file.path().to_str().unwrap(),
&temporary_frame_path,
frame_number.try_into().unwrap(),
frame_rate,
)
.await?;
log::info!("extracted frame {:?}", frame_number);
let mut actual_frame_file = std::fs::File::open(&temporary_frame_path)?;
let mut frame_data = vec![];
actual_frame_file.read_to_end(&mut frame_data)?;
log::info!("sending frame {:?}", frame_number);
let tags_from_frame = if let WrappedResponse::Tags(tags_from_frame) =
send_image_to_dd(frame_data, "amongus.png".to_string(), "image/png", &options)
.await?