如何提升基于帧率的FFmpeg生成时间戳的精度至毫秒级?
解决FFmpeg生成毫秒级精度时间戳的问题
问题原因
你当前命令中使用了输入端的-r $FRAMERATE参数,这个参数会强制FFmpeg将输入流的帧时间戳对齐到固定帧率的间隔(4fps对应250ms),即使滤镜里用了RTCTIME获取系统时间,最终时间戳也会被强制对齐,导致精度无法突破帧率间隔。
修正方案
核心修改点
- 移除输入端的
-r $FRAMERATE:避免强制时间戳对齐,让FFmpeg保留每个帧的真实时间戳精度。 - 将帧率参数移至输出端:仅用于设置视频文件的标称帧率,不影响时间戳的原始精度。
- 保留
RTCTIME的高精度:RTCTIME本身是微秒级精度,通过调整时基可以直接输出毫秒级甚至微秒级时间戳。
修正后的命令
-hide_banner \ -s $(((WIDTH + 63) / 64 * 64))"x"$(((HEIGHT + 15) / 16 * 16)) \ -f rawvideo \ -pix_fmt yuv420p \ -i - \ -filter_complex "crop=$WIDTH:$CROPPED_HEIGHT:0:0,settb=1/1000,setpts=RTCTIME/1000-1500000000000,split[out][ts];[out]setpts=N/FRAME_RATE/TB[out]" \ -map [out] \ -c:v ffv1 \ -vsync passthrough \ -r $FRAMERATE \ -f matroska \ "$OUTPUT_PATH/${FILENAME}.mkv" \ -map [ts] \ -flush_packets 1 \ -f mkvtimestamp_v2 \ "$OUTPUT_PATH/${FILENAME}_ts2.txt"
可选:获取微秒级精度时间戳
如果需要更高精度(比如微秒级),可以调整滤镜中的时基和时间戳计算:
-hide_banner \ -s $(((WIDTH + 63) / 64 * 64))"x"$(((HEIGHT + 15) / 16 * 16)) \ -f rawvideo \ -pix_fmt yuv420p \ -i - \ -filter_complex "crop=$WIDTH:$CROPPED_HEIGHT:0:0,settb=1/1000000,setpts=RTCTIME-1500000000000000,split[out][ts];[out]setpts=N/FRAME_RATE/TB[out]" \ -map [out] \ -c:v ffv1 \ -vsync passthrough \ -r $FRAMERATE \ -f matroska \ "$OUTPUT_PATH/${FILENAME}.mkv" \ -map [ts] \ -flush_packets 1 \ -f mkvtimestamp_v2 \ "$OUTPUT_PATH/${FILENAME}_ts2.txt"
此时生成的_ts2.txt中时间戳为微秒级,后续可根据需求除以1000转换为毫秒级。
说明
vsync passthrough参数确保输出视频保留原始时间戳,不会被FFmpeg重新对齐。- 若你的rawvideo输入流本身携带时间戳(比如从专业采集设备输入),可以去掉滤镜中的
setpts=RTCTIME...,直接保留输入流的原始时间戳即可。
内容的提问来源于stack exchange,提问作者Doopy
相关产品推荐
相关产品推荐

