返回
字幕叠加不同步?问题解析与FFmpeg解决方案
python
2024-12-27 20:37:58
字幕叠加不同步:问题解析与解决方案
视频处理中,字幕叠加不同步是个常见的问题。常见表现是字幕总是从视频起始位置开始,而非与视频片段同步。这通常由时间参数配置错误导致。 本文分析此问题背后的原因并提供可行的解决策略。
问题分析
问题的核心在于时间同步。字幕时间轴与其对应的视频时间轴未能对齐。尽管 .srt
文件格式正确,并且视频剪辑也已经实现,但在将字幕添加到裁剪片段时,同步偏移未得到妥善处理。关键原因分析:
- 时间基准不一致: 提取的视频片段的时间基准是裁剪片段的开始时间;字幕时间基准仍是完整视频的开始时间。若不指定偏移,FFmpeg 会认为字幕的起始时间总是相对于视频的开头。
- FFmpeg 参数错误: 虽然在 FFmpeg 命令中设置了
-ss
参数用于截取视频片段,但这仅仅影响视频内容的读取起始点,对字幕的时间戳无效。需要在subtitles
过滤器中添加时间偏移(TimeOffset
)。
解决方案
为了解决字幕与视频片段的同步问题,必须让 FFmpeg 知道字幕的偏移时间。需要以下修改:
- 正确使用
TimeOffset
: 使用 FFmpeg 的subtitles
过滤器时,需指定TimeOffset
参数,告诉 FFmpeg 字幕需要向前或向后移动多少秒。将剪辑开始时间用作偏移量。 - 仅将
input_file
用作参考:-ss
参数应用于输入文件,以便字幕文件根据原始时间轴加载,并与视频正确对齐。视频剪辑可以使用-i temp_clip.mp4
但为了确保没有额外的 seek 影响,我们选择不使用剪辑后的临时文件。 - 注意 duration 参数: 输出时间
-t
也必须正确设置,应为裁剪视频的持续时间(end_time - start_time
)。
以下为修改后的代码:
import subprocess
from moviepy.editor import VideoFileClip
def parse_srt(srt_file):
"""Parse the SRT file and return a list of subtitles with their timestamps."""
subtitles = []
with open(srt_file, 'r') as f:
content = f.read().strip().split('\n\n')
for entry in content:
lines = entry.split('\n')
if len(lines) >= 3:
index = lines[0]
timestamps = lines[1]
text = '\n'.join(lines[2:])
start, end = timestamps.split(' --> ')
subtitles.append((start.strip(), end.strip(), text.strip()))
return subtitles
def print_subtitles_in_range(subtitles, start_time, end_time):
"""Print subtitles that fall within the given start and end times."""
for start, end, text in subtitles:
start_seconds = convert_srt_time_to_seconds(start)
end_seconds = convert_srt_time_to_seconds(end)
if start_seconds >= start_time and end_seconds <= end_time:
print(f"{start} --> {end}: {text}")
def convert_srt_time_to_seconds(time_str):
"""Convert SRT time format to total seconds."""
hours, minutes, seconds = map(float, time_str.replace(',', '.').split(':'))
return hours * 3600 + minutes * 60 + seconds
def create_captioned_clip(input_file, start_time, end_time, srt_file, output_file):
# Step 1: Extract the clip from the main video
clip = VideoFileClip(input_file).subclip(start_time, end_time)
print("Clip duration:", clip.duration)
# 移除临时剪辑文件
#temp_clip_path = "temp_clip.mp4"
#clip.write_videofile(temp_clip_path, codec="libx264")
# Step 2: Parse the SRT file to get subtitles
subtitles = parse_srt(srt_file)
# Step 3: Print subtitles that fall within the start and end times
print("\nSubtitles for the selected clip:")
print_subtitles_in_range(subtitles, start_time, end_time)
# Step 4: Add subtitles using FFmpeg with TimeOffset correction
ffmpeg_command = [
"ffmpeg",
"-i", input_file,
"-vf", f"subtitles='{srt_file}:force_style=Alignment=10,TimeOffset={start_time}'",
"-ss", str(start_time),
"-to", str(end_time), # 使用 -to 而非 -t 更加符合习惯。
output_file
]
print("Running command:", ' '.join(ffmpeg_command))
subprocess.run(ffmpeg_command, capture_output=True, text=True)
# Define input video and srt file
input_video = "Soul.2020.720p.BluRay.x264.AAC-[YTS.MX].mp4"
subtitle_file = "Soul.2020.720p.BluRay.x264.AAC-[YTS.MX].srt"
# Define multiple clips with start and end times
clips = [
{"start": (5 * 60), "end": (5 * 60 + 30), "output": "output_folder/captioned_clip1.mp4"},
{"start": (7 * 60), "end": (7 * 60 + 25), "output": "output_folder/captioned_clip2.mp4"},
]
# Process each clip
for clip_info in clips:
create_captioned_clip(input_video, clip_info["start"], clip_info["end"], subtitle_file, clip_info["output"])
-i input_file
:使用完整原始文件进行字幕叠加。-vf
: 字幕叠加,使用TimeOffset={start_time}
,使字幕同步到指定起始时间。Alignment=10
保证字幕显示在底部中间位置,更美观易读。-ss
: 将视频处理的起始时间,调整到期望片段的起始时间。-to
: 使用to
来指定持续时间,避免与-ss
命令参数的冲突。
修改后的脚本会使 FFmpeg 认识到字幕的偏移量,最终实现字幕和视频片段的同步。
步骤说明
- 将代码粘贴到
.py
文件,确保已安装 moviepy 库:pip install moviepy
- 创建
output_folder
,如果需要,在同一目录下放置视频文件和.srt
文件。 - 运行 Python 脚本。它会处理多个剪辑片段,正确地叠加字幕并同步。
通过这些修改,视频片段与字幕应能正确同步。 务必使用匹配视频的 .srt 文件,避免出现错乱现象。 并且 srt_file
必须与 input_file
的时间线完全一致。