28 lines
1.4 KiB
Python
28 lines
1.4 KiB
Python
"""FFmpeg encoding; this module also works outside Unreal."""
|
|
from pathlib import Path
|
|
import subprocess
|
|
|
|
from .paths import executable
|
|
|
|
|
|
def encode(frames, fps, output=None, ffmpeg=None, expected_frames=None):
|
|
frames = Path(frames).resolve()
|
|
if fps <= 0:
|
|
raise ValueError("FPS musi byc dodatni.")
|
|
images = sorted(frames.glob("frame_*.png"))
|
|
count = len(images)
|
|
if not count or any(p.name != f"frame_{i:04d}.png" for i, p in enumerate(images)):
|
|
raise RuntimeError(f"Brak kompletnej numeracji frame_0000.png, frame_0001.png... w {frames}")
|
|
if expected_frames is not None and count != expected_frames:
|
|
raise RuntimeError(f"Render zapisal {count} klatek zamiast {expected_frames}.")
|
|
output = Path(output) if output else frames.parent / "film.mp4"
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
command = [executable("ffmpeg", ffmpeg), "-hide_banner", "-loglevel", "error", "-y",
|
|
"-framerate", str(fps), "-start_number", "0", "-i", str(frames / "frame_%04d.png"),
|
|
"-frames:v", str(count), "-c:v", "libx264", "-crf", "20", "-pix_fmt", "yuv420p",
|
|
"-vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2", "-movflags", "+faststart", str(output)]
|
|
result = subprocess.run(command, capture_output=True, text=True)
|
|
if result.returncode:
|
|
raise RuntimeError("FFmpeg: " + result.stderr[-4000:])
|
|
return output.resolve()
|