Spaces:
Running
Running
File size: 4,583 Bytes
3b13b0e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
"""
使用 moviepy 合并视频、音频、字幕和背景音乐
"""
from moviepy.editor import (
VideoFileClip,
AudioFileClip,
TextClip,
CompositeVideoClip,
concatenate_videoclips
)
# from moviepy.config import change_settings
import os
# 设置字体文件路径(用于中文字幕显示)
FONT_PATH = "../../resource/fonts/STHeitiMedium.ttc" # 请确保此路径下有对应字体文件
# change_settings(
# {"IMAGEMAGICK_BINARY": r"C:\Program Files\ImageMagick-7.1.1-Q16\magick.exe"}) # Windows系统需要设置 ImageMagick 路径
class VideoMerger:
"""视频合并处理类"""
def __init__(self, output_path: str = "../../resource/videos/merged_video.mp4"):
"""
初始化视频合并器
参数:
output_path: 输出文件路径
"""
self.output_path = output_path
self.video_clips = []
self.background_music = None
self.subtitles = []
def add_video(self, video_path: str, start_time: str = None, end_time: str = None) -> None:
"""
添加视频片段
参数:
video_path: 视频文件路径
start_time: 开始时间 (格式: "MM:SS")
end_time: 结束时间 (格式: "MM:SS")
"""
video = VideoFileClip(video_path)
if start_time and end_time:
video = video.subclip(self._time_to_seconds(start_time),
self._time_to_seconds(end_time))
self.video_clips.append(video)
def add_audio(self, audio_path: str, volume: float = 1.0) -> None:
"""
添加背景音乐
参数:
audio_path: 音频文件路径
volume: 音量大小 (0.0-1.0)
"""
self.background_music = AudioFileClip(audio_path).volumex(volume)
def add_subtitle(self, text: str, start_time: str, end_time: str,
position: tuple = ('center', 'bottom'), fontsize: int = 24) -> None:
"""
添加字幕
参数:
text: 字幕文本
start_time: 开始时间 (格式: "MM:SS")
end_time: 结束时间 (格式: "MM:SS")
position: 字幕位置
fontsize: 字体大小
"""
subtitle = TextClip(
text,
font=FONT_PATH,
fontsize=fontsize,
color='white',
stroke_color='black',
stroke_width=2
)
subtitle = subtitle.set_position(position).set_duration(
self._time_to_seconds(end_time) - self._time_to_seconds(start_time)
).set_start(self._time_to_seconds(start_time))
self.subtitles.append(subtitle)
def merge(self) -> None:
"""合并所有媒体元素并导出视频"""
if not self.video_clips:
raise ValueError("至少需要添加一个视频片段")
# 合并视频片段
final_video = concatenate_videoclips(self.video_clips)
# 如果有背景音乐,设置其持续时间与视频相同
if self.background_music:
self.background_music = self.background_music.set_duration(final_video.duration)
final_video = final_video.set_audio(self.background_music)
# 添加字幕
if self.subtitles:
final_video = CompositeVideoClip([final_video] + self.subtitles)
# 导出最终视频
final_video.write_videofile(
self.output_path,
fps=24,
codec='libx264',
audio_codec='aac'
)
# 释放资源
final_video.close()
for clip in self.video_clips:
clip.close()
if self.background_music:
self.background_music.close()
@staticmethod
def _time_to_seconds(time_str: str) -> float:
"""将时间字符串转换为秒数"""
minutes, seconds = map(int, time_str.split(':'))
return minutes * 60 + seconds
def test_merge_video():
"""测试视频合并功能"""
merger = VideoMerger()
# 添加两个视频片段
merger.add_video("../../resource/videos/cut_video.mp4", "00:00", "01:00")
merger.add_video("../../resource/videos/demo.mp4", "00:00", "00:30")
# 添加背景音乐
merger.add_audio("../../resource/songs/output000.mp3", volume=0.3)
# 添加字幕
merger.add_subtitle("第一个精彩片段", "00:00", "00:05")
merger.add_subtitle("第二个精彩片段", "01:00", "01:05")
# 合并并导出
merger.merge()
if __name__ == "__main__":
test_merge_video()
|