You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FFmpeg滤镜调整视频速度时的时长偏差问题

视频速度对齐问题:MoviePy与直接FFmpeg调用的时长偏差

我正在做一个通过调整视频速度来对齐配音和对应字幕的项目,同时使用FFmpeg(直接调用及通过MoviePy间接调用)处理视频,但遇到了一个问题:

  • 用MoviePy调整视频速度并拼接片段后,最终视频时长和配音时长完全匹配;
  • 但直接用FFmpeg复杂滤镜脚本处理速度并拼接视频片段时,最终视频往往比配音短1-2秒,结尾出现对齐偏差,且字幕越长偏差越大。

效果完美但速度较慢的MoviePy代码

total_video_duration_sec = get_video_duration(input_video)
durations = get_durations()

if subtitles[0].start.total_seconds() > 0:
    gap_clip = clip.subclip(0, subtitles[0].start.total_seconds()).without_audio()
    processed_clips.append(gap_clip)

for i, (subtitle, audio_durations_sec) in enumerate(zip(subtitles, durations)):

    start_sec = subtitle.start.total_seconds()
    end_sec = subtitle.end.total_seconds()
    next_start_sec = subtitles[i + 1].start.total_seconds() if i < len(subtitles) - 1 else total_video_duration_sec
    original_duration_sec = end_sec - start_sec

    pause_duration_sec = next_start_sec - end_sec

    # 计算速度因子
    speed_factor = original_duration_sec / audio_duration_sec

    # 从原视频中提取字幕对应的片段
    subtitle_clip = clip.subclip(start_sec, end_sec).without_audio()
    
    # 对片段应用速度调整
    adjusted_clip = subtitle_clip.fx(speedx, speed_factor)
    
    # 将调整后的片段加入列表
    processed_clips.append(adjusted_clip)


    if pause_duration_sec > 0:
        gap_clip = clip.subclip(end_sec, next_start_sec).without_audio()
        processed_clips.append(gap_clip)

 
# 拼接所有处理后的片段
final_clip = concatenate_videoclips(processed_clips)

速度快但存在时长偏差的FFmpeg脚本

# 获取输入视频的总时长和帧率
total_video_duration_sec, fps = get_video_info(input_video)

# 获取每个字幕对应的配音片段时长
durations = get_durations()

# 如果第一个字幕不是从视频开头开始,添加视频开头到第一个字幕起始点的片段
if subtitles[0].start.total_seconds() > 0:
    initial_pause_video_script = f"[0:v]trim=start=0:end={round(subtitles[0].start.total_seconds(), 3)},setpts=PTS-STARTPTS[v0]"
    filter_script.insert(0, initial_pause_video_script)
    inputs.insert(0, "[v0]")

# 遍历每个字幕及其对应的配音时长
for i, (subtitle, audio_duration_sec) in enumerate(zip(subtitles, durations)):
    
    # 确定下一个字幕的起始时间(如果是最后一个字幕则用视频总时长)
    next_start_sec = subtitles[i + 1].start.total_seconds() if i < len(subtitles) - 1 else total_video_duration_sec
    start_sec = subtitle.start.total_seconds()
    end_sec = subtitle.end.total_seconds()
    original_duration_sec = end_sec - start_sec
    pause_duration_sec = next_start_sec - end_sec
    
    # 根据配音时长和原字幕片段时长计算速度因子
    speed_factor = audio_duration_sec / original_duration_sec 

    # 生成字幕对应视频片段的滤镜脚本
    filter_script.append(f"[0:v]trim=start={start_sec}:end={end_sec},setpts={speed_factor}*(PTS-STARTPTS)[v{i*2+1}]")
    inputs.append(f"[v{i*2+1}]")
    
    # 如果当前字幕和下一个字幕之间有间隔,生成间隔片段的滤镜脚本
    if pause_duration_sec > 0:
        filter_script.append(f"[0:v]trim=start={end_sec}:end={next_start_sec},setpts=PTS-STARTPTS[v{i*2+2}]")
        inputs.append(f"[v{i*2+2}]")

# 组合所有滤镜脚本和输入流,生成最终滤镜脚本
filter_chain = ";".join(filter_script)
inputs_chain = "".join(inputs)
final_filter_script = f"{filter_chain};{inputs_chain}concat=n={len(inputs)}:v=1,fps={fps}[outv]"

# 将最终滤镜脚本写入文件
with open(filter_complex_file, "w") as f:
    f.write(final_filter_script)

# 生成并执行FFmpeg命令处理视频
cmd = [
    'ffmpeg', '-y', 
    '-i', input_video,  # 输入视频文件
    '-filter_complex_script', 'filtergraph.txt', 
    '-map', '[outv]',  # 映射滤镜输出的视频流
    '-c:v', 'libx264', '-preset', 'veryfast', '-crf', '18',
    final_output_video  # 输出文件
]
subprocess.run(cmd)

我发现不仅FFmpeg的速度调整不够准确,就连简单剪辑操作的表现也不如MoviePy。既然MoviePy底层同样依赖FFmpeg,想知道直接使用FFmpeg时忽略了哪些细节。

已尝试的解决方法:修改帧率、在trim滤镜中使用start_frame和end_frame参数。

内容的提问来源于stack exchange,提问作者awerks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:05:57