Skip to content

Commit cdbd1ed

Browse files
committed
Add video recording code
1 parent ac847ce commit cdbd1ed

2 files changed

Lines changed: 62 additions & 45 deletions

File tree

biped_walking_controller/simulation.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
import subprocess
13
import typing
24
from pathlib import Path
35
from typing import Tuple, Dict
@@ -340,6 +342,50 @@ def _compute_force(
340342
return total_force, [mean_x, mean_y, mean_z]
341343

342344

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+
343389
class Simulator:
344390
"""
345391
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):
422468

423469
self._displayed_lines = None
424470
self._displayed_points = None
471+
self.log_id = None
472+
self.filename = None
425473

426474
def step(self):
427475
"""
@@ -723,3 +771,12 @@ def get_zmp_pose(self):
723771
px = -M[1] / F[2]
724772
py = M[0] / F[2]
725773
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)

examples/example_4_physics_simulation.py

Lines changed: 5 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import math
22
import argparse
3-
import subprocess
43
from pathlib import Path
54

65
import numpy as np
@@ -34,51 +33,12 @@
3433
)
3534

3635

37-
def process_video(simulation_duration: float, start_time: float = 0.0):
38-
cmd = [
39-
"ffprobe",
40-
"-i",
41-
"talos_run.mp4",
42-
"-show_entries",
43-
"format=duration",
44-
"-v",
45-
"quiet",
46-
"-of",
47-
"csv=p=0",
48-
]
49-
50-
out = subprocess.check_output(cmd).decode().strip()
51-
video_duration = float(out)
52-
53-
ratio = simulation_duration / video_duration
54-
55-
cmd = [
56-
"ffmpeg",
57-
"-ss",
58-
str(start_time / ratio),
59-
"-i",
60-
"talos_run.mp4",
61-
"-filter:v",
62-
f"setpts={ratio}*PTS",
63-
"-r",
64-
"60",
65-
"-c:v",
66-
"libx264",
67-
"-crf",
68-
"18",
69-
"-preset",
70-
"slow",
71-
"talos_run_fixed.mp4",
72-
]
73-
74-
subprocess.run(cmd, check=True)
75-
76-
7736
def main():
7837
p = argparse.ArgumentParser()
7938
p.add_argument("--path-talos-data", type=Path, help="Path to talos_data root")
8039
p.add_argument("--plot-results", action="store_true")
8140
p.add_argument("--launch-gui", action="store_true")
41+
p.add_argument("--record-video", action="store_true")
8242
args = p.parse_args()
8343

8444
np.set_printoptions(suppress=True, precision=3)
@@ -262,7 +222,8 @@ def main():
262222
rf_forces = np.zeros((len(phases), 1))
263223
lf_forces = np.zeros((len(phases), 1))
264224

265-
log_id = pb.startStateLogging(pb.STATE_LOGGING_VIDEO_MP4, "talos_run.mp4")
225+
if args.record_video:
226+
simulator.start_video_record()
266227

267228
# We start the walking phase
268229
for k, _ in enumerate(phases[:-2]):
@@ -344,9 +305,8 @@ def main():
344305

345306
rf_forces[k], lf_forces[k] = simulator.get_contact_forces()
346307

347-
pb.stopStateLogging(log_id)
348-
349-
process_video(t[-1], t_init + 2.0)
308+
if args.record_video:
309+
simulator.stop_video_record(duration=t[-1])
350310

351311
if args.plot_results:
352312

0 commit comments

Comments
 (0)