从MP4生成TS文件出现时长不一致问题求助
解决FFmpeg裁剪TS文件时长偏差的问题
我碰到过好多次这种TS时长和预期不符的情况,结合你的命令和问题描述,咱们先拆解下原因,再给出针对性的解决方案:
为什么会出现时长偏差?
你的预期时长是29.834 - 1.000 = 28.834秒(28834ms),但实际输出多了39ms,主要有两个核心原因:
- MPEG-TS容器的强制帧对齐:TS流是基于188字节的数据包传输的,视频帧必须对齐到关键帧或GOP边界,FFmpeg为了符合TS规范,会自动调整输出时长,确保最后一帧能完整封装,这就可能导致时长略有超出。
- 时间戳处理逻辑:你把
-ss放在-i之后,FFmpeg会先解码整个视频到起始时间点,虽然起始时间精确,但-to是基于输入视频的时间戳计算结束点,如果输入视频存在B帧、帧率不是严格整数,或者帧时间戳有微小偏移,都会导致实际输出时长偏差。
解决方案
方案1:调整参数顺序,用-t指定精确时长
把-ss移到-i之前(配合-accurate_seek保证精确seek),同时用-t直接指定要输出的时长(28.834秒),再加上-avoid_negative_ts make_zero确保时间戳从0开始,避免TS容器自动调整:
ffmpeg -ss 00:00:01.000 -accurate_seek -i "C:\FFMPEG\Temp\S3\2ad239d1-f4b9-4854-afe4-7e28157893daHighRes.mp4" -t 00:00:28.834 -q:v 0 -y -vf "fade=t=out:st=28.334:d=0.500, scale=iw*min(1080/iw\,720/ih):ih*min(1080/iw\,720/ih),pad=1080:720:(1080-iw)/2:(720-ih)/2" -avoid_negative_ts make_zero -shortest "C:\FFMPEG\Temp\Crops\5ae9806e32ab040978d97013_0.ts"
注意:fade滤镜的
st参数调整为28.334,因为起始时间是1秒,所以实际fade开始时间是1+28.334=29.334,和你原来的逻辑一致;-shortest确保输出时长由视频/音频中较短的流决定,避免音频拖长时长。
方案2:强制输出指定帧数(最精确)
如果知道输入视频的帧率,直接计算要输出的帧数,用-frames:v强制限制,完全规避容器的自动调整:
- 先获取输入视频的帧率:
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 "C:\FFMPEG\Temp\S3\2ad239d1-f4b9-4854-afe4-7e28157893daHighRes.mp4"
- 计算帧数:比如帧率是30fps,那么
28.834 * 30 ≈ 865帧,然后修改命令:
ffmpeg -ss 00:00:01.000 -accurate_seek -i "C:\FFMPEG\Temp\S3\2ad239d1-f4b9-4854-afe4-7e28157893daHighRes.mp4" -frames:v 865 -q:v 0 -y -vf "fade=t=out:st=28.334:d=0.500, scale=iw*min(1080/iw\,720/ih):ih*min(1080/iw\,720/ih),pad=1080:720:(1080-iw)/2:(720-ih)/2" -avoid_negative_ts make_zero -shortest "C:\FFMPEG\Temp\Crops\5ae9806e32ab040978d97013_0.ts"
方案3:先输出MP4再转TS
MP4容器对时长的限制更宽松,先精确裁剪到MP4,再转成TS,避免TS的帧对齐干扰:
- 生成精确时长的MP4:
ffmpeg -ss 00:00:01.000 -accurate_seek -i "C:\FFMPEG\Temp\S3\2ad239d1-f4b9-4854-afe4-7e28157893daHighRes.mp4" -t 00:00:28.834 -q:v 0 -y -vf "fade=t=out:st=28.334:d=0.500, scale=iw*min(1080/iw\,720/ih):ih*min(1080/iw\,720/ih),pad=1080:720:(1080-iw)/2:(720-ih)/2" -avoid_negative_ts make_zero -shortest "C:\FFMPEG\Temp\Temp.mp4"
- 转成TS(直接复制流,保证时长不变):
ffmpeg -i "C:\FFMPEG\Temp\Temp.mp4" -c:v copy -c:a copy -y "C:\FFMPEG\Temp\Crops\5ae9806e32ab040978d97013_0.ts"
验证结果
执行完命令后,用ffprobe检查时长:
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "C:\FFMPEG\Temp\Crops\5ae9806e32ab040978d97013_0.ts"
应该会得到28.834左右的结果,误差在几毫秒内(符合视频帧的精度)。
内容的提问来源于stack exchange,提问作者Mark Walsh
相关产品推荐
相关产品推荐

