Skip to content

Commit 9233243

Browse files
BoatsMcGeeBoats McGee
authored andcommitted
Fix Scene Detection frames mismatch causes invalid frame access crashes (master-of-zen#927)
* Fix frame count mismatch between FFmpeg and VapourSynth Fix Scene Detection uses incompatible decode method leading to accessing invalid frames * Fix race condition in Scene Detection causes End of File Error --------- Co-authored-by: Boats McGee <{ID}+{username}@users.noreply.github.com>
1 parent 0a77e7a commit 9233243

File tree

3 files changed

+26
-14
lines changed

3 files changed

+26
-14
lines changed

av1an-core/src/context.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl Av1anContext {
116116

117117
// frames need to be recalculated in this case
118118
if self.frames == 0 {
119-
self.frames = self.args.input.frames()?;
119+
self.frames = self.args.input.frames(self.vs_script.clone())?;
120120
done.frames.store(self.frames, atomic::Ordering::Relaxed);
121121
}
122122

@@ -726,9 +726,19 @@ impl Av1anContext {
726726
fn calc_split_locations(&self) -> anyhow::Result<(Vec<Scene>, usize)> {
727727
let zones = self.parse_zones()?;
728728

729+
// Create a new input with the generated VapourSynth script for Scene Detection
730+
let input = if let Some(ref vs_script) = self.vs_script {
731+
Input::VapourSynth {
732+
path: vs_script.clone(),
733+
vspipe_args: Vec::new(),
734+
}
735+
} else {
736+
self.args.input.clone()
737+
};
738+
729739
Ok(match self.args.split_method {
730740
SplitMethod::AvScenechange => av_scenechange_detect(
731-
&self.args.input,
741+
&input,
732742
self.args.encoder,
733743
self.frames,
734744
self.args.min_scene_len,
@@ -764,8 +774,7 @@ impl Av1anContext {
764774
zone_overrides: None,
765775
});
766776
}
767-
768-
(scenes, self.args.input.frames()?)
777+
(scenes, self.args.input.frames(self.vs_script.clone())?)
769778
}
770779
})
771780
}
@@ -804,7 +813,7 @@ impl Av1anContext {
804813
crate::split::read_scenes_from_file(scene_file.as_ref())?
805814
} else {
806815
used_existing_cuts = false;
807-
self.frames = self.args.input.frames()?;
816+
self.frames = self.args.input.frames(self.vs_script.clone())?;
808817
self.calc_split_locations()?
809818
};
810819
self.frames = frames;

av1an-core/src/lib.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,20 @@ impl Input {
115115
matches!(&self, Input::VapourSynth { .. })
116116
}
117117

118-
pub fn frames(&self) -> anyhow::Result<usize> {
118+
pub fn frames(&self, vs_script_path: Option<PathBuf>) -> anyhow::Result<usize> {
119119
const FAIL_MSG: &str = "Failed to get number of frames for input video";
120120
Ok(match &self {
121-
Input::Video { path } => {
121+
Input::Video { path } if vs_script_path.is_none() => {
122122
ffmpeg::num_frames(path.as_path()).map_err(|_| anyhow::anyhow!(FAIL_MSG))?
123123
}
124-
Input::VapourSynth { path, .. } => {
125-
vapoursynth::num_frames(path.as_path(), self.as_vspipe_args_map()?)
126-
.map_err(|_| anyhow::anyhow!(FAIL_MSG))?
127-
}
124+
path => vapoursynth::num_frames(
125+
vs_script_path
126+
.as_ref()
127+
.map(|p| p.as_path())
128+
.unwrap_or(path.as_path()),
129+
self.as_vspipe_args_map()?,
130+
)
131+
.map_err(|_| anyhow::anyhow!(FAIL_MSG))?,
128132
})
129133
}
130134

av1an-core/src/scene_detect.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ pub fn av_scenechange_detect(
3838

3939
let input2 = input.clone();
4040
let frame_thread = thread::spawn(move || {
41-
let frames = input2.frames().unwrap();
41+
let frames = input2.frames(None).unwrap();
4242
if verbosity != Verbosity::Quiet {
4343
progress_bar::convert_to_progress(0);
4444
progress_bar::set_len(frames as u64);
4545
}
4646
frames
4747
});
4848

49+
let frames = frame_thread.join().unwrap();
4950
let scenes = scene_detect(
5051
input,
5152
encoder,
@@ -65,8 +66,6 @@ pub fn av_scenechange_detect(
6566
zones,
6667
)?;
6768

68-
let frames = frame_thread.join().unwrap();
69-
7069
progress_bar::finish_progress_bar();
7170

7271
Ok((scenes, frames))

0 commit comments

Comments
 (0)