|
| 1 | +import os |
| 2 | +import subprocess |
1 | 3 | import typing |
2 | 4 | from pathlib import Path |
3 | 5 | from typing import Tuple, Dict |
@@ -340,6 +342,50 @@ def _compute_force( |
340 | 342 | return total_force, [mean_x, mean_y, mean_z] |
341 | 343 |
|
342 | 344 |
|
| 345 | +def _process_video(filename: str, simulation_duration: float, start_time: float = 0.0): |
| 346 | + cmd = [ |
| 347 | + "ffprobe", |
| 348 | + "-i", |
| 349 | + filename, |
| 350 | + "-show_entries", |
| 351 | + "format=duration", |
| 352 | + "-v", |
| 353 | + "quiet", |
| 354 | + "-of", |
| 355 | + "csv=p=0", |
| 356 | + ] |
| 357 | + |
| 358 | + out = subprocess.check_output(cmd).decode().strip() |
| 359 | + video_duration = float(out) |
| 360 | + |
| 361 | + ratio = simulation_duration / video_duration |
| 362 | + cmd = [ |
| 363 | + "ffmpeg", |
| 364 | + "-y", |
| 365 | + "-ss", |
| 366 | + str(start_time / ratio), |
| 367 | + "-i", |
| 368 | + filename, |
| 369 | + "-filter:v", |
| 370 | + f"setpts={ratio}*PTS", |
| 371 | + "-r", |
| 372 | + "60", |
| 373 | + "-c:v", |
| 374 | + "libx264", |
| 375 | + "-crf", |
| 376 | + "18", |
| 377 | + "-preset", |
| 378 | + "slow", |
| 379 | + "output.mp4", |
| 380 | + ] |
| 381 | + |
| 382 | + subprocess.run(cmd, check=True) |
| 383 | + |
| 384 | + # Remove the original file and rename the output to the original file |
| 385 | + os.remove(filename) |
| 386 | + os.rename("output.mp4", filename) |
| 387 | + |
| 388 | + |
343 | 389 | class Simulator: |
344 | 390 | """ |
345 | 391 | Thin PyBullet wrapper for loading a robot URDF and driving it from |
@@ -422,6 +468,8 @@ def __init__(self, dt, path_to_robot_urdf: Path, model, launch_gui=True): |
422 | 468 |
|
423 | 469 | self._displayed_lines = None |
424 | 470 | self._displayed_points = None |
| 471 | + self.log_id = None |
| 472 | + self.filename = None |
425 | 473 |
|
426 | 474 | def step(self): |
427 | 475 | """ |
@@ -723,3 +771,12 @@ def get_zmp_pose(self): |
723 | 771 | px = -M[1] / F[2] |
724 | 772 | py = M[0] / F[2] |
725 | 773 | return np.array([px, py, 0.0]) |
| 774 | + |
| 775 | + def start_video_record(self, filename: str = "recording.mp4"): |
| 776 | + self.filename = filename |
| 777 | + self.log_id = pb.startStateLogging(pb.STATE_LOGGING_VIDEO_MP4, self.filename) |
| 778 | + |
| 779 | + def stop_video_record(self, duration: float, t_start: float = 0.0): |
| 780 | + pb.stopStateLogging(self.log_id) |
| 781 | + |
| 782 | + _process_video(self.filename, duration, t_start) |
0 commit comments