Skip to content

Commit 8864753

Browse files
committed
fix(clip): no empty frames
1 parent cd70e23 commit 8864753

File tree

3 files changed

+39
-30
lines changed

3 files changed

+39
-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: 36 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,39 +284,11 @@ 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

318290
self._target_fps = fps
291+
319292
self._set_styles()
320293
self._load_fonts()
321294
self._patch_text_functions()
@@ -355,6 +328,39 @@ def _startup_profile_context(self):
355328
print(f"{green}UI window ready in {elapsed_ms:.1f} ms{reset}")
356329
sys.exit(0)
357330

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

561567
rl.end_drawing()
562568

563-
if RECORD:
569+
if self._recording:
564570
image = rl.load_image_from_texture(self._render_texture.texture)
565571
data_size = image.width * image.height * 4
566572
data = bytes(rl.ffi.buffer(image.data, data_size))

tools/clip/run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,8 @@ def clip(route: Route, output: str, start: int, end: int, headless: bool = True,
314314
if should_render:
315315
main_layout.render()
316316
render_overlays(rl, gui_app, font, FONT_SCALE, metadata, title, start, frame_idx, show_metadata, show_time)
317+
if road_view.frame is not None:
318+
gui_app.begin_recording()
317319
frame_idx += 1
318320
pbar.update(1)
319321
timer.lap("render")

0 commit comments

Comments
 (0)