Skip to content

Commit

Permalink
Implement zerocopy scene detection for Vapoursynth inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
shssoichiro committed May 22, 2024
1 parent 4ebdcd0 commit dbdd5e0
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 35 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion av1an-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ crossbeam-channel = "0.5.1"
crossbeam-utils = "0.8.5"
textwrap = "0.16.0"
path_abs = "0.5.1"
av-scenechange = { version = "0.10.0", default-features = false }
av-scenechange = { version = "0.11.0", default-features = false, features = [
"vapoursynth",
] }
y4m = "0.8.0"
thiserror = "1.0.30"
paste = "1.0.5"
Expand Down
70 changes: 38 additions & 32 deletions av1an-core/src/scene_detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::thread;

use ansi_term::Style;
use anyhow::bail;
use av_scenechange::decoder::Decoder;
use av_scenechange::vapoursynth::VapoursynthDecoder;
use av_scenechange::{detect_scene_changes, DetectionOptions, SceneDetectionSpeed};
use ffmpeg::format::Pixel;
use itertools::Itertools;
Expand Down Expand Up @@ -147,7 +149,7 @@ pub fn scene_detect(
frame_limit,
callback.as_ref().map(|cb| cb as &dyn Fn(usize, usize)),
)
};
}?;
if let Some(limit) = frame_limit {
if limit != sc_result.frame_count {
bail!(
Expand Down Expand Up @@ -206,7 +208,7 @@ fn build_decoder(
sc_scaler: &str,
sc_pix_format: Option<Pixel>,
sc_downscale_height: Option<usize>,
) -> anyhow::Result<(y4m::Decoder<impl Read>, usize)> {
) -> anyhow::Result<(Decoder<impl Read>, usize)> {
let bit_depth;
let filters: SmallVec<[String; 4]> = match (sc_downscale_height, sc_pix_format) {
(Some(sdh), Some(spf)) => into_smallvec![
Expand All @@ -225,53 +227,57 @@ fn build_decoder(
(None, None) => smallvec![],
};

let decoder = y4m::Decoder::new(match input {
let decoder = match input {
Input::VapourSynth(path) => {
bit_depth = crate::vapoursynth::bit_depth(path.as_ref())?;
let vspipe = Command::new("vspipe")
.arg("-c")
.arg("y4m")
.arg(path)
.arg("-")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()?
.stdout
.unwrap();

if !filters.is_empty() {
Command::new("ffmpeg")
.stdin(vspipe)
.args(["-i", "pipe:", "-f", "yuv4mpegpipe", "-strict", "-1"])
.args(filters)
let vspipe = Command::new("vspipe")
.arg("-c")
.arg("y4m")
.arg(path)
.arg("-")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()?
.stdout
.unwrap()
.unwrap();
Decoder::Y4m(y4m::Decoder::new(
Command::new("ffmpeg")
.stdin(vspipe)
.args(["-i", "pipe:", "-f", "yuv4mpegpipe", "-strict", "-1"])
.args(filters)
.arg("-")
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()?
.stdout
.unwrap(),
)?)
} else {
vspipe
Decoder::Vapoursynth(VapoursynthDecoder::new(path.as_ref())?)
}
}
Input::Video(path) => {
let input_pix_format = crate::ffmpeg::get_pixel_format(path.as_ref())
.unwrap_or_else(|e| panic!("FFmpeg failed to get pixel format for input video: {e:?}"));
bit_depth = encoder.get_format_bit_depth(sc_pix_format.unwrap_or(input_pix_format))?;
Command::new("ffmpeg")
.args(["-r", "1", "-i"])
.arg(path)
.args(filters.as_ref())
.args(["-f", "yuv4mpegpipe", "-strict", "-1", "-"])
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()?
.stdout
.unwrap()
Decoder::Y4m(y4m::Decoder::new(
Command::new("ffmpeg")
.args(["-r", "1", "-i"])
.arg(path)
.args(filters.as_ref())
.args(["-f", "yuv4mpegpipe", "-strict", "-1", "-"])
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.spawn()?
.stdout
.unwrap(),
)?)
}
})?;
};

Ok((decoder, bit_depth))
}

0 comments on commit dbdd5e0

Please sign in to comment.