基于FFmpeg的Android视频播放器音视频不同步(视频快2~3倍)问题求助
音视频不同步问题排查及解决方案
问题根因定位
- 解码流程存在缺失
现有BaseDecoder::RealDecode仅调用avcodec_receive_frame拉取解码后帧,没有实现从packet队列取包、调用avcodec_send_packet喂包给解码器的逻辑。如果未对avcodec_receive_frame的返回值做错误处理,会导致解码器要么不停返回错误生成无效帧,要么以最大速度拉取内部缓存帧,完全不受控,直接造成视频播放速度异常。 - PTS计算逻辑存在隐患
当前帧PTS计算依赖GetTimeBase()的返回值,如果该方法返回的不是对应流(视频/音频)独立的AVRational参数,比如错误混用音视频流的timebase、或者返回全局AV_TIME_BASE而非流本身的timebase,会导致PTS计算值偏差2~3倍,直接让同步逻辑失效。 - 同步逻辑设计错误
ReceiveVideoFrame中当视频帧PTS和音频PTS差值大于1秒时,仅休眠了视频额外延迟时长,没有对超过1秒的差值做补偿,导致视频始终快于音频;同时当前仅在音频帧进入同步逻辑时更新audio_pts,没有维护实时音频时钟——音频是持续播放的,非喂帧时间段的播放进度没有被统计,会导致同步的时间基准完全不准。 - 音频播放配置异常
如果音频输出模块(如OpenSL ES)的采样率、声道数、采样格式和解码输出的PCM参数不匹配,会导致音频播放速度变慢,体感上就是视频快2~3倍。 - 队列无流量控制
解码器packet队列、Render的frame队列均未设置最大长度阈值,没有堆积保护逻辑,会导致大量帧积压在队列中,同步逻辑无法及时纠正速度偏差。
修复方案
- 补全解码流程
在BaseDecoder::RealDecode循环中增加错误处理逻辑:如果avcodec_receive_frame返回AVERROR(EAGAIN),则从av_packet_queue取出AVPacket调用avcodec_send_packet喂给解码器,处理EOF等异常返回值,避免无效帧输出。 - 校准PTS计算逻辑
打印音视频流的timebase.num、timebase.den参数,确认GetTimeBase()返回对应流自身的timebase值;打印相邻帧的PTS差值,25fps视频相邻帧差值应为0.04s左右,确认PTS计算符合预期。 - 修正同步逻辑
- 维护独立的音频时钟:根据音频输出的已播放样本数实时计算当前音频播放进度,不依赖最后一帧音频的PTS作为同步基准。
- 调整休眠逻辑:视频帧和音频的差值无论是否超过1秒,都按照实际差值+额外延迟的总时长休眠,不需要单独做1秒阈值的特殊处理。
- 校验音频配置
确认OpenSL ES的输出参数和解码输出的PCM参数完全一致,单独测试音频播放速度是否正常。 - 增加队列流量控制
给packet队列、frame队列设置最大长度(通常视频帧队列不超过10帧,音频packet队列不超过50包),队列满时丢弃非关键帧,避免帧堆积。
内容的提问来源于stack exchange,提问作者ZSpirytus
相关产品推荐
相关产品推荐

