使用FFmpeg裁剪视频时出现帧序号偏移问题
解决FFmpeg裁剪59.94fps视频时的帧偏移问题
我之前处理非整数帧率视频时也碰到过一模一样的问题,尤其是你用的59.94fps(实际是60000/1001≈59.94fps)的MTS格式,很容易因为帧率特性和封装格式的细节出现帧偏移。下面给你拆解原因和解决办法:
核心问题分析
- 非整数帧率的计算偏差:59.94不是严格的整数,帧索引和实际时间的对应关系并非绝对线性,直接用
start_frame/end_frame指定范围时,FFmpeg内部的帧计数逻辑容易出现累积误差,导致最终偏移。 - MTS视频的帧顺序差异:MTS属于MPEG-TS封装,视频流通常包含B帧(双向预测帧)——这类帧的存储顺序(DTS)和显示顺序(PTS)不一致。
trim滤镜的start_frame是按显示顺序计数的,但实际裁剪时会受存储顺序影响,导致选中的帧和预期出现偏移。
解决方案
方案1:改用时间戳裁剪(最可靠)
先把目标帧索引转换成对应的时间,再用时间参数代替帧索引:
- 开始时间:
36435 / 59.94 ≈ 607.86秒 - 结束时间:
36786 / 59.94 ≈ 613.71秒
修改后的代码如下:
import os import ffmpeg print(os.listdir('C:/Users/sgris/Downloads')) ( ffmpeg .input('C:/Users/sgris/Downloads/apid/18-2-19 6.04pm.MTS') .trim(start=607.86, end=613.71) .setpts('PTS-STARTPTS') # 重置时间戳,避免播放卡顿 .output('C:/Users/sgris/Downloads/testtest2.mp4') .run() )
如果想要极致精准,可以先用ffprobe查看目标帧的实际显示时间:
ffprobe -v error -select_streams v:0 -show_entries frame=frame_number,pkt_pts_time -of csv=p=0 "C:/Users/sgris/Downloads/apid/18-2-19 6.04pm.MTS" | grep "36435"
把返回的时间值直接填入start参数即可。
方案2:用select滤镜按帧索引选择(必须用帧索引时)
如果一定要基于帧索引裁剪,select滤镜的筛选逻辑更直接,会严格按显示顺序的帧序号挑选,同时重新计算时间戳:
import os import ffmpeg print(os.listdir('C:/Users/sgris/Downloads')) ( ffmpeg .input('C:/Users/sgris/Downloads/apid/18-2-19 6.04pm.MTS') .filter('select', 'between(n,36435,36786)') # n代表显示顺序的帧序号 .setpts('N/FRAME_RATE/TB') # 基于实际帧率重新生成时间戳 .output('C:/Users/sgris/Downloads/testtest2.mp4', vsync='vfr') # 可变帧率输出,避免丢帧 .run() )
验证方法
裁剪后可以用以下命令检查输出视频的总帧数,确认是否符合预期(预期帧数:36786 - 36435 + 1 = 352帧):
ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames "C:/Users/sgris/Downloads/testtest2.mp4"
内容的提问来源于stack exchange,提问作者Sylvain
相关产品推荐
相关产品推荐

