This commit is contained in:
firestar5683
2026-05-26 16:02:58 -05:00
parent a4789c9f61
commit fb93198a92
2 changed files with 47 additions and 4 deletions
+21 -2
View File
@@ -31,7 +31,7 @@ void logger_rotate(LoggerdState *s) {
void rotate_if_needed(LoggerdState *s) {
// all encoders ready, trigger rotation
bool all_ready = s->ready_to_rotate == s->max_waiting;
bool all_ready = s->max_waiting > 0 && s->ready_to_rotate == s->max_waiting;
// fallback logic to prevent extremely long segments in the case of camera, encoder, etc. malfunctions
bool timed_out = false;
@@ -53,6 +53,22 @@ void rotate_if_needed(LoggerdState *s) {
}
}
template <size_t N>
int get_expected_encoder_count(const LogCameraInfo (&cameras)[N]) {
const auto streams = VisionIpcClient::getAvailableStreams("camerad", false);
if (streams.empty()) {
return 0;
}
int count = 0;
for (const auto &cam : cameras) {
if (streams.count(cam.stream_type) > 0) {
count += cam.encoder_infos.size();
}
}
return count;
}
struct RemoteEncoder {
std::unique_ptr<VideoWriter> writer;
int encoderd_segment_offset;
@@ -262,9 +278,9 @@ void loggerd_thread() {
for (const auto &cam : cameras_logged) {
for (const auto &encoder_info : cam.encoder_infos) {
encoder_infos_dict[encoder_info.publish_name] = encoder_info;
s.max_waiting++;
}
}
s.max_waiting = get_expected_encoder_count(cameras_logged);
for (auto &[sock, service] : service_state) {
auto it = encoder_infos_dict.find(service.name);
@@ -305,6 +321,9 @@ void loggerd_thread() {
}
if (service.encoder) {
if (s.max_waiting == 0) {
s.max_waiting = get_expected_encoder_count(cameras_logged);
}
s.last_camera_seen_tms = millis_since_boot();
bytes_count += handle_encoder_msg(&s, msg, service.name, remote_encoders[sock], encoder_infos_dict[service.name]);
} else {
+26 -2
View File
@@ -97,12 +97,12 @@ class TestLoggerd:
return sent_msgs
def _publish_camera_and_audio_messages(self, num_segs=1, segment_length=5):
def _publish_camera_and_audio_messages(self, num_segs=1, segment_length=5, streams=None):
# Use small frame sizes for testing (width, height, size, stride, uv_offset)
# NV12 format: size = stride * height * 1.5, uv_offset = stride * height
w, h = 320, 240
frame_spec = (w, h, w * h * 3 // 2, w, w * h)
streams = [
streams = streams or [
(VisionStreamType.VISION_STREAM_ROAD, frame_spec, "roadCameraState"),
(VisionStreamType.VISION_STREAM_DRIVER, frame_spec, "driverCameraState"),
(VisionStreamType.VISION_STREAM_WIDE_ROAD, frame_spec, "wideRoadCameraState"),
@@ -204,6 +204,30 @@ class TestLoggerd:
diff = logged ^ expected_files
assert len(diff) == 0, f"didn't get all expected files. seg={n} {route_path=}, {diff=}\n{logged=} {expected_files=}"
@pytest.mark.xdist_group("camera_encoder_tests")
def test_rotation_without_wide_camera(self):
Params().put("RecordFront", True)
w, h = 320, 240
frame_spec = (w, h, w * h * 3 // 2, w, w * h)
streams = [
(VisionStreamType.VISION_STREAM_ROAD, frame_spec, "roadCameraState"),
(VisionStreamType.VISION_STREAM_DRIVER, frame_spec, "driverCameraState"),
]
expected_files = {"rlog.zst", "qlog.zst", "qcamera.ts", "fcamera.hevc", "dcamera.hevc"}
num_segs = random.randint(2, 3)
length = random.randint(4, 5)
self._publish_camera_and_audio_messages(num_segs=num_segs, segment_length=length, streams=streams)
route_path = str(self._get_latest_log_dir()).rsplit("--", 1)[0]
for n in range(num_segs):
p = Path(f"{route_path}--{n}")
logged = {f.name for f in p.iterdir() if f.is_file()}
diff = logged ^ expected_files
assert len(diff) == 0, f"unexpected files without wide camera. seg={n} {route_path=}, {diff=}\n{logged=} {expected_files=}"
def test_bootlog(self):
# generate bootlog with fake launch log
launch_log = ''.join(str(random.choice(string.printable)) for _ in range(100))