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