Skip to content

Commit ed9b3f1

Browse files
author
Trey Moen
committed
fix(clip): clean start
1 parent efc2364 commit ed9b3f1

File tree

3 files changed

+49
-30
lines changed

3 files changed

+49
-30
lines changed

selfdrive/ui/tests/diff/replay.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def run_replay():
8585
if not HEADLESS:
8686
rl.set_config_flags(rl.FLAG_WINDOW_HIDDEN)
8787
gui_app.init_window("ui diff test", fps=FPS)
88+
gui_app.begin_recording()
8889
main_layout = MiciMainLayout()
8990
main_layout.set_rect(rl.Rectangle(0, 0, gui_app.width, gui_app.height))
9091

system/ui/lib/application.py

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def __init__(self, width: int | None = None, height: int | None = None):
220220
self._ffmpeg_queue: queue.Queue | None = None
221221
self._ffmpeg_thread: threading.Thread | None = None
222222
self._ffmpeg_stop_event: threading.Event | None = None
223+
self._recording = False
223224
self._textures: dict[str, rl.Texture] = {}
224225
self._target_fps: int = _DEFAULT_FPS
225226
self._last_fps_log_time: float = time.monotonic()
@@ -283,35 +284,6 @@ def _close(sig, frame):
283284
self._render_texture = rl.load_render_texture(self._width, self._height)
284285
rl.set_texture_filter(self._render_texture.texture, rl.TextureFilter.TEXTURE_FILTER_BILINEAR)
285286

286-
if RECORD:
287-
output_fps = fps * RECORD_SPEED
288-
ffmpeg_args = [
289-
'ffmpeg',
290-
'-v', 'warning', # Reduce ffmpeg log spam
291-
'-nostats', # Suppress encoding progress
292-
'-f', 'rawvideo', # Input format
293-
'-pix_fmt', 'rgba', # Input pixel format
294-
'-s', f'{self._width}x{self._height}', # Input resolution
295-
'-r', str(fps), # Input frame rate
296-
'-i', 'pipe:0', # Input from stdin
297-
'-vf', 'vflip,format=yuv420p', # Flip vertically and convert to yuv420p
298-
'-r', str(output_fps), # Output frame rate (for speed multiplier)
299-
'-c:v', 'libx264',
300-
'-preset', 'ultrafast',
301-
]
302-
if RECORD_BITRATE:
303-
ffmpeg_args += ['-b:v', RECORD_BITRATE, '-maxrate', RECORD_BITRATE, '-bufsize', RECORD_BITRATE]
304-
ffmpeg_args += [
305-
'-y', # Overwrite existing file
306-
'-f', 'mp4', # Output format
307-
RECORD_OUTPUT, # Output file path
308-
]
309-
self._ffmpeg_proc = subprocess.Popen(ffmpeg_args, stdin=subprocess.PIPE)
310-
self._ffmpeg_queue = queue.Queue(maxsize=60) # Buffer up to 60 frames
311-
self._ffmpeg_stop_event = threading.Event()
312-
self._ffmpeg_thread = threading.Thread(target=self._ffmpeg_writer_thread, daemon=True)
313-
self._ffmpeg_thread.start()
314-
315287
# OFFSCREEN disables FPS limiting for fast offline rendering (e.g. clips)
316288
rl.set_target_fps(0 if OFFSCREEN else fps)
317289

@@ -355,6 +327,39 @@ def _startup_profile_context(self):
355327
print(f"{green}UI window ready in {elapsed_ms:.1f} ms{reset}")
356328
sys.exit(0)
357329

330+
def begin_recording(self):
331+
if not RECORD or self._recording:
332+
return
333+
334+
self._recording = True
335+
output_fps = self._target_fps * RECORD_SPEED
336+
ffmpeg_args = [
337+
'ffmpeg',
338+
'-v', 'warning', # Reduce ffmpeg log spam
339+
'-nostats', # Suppress encoding progress
340+
'-f', 'rawvideo', # Input format
341+
'-pix_fmt', 'rgba', # Input pixel format
342+
'-s', f'{self._width}x{self._height}', # Input resolution
343+
'-r', str(self._target_fps), # Input frame rate
344+
'-i', 'pipe:0', # Input from stdin
345+
'-vf', 'vflip,format=yuv420p', # Flip vertically and convert to yuv420p
346+
'-r', str(output_fps), # Output frame rate (for speed multiplier)
347+
'-c:v', 'libx264',
348+
'-preset', 'ultrafast',
349+
]
350+
if RECORD_BITRATE:
351+
ffmpeg_args += ['-b:v', RECORD_BITRATE, '-maxrate', RECORD_BITRATE, '-bufsize', RECORD_BITRATE]
352+
ffmpeg_args += [
353+
'-y', # Overwrite existing file
354+
'-f', 'mp4', # Output format
355+
RECORD_OUTPUT, # Output file path
356+
]
357+
self._ffmpeg_proc = subprocess.Popen(ffmpeg_args, stdin=subprocess.PIPE)
358+
self._ffmpeg_queue = queue.Queue(maxsize=60) # Buffer up to 60 frames
359+
self._ffmpeg_stop_event = threading.Event()
360+
self._ffmpeg_thread = threading.Thread(target=self._ffmpeg_writer_thread, daemon=True)
361+
self._ffmpeg_thread.start()
362+
358363
def _ffmpeg_writer_thread(self):
359364
"""Background thread that writes frames to ffmpeg."""
360365
while True:
@@ -560,7 +565,7 @@ def render(self):
560565

561566
rl.end_drawing()
562567

563-
if RECORD:
568+
if self._recording:
564569
image = rl.load_image_from_texture(self._render_texture.texture)
565570
data_size = image.width * image.height * 4
566571
data = bytes(rl.ffi.buffer(image.data, data_size))

tools/clip/run.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ def mock_update(timeout=None):
124124
sm.frame += 1
125125
ui_state.sm.update = mock_update
126126

127+
# Prevent _update_status from overwriting started_frame during onroad transition detection
128+
# This fixes an issue where driver monitoring isn't immediately shown
129+
_orig_update = ui_state.update
130+
def clip_update():
131+
_orig_update()
132+
ui_state.started_frame = 0
133+
ui_state.update = clip_update
134+
127135

128136
def get_frame_dimensions(camera_path: str) -> tuple[int, int]:
129137
"""Get frame dimensions from a video file using ffprobe."""
@@ -320,6 +328,7 @@ def clip(route: Route, output: str, start: int, end: int, headless: bool = True,
320328
timer.lap("setup")
321329

322330
frame_idx = 0
331+
road_view_ready = False
323332
with tqdm.tqdm(total=len(message_chunks), desc="Rendering", unit="frame") as pbar:
324333
for should_render in gui_app.render():
325334
if frame_idx >= len(message_chunks):
@@ -330,6 +339,10 @@ def clip(route: Route, output: str, start: int, end: int, headless: bool = True,
330339
if should_render:
331340
road_view.render()
332341
render_overlays(gui_app, font, big, metadata, title, start, frame_idx, show_metadata, show_time)
342+
if road_view_ready:
343+
gui_app.begin_recording()
344+
if road_view.frame is not None:
345+
road_view_ready = True
333346
frame_idx += 1
334347
pbar.update(1)
335348
timer.lap("render")

0 commit comments

Comments
 (0)