You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

音频采样率为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

火山引擎 最新活动