92 lines
2.8 KiB
Rust
92 lines
2.8 KiB
Rust
// Unit coverage for HEVC recovery state in the client upstream path.
|
|
//
|
|
// Scope: include the client HEVC keyframe helpers with a tiny camera-config
|
|
// shim so the logic can be tested without GTK/GStreamer capture hardware.
|
|
// Targets: `client/src/app/uplink_media/video_keyframes.rs`.
|
|
// Why: freshness-first dropping is only safe for predictive codecs when the
|
|
// next emitted video frame is a clean recovery point.
|
|
|
|
mod input {
|
|
pub mod camera {
|
|
#[derive(Clone, Copy)]
|
|
pub enum CameraCodec {
|
|
Mjpeg,
|
|
Hevc,
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub struct CameraConfig {
|
|
pub codec: CameraCodec,
|
|
}
|
|
}
|
|
}
|
|
|
|
use lesavka_common::lesavka::{UpstreamMediaBundle, VideoPacket};
|
|
use temp_env::with_vars;
|
|
|
|
include!("../../../../client/src/app/uplink_media/video_keyframes.rs");
|
|
|
|
fn video_bundle(data: Vec<u8>) -> UpstreamMediaBundle {
|
|
UpstreamMediaBundle {
|
|
video: Some(VideoPacket {
|
|
data,
|
|
..Default::default()
|
|
}),
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn annex_b_irap_detection_handles_three_and_four_byte_start_codes() {
|
|
assert!(contains_hevc_irap(&[0, 0, 0, 1, 0x26, 0x01, 0xaa]));
|
|
assert!(contains_hevc_irap(&[0, 0, 1, 0x28, 0x01, 0xbb]));
|
|
assert!(contains_hevc_irap(&[
|
|
0, 0, 1, 0x02, 0x01, 0xcc, 0, 0, 0, 1, 0x2e, 0x01, 0xdd
|
|
]));
|
|
assert!(!contains_hevc_irap(&[0, 0, 0, 1, 0x02, 0x01, 0xee]));
|
|
assert!(!contains_hevc_irap(&[0x26, 0x01, 0xaa]));
|
|
}
|
|
|
|
#[test]
|
|
fn recovery_wait_holds_delta_bundles_and_releases_on_irap() {
|
|
let delta = video_bundle(vec![0, 0, 0, 1, 0x02, 0x01, 0xaa]);
|
|
let irap = video_bundle(vec![0, 0, 0, 1, 0x26, 0x01, 0xbb]);
|
|
|
|
assert!(!should_hold_hevc_bundle_for_keyframe_recovery(
|
|
false, &delta
|
|
));
|
|
assert!(should_hold_hevc_bundle_for_keyframe_recovery(true, &delta));
|
|
assert!(!should_hold_hevc_bundle_for_keyframe_recovery(true, &irap));
|
|
assert!(bundle_has_hevc_recovery_keyframe(&irap));
|
|
assert!(!bundle_has_hevc_recovery_keyframe(&delta));
|
|
}
|
|
|
|
#[test]
|
|
fn capture_gap_only_enters_wait_state_when_hevc_recovery_applies() {
|
|
let mut waiting = false;
|
|
note_hevc_capture_gap(false, &mut waiting);
|
|
assert!(!waiting);
|
|
|
|
note_hevc_capture_gap(true, &mut waiting);
|
|
assert!(waiting);
|
|
}
|
|
|
|
#[test]
|
|
fn codec_selection_enables_recovery_for_hevc_only() {
|
|
use input::camera::{CameraCodec, CameraConfig};
|
|
|
|
assert!(upstream_camera_uses_hevc(Some(CameraConfig {
|
|
codec: CameraCodec::Hevc,
|
|
})));
|
|
assert!(!upstream_camera_uses_hevc(Some(CameraConfig {
|
|
codec: CameraCodec::Mjpeg,
|
|
})));
|
|
|
|
with_vars([("LESAVKA_CAM_CODEC", Some("h.265"))], || {
|
|
assert!(upstream_camera_uses_hevc(None));
|
|
});
|
|
with_vars([("LESAVKA_CAM_CODEC", Some("mjpeg"))], || {
|
|
assert!(!upstream_camera_uses_hevc(None));
|
|
});
|
|
}
|