fix: time out a stalled portal and sample motion across segments
Hyprland's portal sometimes creates the session and never answers source selection, before any picker appears. Recording now fails if the portal has not reached its picker within 10 s; time in the picker is not limited. The motion check uses the segment with the most motion, since capture can start late.
This commit is contained in:
@@ -470,24 +470,24 @@ fn check(options: &Options) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
}
|
||||
|
||||
// A black or frozen capture still produces valid segments. When the
|
||||
// captured content was moving, the middle segment must show it.
|
||||
// captured content was moving, some segment must show it (capture may
|
||||
// start late, after the user answers the picker).
|
||||
if options.expect_motion {
|
||||
let middle = &segments[segments.len() / 2];
|
||||
let distinct = Command::new("ffmpeg")
|
||||
.args(["-v", "error", "-i"])
|
||||
.arg(middle)
|
||||
.args(["-map", "0:v:0", "-vf", "mpdecimate=max=0", "-f", "null", "-", "-stats_period", "100"])
|
||||
.args(["-progress", "pipe:1"])
|
||||
.output()?;
|
||||
let frames = String::from_utf8_lossy(&distinct.stdout)
|
||||
.lines()
|
||||
.filter_map(|line| line.strip_prefix("frame="))
|
||||
.filter_map(|frames| frames.parse::<u64>().ok())
|
||||
.last()
|
||||
.unwrap_or(0);
|
||||
let moving = frames > 1;
|
||||
let mut most = (0, None);
|
||||
for segment in &segments {
|
||||
let frames = distinct_frames(segment)?;
|
||||
if frames > most.0 {
|
||||
most = (frames, Some(segment));
|
||||
}
|
||||
}
|
||||
let moving = most.0 > 1;
|
||||
ok &= moving;
|
||||
println!("motion ok={moving} distinct_frames={frames} segment={}", middle.display());
|
||||
println!(
|
||||
"motion ok={moving} distinct_frames={} segment={}",
|
||||
most.0,
|
||||
most.1
|
||||
.map_or(String::new(), |segment| segment.display().to_string())
|
||||
);
|
||||
}
|
||||
|
||||
// A clip spanning the boundaries between the first three segments.
|
||||
@@ -540,6 +540,30 @@ fn check(options: &Options) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
Ok(ok)
|
||||
}
|
||||
|
||||
/// Frames in a segment's video that differ from the previous one.
|
||||
fn distinct_frames(segment: &Path) -> Result<u64, Box<dyn std::error::Error>> {
|
||||
let output = Command::new("ffmpeg")
|
||||
.args(["-v", "error", "-i"])
|
||||
.arg(segment)
|
||||
.args([
|
||||
"-map",
|
||||
"0:v:0",
|
||||
"-vf",
|
||||
"mpdecimate=max=0",
|
||||
"-f",
|
||||
"null",
|
||||
"-",
|
||||
])
|
||||
.args(["-progress", "pipe:1"])
|
||||
.output()?;
|
||||
Ok(String::from_utf8_lossy(&output.stdout)
|
||||
.lines()
|
||||
.filter_map(|line| line.strip_prefix("frame="))
|
||||
.filter_map(|frames| frames.parse().ok())
|
||||
.next_back()
|
||||
.unwrap_or(0))
|
||||
}
|
||||
|
||||
fn ffprobe(path: &Path, query: &[&str]) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let output = Command::new("ffprobe")
|
||||
.args(["-v", "error"])
|
||||
|
||||
Reference in New Issue
Block a user