FFmpeg转码H264 MP4视频卡顿问题排查求助
Windows下FFmpeg采集编码卡顿排查与音频PTS处理建议
视频卡顿的核心排查方向
1. 采集源的时间戳问题
gdigrab和dshow采集的原始帧经常会出现时间戳无效或不统一的情况——比如dshow的视频帧时间戳可能是系统时钟的微秒,gdigrab可能直接用帧率估算的假时间戳,直接丢给编码器会导致PTS混乱。
- 打印采集到的
AVFrame的pts、pkt_dts字段,确认是否连续且符合29.97fps的间隔(大概每帧33367微秒)。如果原始帧pts是AV_NOPTS_VALUE,得手动基于采集顺序+帧率生成,但别硬套固定间隔,要和实际采集节奏匹配。
2. 滤镜链的配置问题
你用了fps和setpts滤镜,但顺序和参数错了也会出问题:
- 正确的顺序应该是先
fps=fps=29.97强制帧率,再用setpts=PTS-STARTPTS重置起始时间戳,避免开头的时间戳偏移。如果反过来,可能会导致丢帧/重复帧的PTS不连贯。 - 打印滤镜输出帧的PTS,用
av_frame_get_best_effort_timestamp()查看,确保相邻帧的时间差稳定在33367微秒左右。
3. 编码器参数的锅
H264编码器参数没调好,编码速度跟不上采集速度,帧积压就会卡顿:
preset别设太“慢”,Windows下libx264用preset=fast或medium就行,平衡质量和速度;- 开启
thread_count,设成和CPU核心数一致,提升编码效率; - 编码器的
time_base要和输出流匹配:29.97fps对应的time_base应该是AVRational{1, 30000}(因为30000/1001=29.97),输出流的time_base也要对应上,别搞混单位。
4. 音视频同步问题
哪怕视频帧率显示正常,音频PTS和视频PTS不匹配,播放器会为了同步丢帧/重复帧,表现出来就是卡顿。比如音频PTS涨得太快,播放器会加速视频,看起来就卡;反之则减速卡顿。
音频PTS的正确计算方式
别依赖采集到的音频帧PTS,dshow的音频时间戳经常有偏移或不连续,自己算才靠谱:
- 维护一个累计采样数的变量,每收到一帧音频,就把
frame->nb_samples加进去; - PTS公式:
pts = (累计采样数 * AV_TIME_BASE) / 采样率,比如采样率44100Hz,每帧1024个采样点,那每帧的PTS增量就是1024 * AV_TIME_BASE / 44100 ≈ 23219微秒; - 输出音频流的
time_base建议设为AVRational{1, AV_TIME_BASE},编码器的time_base也要对应,最后用av_packet_rescale_ts()把编码后的packet时间戳转换成流的time_base。
代码排查的关键节点
- 采集阶段:打印每个采集帧的
pts、pkt_dts、duration,确认有没有无效值(比如AV_NOPTS_VALUE),时间间隔是否稳定; - 滤镜处理阶段:打印滤镜输出帧的PTS,看是否连续、符合帧率要求;
- 编码阶段:检查编码器输出的
AVPacket的pts、dts是否递增,有没有跳变或负数;同时监控编码队列长度,如果一直涨,说明编码速度跟不上,得调参数; - 封装阶段:确认MP4封装时,音视频流的
time_base设置正确,编码后的packet已经用av_packet_rescale_ts()转换过时间戳。
快速验证方法
- 先把滤镜全去掉,直接采集编码,看还卡不卡。如果不卡,说明滤镜链有问题;如果还卡,就查采集或编码器参数;
- 用FFmpeg命令行测相同的采集源:比如采集桌面用
ffmpeg -f gdigrab -framerate 29.97 -i desktop -c:v libx264 -preset fast -crf 23 output.mp4,看命令行生成的视频卡不卡。如果命令行正常,就对比你的代码和命令行的参数差异,肯定是哪里配置不一样。
内容的提问来源于stack exchange,提问作者Expressingx
相关产品推荐
相关产品推荐

