avformat_write_header失败主因是未初始化输出格式上下文,需先调用avformat_alloc_output_context2并正确设置oformat、time_base、codecpar及disposition等参数,否则返回averror(einval)。

ffmpeg\_avformat\_write\_header失败:没初始化输出格式上下文
直接调用 ffmpeg_avformat_write_header() 失败,常见错误是返回负值(如 -22,即 AVERROR(EINVAL)),根本原因是没正确设置 AVFormatContext 的 oformat 字段或没分配流(AVStream)。MP4 封装要求严格的时间基(time_base)和编解码参数(codecpar)必须提前填好,不能只靠 AVCodecContext。
- 先用
av_guess_format("mp4", nullptr, "video/mp4")获取AVOutputFormat*,再avformat_alloc_output_context2(&ofmt_ctx, ofmt, "mp4", nullptr)分配上下文 - H.264 流必须设置
stream->time_base = AVRational{1, 1000}(或与帧率匹配,如{1, 25}),且stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO - AAC 流同理,但
time_base建议设为{1, 48000}(对应 48kHz 采样率),并确保codecpar->sample_rate、codecpar->channels、codecpar->format(如AV_SAMPLE_FMT_FLTP)已赋值 - 别漏掉
avformat_new_stream(ofmt_ctx, nullptr)创建流,且每个流的id要唯一(默认从 0 开始递增)
av\_interleaved\_write\_frame写入失败:DTS/PTS未按顺序或未重映射
封装 MP4 时,av_interleaved_write_frame() 报 AVERROR(EINVAL) 或卡住,大概率是音视频时间戳混乱。MP4 要求 DTS 严格递增,且音频 PTS 必须与视频 PTS 对齐(尤其首帧)。FFmpeg 不会自动帮你算 DTS,必须手动维护。
- 对每帧输入数据(
AVPacket),先用av_packet_rescale_ts(pkt, in_stream->time_base, out_stream->time_base)将时间戳从解码器时间基转为输出流时间基 - 视频帧 DTS/PTS 通常可直接用(前提是原始流时间基合理),但 AAC 音频常需重新生成:例如按固定采样数(如 1024 样本)计算间隔,
pkt->pts = pkt->dts = next_audio_pts; next_audio_pts += 1024;(单位为out_stream->time_base的分子) - 务必保证音视频 pkt 的
dts全局递增——可用一个全局int64_t last_dts = -1检查,避免因编码器乱序导致写入失败 - MP4 不接受负 DTS,首帧
dts必须 ≥ 0;若原始流有 negative dts,需整体偏移(pkt->dts -= min_dts)
avformat\_write\_trailer报错或文件损坏:没正确 flush 编码器缓存
调用 avformat_write_trailer() 后文件无法播放,或播放器提示“moov atom not found”,说明 MP4 的索引(moov)没写全。这往往是因为音频/视频编码器还有未输出的延迟帧(delayed frames)没被 avcodec_receive_packet() 取出,就直接关流了。
- 在结束前,对每个编码器(
AVCodecContext*)循环调用avcodec_send_frame(nullptr)+avcodec_receive_packet(&pkt),直到返回AVERROR(EAGAIN)或AVERROR_EOF - 每次收到 packet 后,仍需
av_packet_rescale_ts()和av_interleaved_write_frame()写入,否则这些帧丢失,moov 中缺少关键索引项 - 确保所有流都 flush 完毕后再调用
avformat_write_trailer();如果某流提前 close,avformat_write_trailer()可能静默失败 - 检查输出文件大小:正常 MP4 至少几百字节;若只有几十字节,基本是 moov 没写进去,回头查 flush 是否遗漏
AV\_STREAM\_INFO\_FLAG\_DEFAULT未设:MP4 播放器找不到主音轨/视频轨
生成的 MP4 文件在某些播放器(如 QuickTime、部分 Android 原生播放器)里无声或黑屏,但 ffplay 能播,问题常出在流标记缺失。MP4 规范依赖 AVStream->disposition 中的标志位来指定默认音轨/视频轨。
- 给视频流设置:
out_stream->disposition |= AV_DISPOSITION_DEFAULT; - 给音频流也设置:
out_stream->disposition |= AV_DISPOSITION_DEFAULT;(MP4 允许多个 default,播放器通常选第一个 video + 第一个 audio) - 如果音频有多个语言(如中/英),可额外加
AV_DISPOSITION_DUB或AV_DISPOSITION_VISUAL_IMPAIRED等,但至少一个要带DEFAULT - 这个字段必须在
avformat_write_header()之前设置,之后修改无效
MP4 封装真正麻烦的不是 API 调用顺序,而是时间基换算、DTS 保序、flush 完整性这三处细节——任意一处错,文件就可能半残。尤其注意 AAC 的 time_base 和 sample_rate 必须与 codecpar 一致,否则 avcodec_parameters_to_context() 会静默失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











