2026-08-20 11:39:21 +08:00
|
|
|
|
"""将幻灯片与配音逐段合成为 MP4,再拼接为完整视频。"""
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
import imageio_ffmpeg
|
|
|
|
|
|
|
|
|
|
|
|
FFMPEG = imageio_ffmpeg.get_ffmpeg_exe()
|
2026-09-08 00:07:26 +08:00
|
|
|
|
WS = Path(__file__).resolve().parent
|
|
|
|
|
|
REPO_ROOT = WS.parent
|
2026-08-20 11:39:21 +08:00
|
|
|
|
PARTS = WS / "parts"
|
|
|
|
|
|
PARTS.mkdir(exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
N = 12
|
|
|
|
|
|
part_files = []
|
|
|
|
|
|
for i in range(1, N + 1):
|
|
|
|
|
|
slide = WS / "slides" / f"slide{i:02d}.png"
|
|
|
|
|
|
audio = WS / "audio" / f"seg{i:02d}.mp3"
|
|
|
|
|
|
part = PARTS / f"part{i:02d}.mp4"
|
|
|
|
|
|
cmd = [
|
|
|
|
|
|
FFMPEG, "-y",
|
|
|
|
|
|
"-loop", "1", "-framerate", "30", "-i", str(slide),
|
|
|
|
|
|
"-i", str(audio),
|
|
|
|
|
|
"-c:v", "libx264", "-preset", "medium", "-tune", "stillimage",
|
|
|
|
|
|
"-c:a", "aac", "-b:a", "192k",
|
|
|
|
|
|
"-pix_fmt", "yuv420p",
|
|
|
|
|
|
"-shortest", "-movflags", "+faststart",
|
|
|
|
|
|
str(part),
|
|
|
|
|
|
]
|
|
|
|
|
|
r = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
|
|
|
|
|
|
if r.returncode != 0 or not part.exists():
|
|
|
|
|
|
print(f"part{i:02d} 合成失败:\n{r.stderr[-800:]}")
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
part_files.append(part)
|
|
|
|
|
|
print(f"part{i:02d}.mp4 ✓ ({part.stat().st_size // 1024} KB)")
|
|
|
|
|
|
|
|
|
|
|
|
lst = WS / "concat.txt"
|
2026-09-08 00:07:26 +08:00
|
|
|
|
lst.write_text("".join(f"file 'parts/{p.name}'\n" for p in part_files), encoding="utf-8")
|
2026-08-20 11:39:21 +08:00
|
|
|
|
|
2026-09-08 00:07:26 +08:00
|
|
|
|
final = REPO_ROOT / "APS智能体演示视频.mp4"
|
2026-08-20 11:39:21 +08:00
|
|
|
|
r = subprocess.run(
|
|
|
|
|
|
[FFMPEG, "-y", "-f", "concat", "-safe", "0", "-i", str(lst),
|
|
|
|
|
|
"-c", "copy", "-movflags", "+faststart", str(final)],
|
|
|
|
|
|
capture_output=True, text=True, timeout=600,
|
|
|
|
|
|
)
|
|
|
|
|
|
if r.returncode != 0 or not final.exists():
|
|
|
|
|
|
print("拼接失败:\n", r.stderr[-800:])
|
|
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
print(f"\n最终视频: {final} ({final.stat().st_size / 1024 / 1024:.1f} MB)")
|