使用MoviePy添加字幕时脚本崩溃的问题求助
MoviePy添加SRT字幕崩溃问题解决
问题情况
使用MoviePy生成.srt字幕并添加到视频时出现崩溃:无字幕视频通过_match_audio_duration()可正常导出,字幕文件已生成但脚本在添加字幕环节报错,实际崩溃根源在SubtitlesClip初始化步骤,而非最初以为的CompositeVideoClip代码行。
报错信息
Traceback (most recent call last): File "*directory*", line 86, in <module> editor.add_captions_to_video() File "*directory*", line 69, in add_captions_to_video captions = SubtitlesClip(self.caption_path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "*directory*", line 55, in __init__ self.duration = max([tb for ((ta,tb), txt) in self.subtitles]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "*directory*", line 55, in <listcomp> self.duration = max([tb for ((ta,tb), txt) in self.subtitles]) ^^^^^^^ TypeError: cannot unpack non-iterable NoneType object Exception ignored in: <function FFMPEG_VideoReader.__del__ at 0x000002097E824400> Traceback (most recent call last): File "*directory*", line 199, in __del__ self.close() File "*directory*", line 190, in close self.proc.terminate() File "*directory*", line 1642, in terminate _winapi.TerminateProcess(self._handle, 1) OSError: [WinError 6] The handle is invalid
完整代码
import os import subprocess import time import moviepy.editor as mp import pyttsx3 from moviepy.video.tools.subtitles import SubtitlesClip class VideoEditor: def __init__(self, input_text_path, input_video_path, output_dir): self.input_text_path = input_text_path self.input_video_path = input_video_path self.output_dir = output_dir self.text = "" self.audio_path = "" self.video_path = "" self.caption_path = "" def _convert_text_to_audio(self): # Read text from file with open(self.input_text_path, "r") as f: self.text = f.read() # Set up pyttsx3 engine = pyttsx3.init() # Convert text to speech and save as MP3 self.audio_path = os.path.join(self.output_dir, "audio.mp3") engine.save_to_file(self.text, self.audio_path) engine.runAndWait() def _match_audio_duration(self): # Set up moviepy input_clip = mp.VideoFileClip(self.input_video_path) audio_clip = mp.AudioFileClip(self.audio_path) if audio_clip.duration > input_clip.duration: input_clip = input_clip.fx(mp.vfx.loop, duration=audio_clip.duration) # Add audio to video final_clip = input_clip.set_audio(audio_clip) # Cut video to match audio duration final_clip = final_clip.subclip(0, audio_clip.duration) # Save output video self.video_path = os.path.join(self.output_dir, "output_video.mp4") final_clip.write_videofile(self.video_path, fps=24) def _create_captions(self): # Create captions from text self.caption_path = os.path.join(self.output_dir, "captions.srt") caption_txt = "" for i, line in enumerate(self.text.splitlines()): start = i * 3 end = (i + 1) * 3 caption_txt += f"{start}00 --> {end}00\n{line}\n\n" with open(self.caption_path, "w") as f: f.write(caption_txt) def add_captions_to_video(self): self._convert_text_to_audio() self._match_audio_duration() self._create_captions() # Set up moviepy input_clip = mp.VideoFileClip(self.video_path) # Create TextClip for captions captions = SubtitlesClip(self.caption_path) caption_clip = captions.set_position(("center", "bottom")) # Overlay captions on video final_clip = mp.CompositeVideoClip([input_clip, caption_clip.set_position(("center", "bottom"))]) # Save output video output_path = os.path.join(self.output_dir, "output_video_captions.mp4") final_clip.write_videofile(output_path, fps=24)
问题根源
崩溃的核心原因是生成的SRT字幕格式完全不符合标准:
- SRT要求时间格式为
HH:MM:SS,mmm(小时:分钟:秒,毫秒),但当前代码生成的是00 --> 300这类无效格式 - SRT每条字幕必须以递增的数字序号开头,当前代码用
start = i*3作为序号,逻辑错误
以上两点导致SubtitlesClip无法解析字幕文件,返回None进而触发unpack错误。
解决方案
1. 修正SRT生成逻辑
修改_create_captions方法,生成符合标准的SRT格式:
def _create_captions(self): # Create captions from text self.caption_path = os.path.join(self.output_dir, "captions.srt") caption_txt = "" lines = self.text.splitlines() for i, line in enumerate(lines): # 计算每条字幕的起止时间(按每条3秒计算) start_sec = i * 3 end_sec = (i + 1) * 3 # 转换为SRT标准时间格式:HH:MM:SS,mmm def format_time(seconds): hours = int(seconds // 3600) minutes = int((seconds % 3600) // 60) secs = int(seconds % 60) millis = int((seconds - int(seconds)) * 1000) return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}" start_time = format_time(start_sec) end_time = format_time(end_sec) # 拼接SRT条目:序号 + 时间轴 + 文本 caption_txt += f"{i+1}\n{start_time} --> {end_time}\n{line}\n\n" with open(self.caption_path, "w", encoding="utf-8") as f: f.write(caption_txt)
2. 完善SubtitlesClip初始化
SubtitlesClip需要传入一个生成文本剪辑的函数来定义字幕样式,否则可能出现渲染问题。修改add_captions_to_video中的对应部分:
def add_captions_to_video(self): self._convert_text_to_audio() self._match_audio_duration() self._create_captions() # Set up moviepy input_clip = mp.VideoFileClip(self.video_path) # 自定义字幕样式函数 def make_text_clip(txt): return mp.TextClip(txt, fontsize=24, color="white", font="Arial", stroke_color="black", stroke_width=1) # 使用自定义样式初始化SubtitlesClip captions = SubtitlesClip(self.caption_path, make_text_clip) caption_clip = captions.set_position(("center", "bottom")) # Overlay captions on video final_clip = mp.CompositeVideoClip([input_clip, caption_clip]) # Save output video output_path = os.path.join(self.output_dir, "output_video_captions.mp4") final_clip.write_videofile(output_path, fps=24)
验证要点
- 生成的SRT文件需符合以下结构:
1 00:00:00,000 --> 00:00:03,000 第一条文本内容 2 00:00:03,000 --> 00:00:06,000 第二条文本内容
- 确保字体存在,若使用非系统字体需指定完整路径
内容的提问来源于stack exchange,提问作者Wyatt
相关产品推荐
相关产品推荐

