音频采样率为48000kHz时生成视频与音频仍不同步的技术求助
解决WAV转视频的音视频同步问题
首先,咱们来拆解你遇到的问题:视频波形提前结束、后续重复最后一帧,本质是发送给FFmpeg的视频帧数量不足,或者帧的时间戳没有正确对应音频时间。结合你的代码逻辑,主要问题出在帧生成的时机判断上,咱们一步步来修正:
1. 当前逻辑的核心错误
你现在的代码是逐样本遍历,通过frame_counter取模触发帧发送,但这个逻辑会导致两个关键问题:
- 帧的生成时机和对应音频区间不匹配:第一次发送帧时只处理了第0个样本,但这帧本该对应0~1/24秒的2000个样本;后续每帧对应的是累积到当前的所有样本,而非固定时间段的内容
- 样本数非
frame_max整数倍时,容易漏掉最后一组样本的帧,导致总帧数不足
2. 修正方案:按帧区间处理音频样本
正确的思路是按帧划分音频区间,每帧对应固定时长的音频样本,处理完整个区间后再发送帧。这样既能保证帧数准确,也能让波形和对应音频时间段匹配:
int main() { // LoadAudio(); const uint32_t samples_per_frame = audio.sample_rate / 24; // 每帧对应的样本数(48000/24=2000) const uint32_t total_samples = audio.left_channel.size(); // 计算总帧数:向上取整,确保最后不足一帧的样本也能生成对应帧 const uint32_t total_frames = (total_samples + samples_per_frame - 1) / samples_per_frame; // InitializePipe2FFMPEG(); for (uint32_t frame_idx = 0; frame_idx < total_frames; ++frame_idx) { // 计算当前帧对应的样本区间 const uint32_t start_sample = frame_idx * samples_per_frame; // 最后一帧的结束样本不能超过总样本数 const uint32_t end_sample = std::min(start_sample + samples_per_frame, total_samples); // 更新波形:仅处理当前帧区间内的样本 for (uint32_t i = start_sample; i < end_sample; ++i) { UpdateWaveform4Image(audio.left_channel[i], audio.right_channel[i]); } // 绘制并发送当前帧到FFmpeg DrawImageAndSend2Pipe(); } // FlushAndClosePipe(); return 0; }
3. 额外优化:设置正确的帧时间戳(PTS)
如果按上面的方法仍有同步问题,大概率是FFmpeg没有收到正确的帧时间戳。你需要在发送每帧时,给FFmpeg指定该帧的显示时间(PTS),确保和音频时间严格对齐:
// 每帧的时间戳,单位:微秒(可根据FFmpeg的时间基数调整) const int64_t pts = frame_idx * (1000000 / 24); // 在DrawImageAndSend2Pipe()中传递PTS给FFmpeg的AVFrame // 示例:av_frame_set_pts(frame, pts);
4. 验证要点
- 确认总帧数:
total_frames应等于音频时长(秒) * 24,比如100秒音频对应2400帧 - 检查波形更新逻辑:确保每帧的波形只对应当前区间的样本(这样波形会随时间滚动,而非一直累积增长)
- 确认FFmpeg参数:确保输出视频帧率确实为24fps,比如添加参数
-r 24
调整后,每帧都对应固定时长的音频,帧数准确,FFmpeg就能正确同步音视频,不会出现波形提前结束的问题了。
内容的提问来源于stack exchange,提问作者zeroslash




