use faster seeking in ffmpeg
This commit is contained in:
parent
1875d3fd48
commit
61250ffaa2
1 changed files with 23 additions and 15 deletions
38
src/main.rs
38
src/main.rs
|
@ -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?
|
||||
|
|
Loading…
Reference in a new issue