使用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
相关产品推荐
相关产品推荐

