混音前必须重采样到统一格式:48000hz、av_ch_layout_stereo、av_sample_fmt_fltp;需按sample对齐、pts时间戳同步、浮点加法混音并幅度钳制,输出前须适配编码器格式与frame_size。

混音前必须重采样到统一格式
FFmpeg 的 av_audio_convert 已废弃,实际混音必须先确保所有输入流的 sample_rate、channel_layout、sample_fmt 完全一致,否则 swr_convert 会静默丢帧或输出乱码。常见错误是直接读取不同来源的 AAC/MP3 音轨(比如 44.1kHz 立体声 + 48kHz 5.1),不重采样就送入混音缓冲区——结果是音频撕裂或播放极短时间后卡死。
实操建议:
- 用
avcodec_parameters_copy拷贝参考流参数,再以该参数为模板初始化SwrContext - 对每条音轨调用
swr_init前,检查swr_is_initialized(ctx) == 0,避免重复 init 导致内存泄漏 - 重采样目标格式推荐:48000Hz、
AV_CH_LAYOUT_STEREO、AV_SAMPLE_FMT_FLTP(平面浮点,便于后续加法混音)
混音缓冲区要按 sample 对齐,不是 frame 对齐
多个音轨时间轴不同步时,不能简单按 AVFrame->nb_samples 逐帧相加。必须把所有音轨解码后的 PCM 数据重采样到同一时间基(例如都转成 1024 样本/包),再按样本点(sample)做浮点加法,否则会出现相位抵消或爆音。
关键点:
- 用
swr_convert输出固定out_nb_samples(如 1024),而非依赖输入帧大小 - 混音缓冲区分配为
float*[channels](平面格式),每个通道独立累加,避免交错格式下索引错位 - 加法后需做幅度钳制:
val = fmaxf(-1.0f, fminf(1.0f, val)),否则多轨叠加易溢出
时间戳同步靠 pts 而非 packet 顺序
不同音轨的 AVPacket 到达顺序不可靠,仅按解码顺序混音会导致音画不同步或音轨错位。必须用 AVFrame->pts 和 time_base 对齐到统一时间线。
做法:
- 维护一个全局混音时钟(单位:微秒),每次写入混音帧前计算其起始时间:
frame_pts_us = av_rescale_q(frame->pts, stream->time_base, AV_TIME_BASE_Q) - 若当前帧 pts 落在已混音区间内,跳过或裁剪;若落后太多(>100ms),补零填充空隙
- 绝对不要依赖
av_read_frame返回 packet 的先后顺序来推断播放顺序
输出编码需手动管理重采样上下文生命周期
混音完成后的 PCM 数据不能直接喂给编码器——编码器内部的 AVCodecContext 通常不支持平面浮点格式,且采样率可能与混音输出不一致。常见错误是复用解码用的 SwrContext,但未重设 out_sample_rate 导致编码失败(错误信息:Error while opening encoder: Invalid argument)。
正确流程:
- 为编码器单独建一个
SwrContext,输入格式 = 混音缓冲区格式,输出格式 =enc_ctx->sample_fmt+enc_ctx->sample_rate -
swr_convert输出的uint8_t**必须和enc_ctx->frame_size对齐(不足则补零,超长则分批) - 每次
avcodec_send_frame前,确认frame->nb_samples == enc_ctx->frame_size,否则编码器静默拒绝
最易被忽略的是:混音缓冲区的样本数未必整除编码器要求的 frame_size,必须缓存余数到下次处理——这个边界逻辑一旦漏掉,输出文件开头或结尾就会缺几毫秒音频。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











