[Bug]: Missing frames in cam.render()
Bug Description
When I use the following code, I notice that cam.render() is called 120 times, but the video only saves 119 frames instead of 120. Is the missing frame the starting frame or the ending frame? Is this by design?
import genesis as gs
gs.init(backend=gs.cpu)
scene = gs.Scene(
show_viewer = True,
viewer_options = gs.options.ViewerOptions(
res = (1280, 960),
camera_pos = (3.5, 0.0, 2.5),
camera_lookat = (0.0, 0.0, 0.5),
camera_fov = 40,
max_FPS = 60,
),
vis_options = gs.options.VisOptions(
show_world_frame = True,
world_frame_size = 1.0,
show_link_frame = False,
show_cameras = False,
plane_reflection = True,
ambient_light = (0.1, 0.1, 0.1),
),
renderer=gs.renderers.Rasterizer(),
)
plane = scene.add_entity(
gs.morphs.Plane(),
)
franka = scene.add_entity(
gs.morphs.MJCF(file='xml/franka_emika_panda/panda.xml'),
)
cam = scene.add_camera(
res = (640, 480),
pos = (3.5, 0.0, 2.5),
lookat = (0, 0, 0.5),
fov = 30,
GUI = False,
)
scene.build()
# 渲染rgb、深度、分割掩码和法线图
# rgb, depth, segmentation, normal = cam.render(rgb=True, depth=True, segmentation=True, normal=True)
cam.start_recording()
import numpy as np
for i in range(120):
scene.step()
cam.set_pose(
pos = (3.0 * np.sin(i / 60), 3.0 * np.cos(i / 60), 2.5),
lookat = (0, 0, 0.5),
)
cam.render()
cam.stop_recording(save_to_filename='video.mp4', fps=60)
Steps to Reproduce
code
Expected Behavior
fix
Screenshots/Videos
No response
Relevant log output
Environment
- OS: [e.g. Ubuntu 22.04]
- GPU/CPU [e.g. A100, RTX 4090, M3pr, Intel I9-9900k, Ryzen 5900x] (N/A if no GPU/CPU)
- GPU-driver version (N/A if no GPU)
- CUDA / CUDA-toolkit version (N/A if non-Nvidia)
Release version or Commit ID
0.3.1
Additional Context
No response
The bug occurs in the animate function at genesis/utils/tools.py, lines 33–44:
from moviepy import ImageSequenceClip
imgs = ImageSequenceClip(imgs, fps=fps)
imgs.write_videofile(
filename,
fps=fps,
logger=None,
codec="libx264",
preset="ultrafast",
# ffmpeg_params=["-crf", "0"],
)
gs.logger.info("Video saved.")
The video appears to save fine (no error), but the last frame gets dropped.
I tested with the following script:
import os
import cv2
import numpy as np
from moviepy import ImageSequenceClip
# Generate 120 frames with center text, text start from 1, end at 120
def generate_frames(n=120, h=60, w=120):
frames = []
font = cv2.FONT_HERSHEY_SIMPLEX
for i in range(n):
img = np.full((h, w, 3), (i * 2 % 255, 100, 200), dtype=np.uint8)
img = cv2.cvtColor(img, cv2.COLOR_HSV2BGR)
text = f"{i+1}"
(w_text, h_text), _ = cv2.getTextSize(text, font, 0.5, 1)
cv2.putText(img, text, ((w - w_text) // 2, (h + h_text) // 2), font, 0.5, (255, 255, 255), 1)
frames.append(img[:, :, ::-1]) # BGR -> RGB
return frames
# Save video with moviepy
imgs = generate_frames(120)
video_file = "test.mp4"
if os.path.exists(video_file):
os.remove(video_file)
clip = ImageSequenceClip(imgs, fps=60)
clip.write_videofile(video_file, fps=60, logger=None, codec="libx264", preset="ultrafast")
# Count frames with OpenCV
cap = cv2.VideoCapture(video_file)
count = 0
while cap.read()[0]:
count += 1
cap.release()
print(f"Generated: 120 frames")
print(f"Read by OpenCV: {count} frames")
print("Pass" if count == 120 else "Fail: Last frame lost")
Looks like this is a moviepy issue — when I downgraded moviepy to version 1.0.0, the frame count became correct.
https://github.com/user-attachments/assets/10b5c932-eda2-4e09-b6ba-cde04dbaea03
Thank you for your detailed analysis. Good to know it may be related to moviepy. We should probably switch to pyav, it is just strictly superior.
A new recorder based on PyAV has been implemented, but camera needs to be updated to leverage this new capability. This should fix this issue.