68 lines
2.1 KiB
Python
68 lines
2.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""视频合成模块
|
|
|
|
使用 MoviePy 将图片背景 + 音频 + 字幕合成为最终视频。
|
|
"""
|
|
|
|
import os
|
|
from moviepy.editor import (
|
|
ImageClip,
|
|
AudioFileClip,
|
|
CompositeVideoClip,
|
|
concatenate_videoclips,
|
|
ColorClip,
|
|
)
|
|
from moviepy.video.tools.subtitles import SubtitlesClip
|
|
from moviepy.editor import TextClip
|
|
|
|
|
|
def _make_bg(size, duration, color=(20, 20, 40)):
|
|
"""生成纯色背景片段"""
|
|
return ColorClip(size=size, color=color, duration=duration)
|
|
|
|
|
|
def _make_subtitle_clip(text: str, size, duration: float):
|
|
"""生成一段字幕文本片段"""
|
|
w, h = size
|
|
try:
|
|
txt = TextClip(text, fontsize=48, color="white", font="Arial",
|
|
size=(w - 100, None), method="caption")
|
|
except Exception:
|
|
# 若系统找不到字体,退化为默认字体
|
|
txt = TextClip(text, fontsize=48, color="white",
|
|
size=(w - 100, None), method="caption")
|
|
txt = txt.set_position(("center", h - 180)).set_duration(duration)
|
|
return txt
|
|
|
|
|
|
def compose_video(scenes: list, audio_paths: list, durations: list,
|
|
out_path: str, resolution=(1280, 720)) -> str:
|
|
"""合成最终视频。
|
|
|
|
Args:
|
|
scenes: 场景列表
|
|
audio_paths: 每个场景对应的音频路径
|
|
durations: 每个场景的时长
|
|
out_path: 输出 mp4 路径
|
|
resolution: (width, height)
|
|
|
|
Returns:
|
|
str: 输出文件路径
|
|
"""
|
|
os.makedirs(os.path.dirname(out_path), exist_ok=True)
|
|
clips = []
|
|
for scene, audio, dur in zip(scenes, audio_paths, durations):
|
|
bg = _make_bg(resolution, dur)
|
|
sub = _make_subtitle_clip(scene["text"], resolution, dur)
|
|
audio_clip = AudioFileClip(audio)
|
|
clip = CompositeVideoClip([bg, sub]).set_audio(audio_clip)
|
|
clips.append(clip)
|
|
|
|
final = concatenate_videoclips(clips, method="compose")
|
|
final.write_videofile(out_path, fps=24, codec="libx264", audio_codec="aac")
|
|
return out_path
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("请通过 cli.py 或 app.py 调用")
|