fix(perception): isolate recorded decode from realtime admission
This commit is contained in:
@@ -62,9 +62,12 @@ from k1link.perception.providers import (
|
||||
from k1link.perception.recorded_source import (
|
||||
DecodedFrameTiming,
|
||||
DecodedRecordedSource,
|
||||
DecodePhase,
|
||||
PrefetchedRecordedImageDecoder,
|
||||
RecordedRavnoves00Source,
|
||||
RecordedSourceError,
|
||||
ReplayPacing,
|
||||
SourcePacingTiming,
|
||||
)
|
||||
|
||||
|
||||
@@ -839,6 +842,7 @@ def test_recorded_source_target_rate_changes_only_wall_clock_pacing(tmp_path: Pa
|
||||
camera_path, timeline_path = _write_recorded_fixture(tmp_path)
|
||||
now = [1_000_000_000]
|
||||
waits: list[float] = []
|
||||
pacing: list[SourcePacingTiming] = []
|
||||
|
||||
def wait(stop_event: Event, seconds: float) -> bool:
|
||||
waits.append(seconds)
|
||||
@@ -852,6 +856,7 @@ def test_recorded_source_target_rate_changes_only_wall_clock_pacing(tmp_path: Pa
|
||||
target_rate_hz=20.0,
|
||||
expected_frame_count=2,
|
||||
expected_source_pack_sha256=None,
|
||||
pacing_observer=pacing.append,
|
||||
clock_ns=lambda: now[0],
|
||||
wait=wait,
|
||||
)
|
||||
@@ -859,6 +864,8 @@ def test_recorded_source_target_rate_changes_only_wall_clock_pacing(tmp_path: Pa
|
||||
packets = list(source.packets(Event()))
|
||||
|
||||
assert waits == pytest.approx([0.05])
|
||||
assert [sample.sequence for sample in pacing] == [0, 1]
|
||||
assert [sample.lateness_ns for sample in pacing] == [0, 0]
|
||||
assert (
|
||||
packets[1].envelope.timestamps.source_ns
|
||||
- packets[0].envelope.timestamps.source_ns
|
||||
@@ -879,6 +886,44 @@ def test_recorded_source_rejects_target_rate_for_uncapped_replay(tmp_path: Path)
|
||||
)
|
||||
|
||||
|
||||
def test_prefetched_decoder_moves_cold_decode_before_source_admission() -> None:
|
||||
observed: list[DecodedFrameTiming] = []
|
||||
|
||||
class Decoder:
|
||||
def frames(self, stop_event: Event) -> Iterator[np.ndarray]:
|
||||
for index in range(4):
|
||||
if stop_event.is_set():
|
||||
return
|
||||
yield np.full((2, 3, 3), index, dtype=np.uint8)
|
||||
|
||||
decoder = PrefetchedRecordedImageDecoder(
|
||||
Decoder(),
|
||||
capacity_frames=2,
|
||||
ready_frames=2,
|
||||
timing_observer=observed.append,
|
||||
)
|
||||
stop_event = Event()
|
||||
|
||||
snapshot = decoder.prepare(stop_event)
|
||||
|
||||
assert snapshot.buffered_frames == 2
|
||||
assert snapshot.capacity_frames == 2
|
||||
assert [sample.phase for sample in observed] == [
|
||||
DecodePhase.PREADMISSION,
|
||||
DecodePhase.PREADMISSION,
|
||||
]
|
||||
decoder.mark_admission_started()
|
||||
frames = list(decoder.frames(stop_event))
|
||||
decoder.close()
|
||||
|
||||
assert [int(frame[0, 0, 0]) for frame in frames] == [0, 1, 2, 3]
|
||||
assert [sample.sequence for sample in observed] == [0, 1, 2, 3]
|
||||
assert [sample.phase for sample in observed[2:]] == [
|
||||
DecodePhase.HOT_LOOP,
|
||||
DecodePhase.HOT_LOOP,
|
||||
]
|
||||
|
||||
|
||||
def test_recorded_source_rejects_timeline_mismatch(tmp_path: Path) -> None:
|
||||
camera_path, timeline_path = _write_recorded_fixture(tmp_path, mismatched=True)
|
||||
source = RecordedRavnoves00Source(
|
||||
|
||||
Reference in New Issue
Block a user