返回

字幕叠加不同步?问题解析与FFmpeg解决方案

python

字幕叠加不同步:问题解析与解决方案

视频处理中,字幕叠加不同步是个常见的问题。常见表现是字幕总是从视频起始位置开始,而非与视频片段同步。这通常由时间参数配置错误导致。 本文分析此问题背后的原因并提供可行的解决策略。

问题分析

问题的核心在于时间同步。字幕时间轴与其对应的视频时间轴未能对齐。尽管 .srt 文件格式正确,并且视频剪辑也已经实现,但在将字幕添加到裁剪片段时,同步偏移未得到妥善处理。关键原因分析:

  • 时间基准不一致: 提取的视频片段的时间基准是裁剪片段的开始时间;字幕时间基准仍是完整视频的开始时间。若不指定偏移,FFmpeg 会认为字幕的起始时间总是相对于视频的开头。
  • FFmpeg 参数错误: 虽然在 FFmpeg 命令中设置了 -ss 参数用于截取视频片段,但这仅仅影响视频内容的读取起始点,对字幕的时间戳无效。需要在 subtitles 过滤器中添加时间偏移(TimeOffset)。

解决方案

为了解决字幕与视频片段的同步问题,必须让 FFmpeg 知道字幕的偏移时间。需要以下修改:

  1. 正确使用TimeOffset: 使用 FFmpeg 的 subtitles 过滤器时,需指定 TimeOffset 参数,告诉 FFmpeg 字幕需要向前或向后移动多少秒。将剪辑开始时间用作偏移量。
  2. 仅将 input_file 用作参考: -ss 参数应用于输入文件,以便字幕文件根据原始时间轴加载,并与视频正确对齐。视频剪辑可以使用 -i temp_clip.mp4 但为了确保没有额外的 seek 影响,我们选择不使用剪辑后的临时文件。
  3. 注意 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 认识到字幕的偏移量,最终实现字幕和视频片段的同步。

步骤说明

  1. 将代码粘贴到 .py 文件,确保已安装 moviepy 库:
    pip install moviepy
    
  2. 创建output_folder ,如果需要,在同一目录下放置视频文件和 .srt 文件。
  3. 运行 Python 脚本。它会处理多个剪辑片段,正确地叠加字幕并同步。

通过这些修改,视频片段与字幕应能正确同步。 务必使用匹配视频的 .srt 文件,避免出现错乱现象。 并且 srt_file 必须与 input_file 的时间线完全一致。