Skip to content

Commit 41c4c0a

Browse files
committed
lil cleanup
1 parent a21ab98 commit 41c4c0a

File tree

5 files changed

+223
-165
lines changed

5 files changed

+223
-165
lines changed

tools/replay/__main__.py

Lines changed: 0 additions & 140 deletions
This file was deleted.

tools/replay/camera.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env python3
2+
import logging
23
import queue
34
import threading
5+
import traceback
46
from enum import Enum, auto
57
from typing import Optional
68

@@ -9,9 +11,22 @@
911
from msgq.visionipc import VisionIpcServer, VisionStreamType
1012
from openpilot.tools.lib.framereader import FrameReader
1113

14+
log = logging.getLogger("replay")
15+
1216
BUFFER_COUNT = 40
1317

1418

19+
def get_nv12_info(width: int, height: int) -> tuple[int, int, int]:
20+
"""Calculate NV12 buffer parameters matching C++ VENUS macros."""
21+
# VENUS_Y_STRIDE for NV12: align to 128
22+
nv12_width = (width + 127) & ~127
23+
# VENUS_Y_SCANLINES for NV12: align to 32
24+
nv12_height = (height + 31) & ~31
25+
# Buffer size from v4l2_format (matches C++ implementation)
26+
nv12_buffer_size = 2346 * nv12_width
27+
return nv12_width, nv12_height, nv12_buffer_size
28+
29+
1530
class CameraType(Enum):
1631
ROAD = 0
1732
DRIVER = 1
@@ -31,6 +46,7 @@ def __init__(self, cam_type: CameraType):
3146
self.stream_type = CAMERA_STREAM_TYPES[cam_type]
3247
self.width = 0
3348
self.height = 0
49+
self.nv12_buffer_size = 0 # Padded buffer size for VisionIPC
3450
self.thread: Optional[threading.Thread] = None
3551
self.queue: queue.Queue = queue.Queue()
3652
self.cached_frames: dict[int, np.ndarray] = {}
@@ -71,8 +87,13 @@ def _start_vipc_server(self) -> None:
7187
cam.cached_frames.clear()
7288

7389
if cam.width > 0 and cam.height > 0:
74-
print(f"camera[{cam.type.name}] frame size {cam.width}x{cam.height}")
75-
self._vipc_server.create_buffers(cam.stream_type, BUFFER_COUNT, cam.width, cam.height)
90+
nv12_width, nv12_height, nv12_buffer_size = get_nv12_info(cam.width, cam.height)
91+
cam.nv12_buffer_size = nv12_buffer_size
92+
log.info(f"camera[{cam.type.name}] frame size {cam.width}x{cam.height}, nv12 buffer size {nv12_buffer_size}")
93+
self._vipc_server.create_buffers_with_sizes(
94+
cam.stream_type, BUFFER_COUNT, cam.width, cam.height,
95+
nv12_buffer_size, nv12_width, nv12_width * nv12_height
96+
)
7697

7798
if cam.thread is None or not cam.thread.is_alive():
7899
cam.thread = threading.Thread(
@@ -108,18 +129,20 @@ def _camera_thread(self, cam: Camera) -> None:
108129
# Get the frame
109130
yuv = self._get_frame(cam, fr, segment_id, frame_id)
110131
if yuv is not None:
111-
# Send via VisionIPC
132+
# Send via VisionIPC - flatten to 1D and pad to match buffer size
112133
timestamp_sof = eidx.timestampSof
113134
timestamp_eof = eidx.timestampEof
114-
self._vipc_server.send(cam.stream_type, yuv.data, frame_id, timestamp_sof, timestamp_eof)
115-
else:
116-
print(f"camera[{cam.type.name}] failed to get frame: {segment_id}")
135+
yuv_bytes = yuv.flatten().tobytes()
136+
# Pad to match the NV12 buffer size expected by VisionIPC
137+
if len(yuv_bytes) < cam.nv12_buffer_size:
138+
yuv_bytes = yuv_bytes + bytes(cam.nv12_buffer_size - len(yuv_bytes))
139+
self._vipc_server.send(cam.stream_type, yuv_bytes, frame_id, timestamp_sof, timestamp_eof)
117140

118141
# Prefetch next frame
119142
self._get_frame(cam, fr, segment_id + 1, frame_id + 1)
120143

121144
except Exception as e:
122-
print(f"camera[{cam.type.name}] error: {e}")
145+
log.error(f"camera[{cam.type.name}] error: {e}\n{traceback.format_exc()}")
123146

124147
with self._publishing_lock:
125148
self._publishing -= 1
@@ -142,7 +165,7 @@ def _get_frame(self, cam: Camera, fr: FrameReader, segment_id: int, frame_id: in
142165
del cam.cached_frames[oldest]
143166
return yuv
144167
except Exception as e:
145-
print(f"Failed to decode frame {frame_id}: {e}")
168+
log.warning(f"Failed to decode frame {frame_id}: {e}")
146169
return None
147170

148171
def push_frame(self, cam_type: CameraType, fr: FrameReader, event) -> None:

tools/replay/consoleui.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,25 @@ def _update_status(self) -> None:
277277
win.addstr(1, 25, "PLAYBACK: ")
278278
self._add_str(win, f"{self.replay.speed:.1f}x", Color.BRIGHT_WHITE, True)
279279

280+
# Timing stats
281+
stats = self.replay.stats
282+
buffer_ms = stats.time_buffer_ns / 1_000_000
283+
284+
# Color code the buffer based on how far ahead/behind we are
285+
if buffer_ms >= 0:
286+
buffer_color = Color.GREEN
287+
elif buffer_ms >= -10:
288+
buffer_color = Color.YELLOW
289+
else:
290+
buffer_color = Color.RED
291+
292+
win.addstr(2, 0, "TIMING: buffer: ")
293+
self._add_str(win, f"{buffer_ms:+.1f}ms", buffer_color)
294+
win.addstr(f" | lags(30s): {stats.lag_count}")
295+
if stats.worst_lag_ns < 0:
296+
worst_ms = stats.worst_lag_ns / 1_000_000
297+
win.addstr(f" | worst: {worst_ms:.0f}ms")
298+
280299
win.refresh()
281300

282301
def _update_timeline(self) -> None:

0 commit comments

Comments
 (0)