Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 54 additions & 7 deletions crates/compositor/src/pipeline_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2274,6 +2274,25 @@ mod tests {
out
}

/// A 64x64, 25 fps, 0.6 s clip whose frames around the two cut points get their own colour:
/// blue before 0.36 s, magenta 0.36-0.399 s (the last frame a 0.4 s cut keeps), lime from
/// 0.4 s, yellow from 0.56 s (the file's last frame).
fn encode_end_frame_colours(codec_args: &[&str], filename: &str) -> std::path::PathBuf {
let boxes = [
("magenta", "between(t,0.36,0.399)"),
("lime", "between(t,0.4,0.559)"),
("yellow", "gte(t,0.56)"),
];
let filter = boxes
.iter()
.map(|(c, en)| format!("drawbox=x=0:y=0:w=iw:h=ih:color={c}:t=fill:enable='{en}'"))
.collect::<Vec<_>>()
.join(",");
let mut args = vec!["-vf", filter.as_str()];
args.extend_from_slice(codec_args);
encode_named_color(&args, filename, "blue", "0.6")
}

unsafe fn allocated_decoder_open_resources(filename: &str) -> DecoderOpenResources {
let path = encode_color(&["-c:v", "libopenh264", "-b:v", "200k"], filename);
let cpath = CString::new(path.to_string_lossy().as_bytes()).expect("fixture path CString");
Expand Down Expand Up @@ -3074,7 +3093,9 @@ mod tests {
let h264 = ["-c:v", "libopenh264", "-b:v", "200k"];
// Long enough that a view which wrapped onto it is still there when the test looks.
let first = encode_named_color(&h264, "997-first.mp4", "red", "3.0");
let last = encode_named_color(&h264, "997-last.mp4", "blue", "0.6");
// The last frame before each end has its own colour (magenta before the 0.4 s cut, yellow
// for the file's last frame), so the held picture says which frame the view stopped on.
let last = encode_end_frame_colours(&h264, "997-last.mp4");
// The paths travel in JSON, and the view matches them against its requests as strings.
let first = first.to_str().expect("utf8").replace('\\', "/");
let last = last.to_str().expect("utf8").replace('\\', "/");
Expand Down Expand Up @@ -3105,6 +3126,8 @@ mod tests {
let first_frame = wait_for_frame(&view, 0, |p| p.clip_index == 2);
let mut gen = first_frame.0;
let mut held = first_frame.5;
let mut held_rgba = first_frame.3;
let (mut held_w, mut held_h) = (first_frame.1, first_frame.2);

// Play to the end of the last clip, then about as long again.
view.set_playing(true);
Expand All @@ -3114,20 +3137,44 @@ mod tests {
while let Some(frame) = view.latest_frame_since(gen) {
gen = frame.0;
held = frame.5;
held_rgba = frame.3;
(held_w, held_h) = (frame.1, frame.2);
}
// The frame held at the end is the clip's own last frame, not the first one its cut
// removed (the 25 fps file has a frame at exactly 0.4 s).
// The published time is the hold clock: it runs on to the clip's end even if decoding
// stopped early. The bounds check the clock (reached the end, never past it); the
// colour below checks which frame is held.
assert!(
held.source_time_sec < last_end_sec,
"end {last_end_sec}: held a frame past the clip's end, at {:.3} s",
held.source_time_sec <= last_end_sec + 1e-6,
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
"end {last_end_sec}: the clock ran past the clip's end, at {:.3} s",
held.source_time_sec
);
// And it did play up to there: a view stalled at its start would pass the bound above.
assert!(
held.source_time_sec > last_end_sec - 0.1,
"end {last_end_sec}: playback did not reach the clip's end, held at {:.3} s",
"end {last_end_sec}: the clock did not reach the clip's end, held at {:.3} s",
held.source_time_sec
);
// The colour proves which frame is held: the last one the cut keeps (magenta), or the
// file's last frame (yellow). Stuck on an earlier frame shows blue or lime instead.
let center = (((held_h / 2) * held_w + held_w / 2) * 4) as usize;
let rgb = &held_rgba[center..center + 3];
let (r, g, b) = (i32::from(rgb[0]), i32::from(rgb[1]), i32::from(rgb[2]));
if last_end_sec < 0.5 {
assert!(
r > 150 && b > 150 && g < 100,
"end {last_end_sec}: expected magenta, the last frame the cut keeps: {rgb:?}"
);
} else {
assert!(
r > 150 && g > 150 && b < 100,
"end {last_end_sec}: expected yellow, the file's last frame: {rgb:?}"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
);
}

assert_eq!(
held.clip_index, 2,
"end {last_end_sec}: held a frame from clip {} instead of the last clip",
held.clip_index
);

// A seek inside the last clip, as the app sends it while paused.
view.set_time(0.2);
Expand Down
Loading