perf(render_video): 优化视频编码的关键帧间隔策略

- 根据视频总帧数动态计算 GOP 大小,避免关键帧过多
- 短视频使用全部帧数作为 GOP,确保只在开头有关键帧
- 正常视频保持 2 秒一个关键帧的策略
- 添加强制第一帧为关键帧的设置
- 优化关键帧最小间隔参数,提升编码效率
This commit is contained in:
2026-02-04 17:46:01 +08:00
parent a70573395b
commit eeb21cada3

View File

@@ -275,12 +275,24 @@ class RenderSegmentVideoHandler(BaseHandler):
cmd.extend(['-vf', ','.join(filters)]) cmd.extend(['-vf', ','.join(filters)])
# 计算总帧数,动态调整 GOP
total_frames = int(actual_duration_sec * fps)
if total_frames <= 1:
gop_size = 1
elif total_frames < fps:
gop_size = total_frames
else:
gop_size = fps * 2 # 正常情况,2 秒一个关键帧
# 编码参数 # 编码参数
cmd.extend([ cmd.extend([
'-c:v', 'libx264', '-c:v', 'libx264',
'-preset', 'fast', '-preset', 'fast',
'-crf', '18', '-crf', '18',
'-r', str(fps), '-r', str(fps),
'-g', str(gop_size),
'-keyint_min', str(min(gop_size, fps // 2 or 1)),
'-force_key_frames', 'expr:eq(n,0)',
'-an', # 无音频 '-an', # 无音频
output_file output_file
]) ])
@@ -357,16 +369,28 @@ class RenderSegmentVideoHandler(BaseHandler):
fps = output_spec.fps fps = output_spec.fps
cmd.extend(['-r', str(fps)]) cmd.extend(['-r', str(fps)])
# GOP 大小(关键帧间隔)
gop_size = fps * 2 # 2秒一个关键帧
cmd.extend(['-g', str(gop_size)])
cmd.extend(['-keyint_min', str(gop_size)])
# 时长(包含 overlap 区域) # 时长(包含 overlap 区域)
total_duration_ms = duration_ms + overlap_head_ms + overlap_tail_ms total_duration_ms = duration_ms + overlap_head_ms + overlap_tail_ms
duration_sec = total_duration_ms / 1000.0 duration_sec = total_duration_ms / 1000.0
cmd.extend(['-t', str(duration_sec)]) cmd.extend(['-t', str(duration_sec)])
# 动态调整 GOP 大小:对于短视频,GOP 不能大于总帧数
total_frames = int(duration_sec * fps)
if total_frames <= 1:
gop_size = 1
elif total_frames < fps:
# 短于 1 秒的视频,使用全部帧数作为 GOP(整个视频只有开头一个关键帧)
gop_size = total_frames
else:
# 正常情况,2 秒一个关键帧
gop_size = fps * 2
cmd.extend(['-g', str(gop_size)])
cmd.extend(['-keyint_min', str(min(gop_size, fps // 2 or 1))])
# 强制第一帧为关键帧
cmd.extend(['-force_key_frames', 'expr:eq(n,0)'])
# 无音频(视频片段不包含音频) # 无音频(视频片段不包含音频)
cmd.append('-an') cmd.append('-an')