avformat_open_input是读取mp4元数据最可靠方式,它完整处理moov box嵌套、字节序、碎片化等复杂细节,支持所有mp4变体,无需手动解析二进制结构。

用 FFmpeg 的 avformat_open_input 读取 MP4 元数据最可靠
MP4 文件的 metadata(如时长、编码格式、分辨率、创建时间)并不全在文件头,而是分散在 moov box 及其子 box(mvhd, trak, mdhd, udta 等)中。直接解析二进制结构极易出错——box 嵌套、大小字段字节序、可选字段缺失、碎片化 moof + mdat 都会让手写 parser 快速失效。FFmpeg 的 avformat_open_input 已完整处理这些细节,且支持所有常见 MP4 变体(包括 QuickTime 兼容格式、ISO Base Media v2)。不要自己解析 ftyp 或 mdat 开头字节。
- 调用前必须先
avformat_network_init()(即使不联网,部分 demuxer 内部会检查) -
avformat_open_input成功后,AVFormatContext->duration是微秒级总时长(可能为AV_NOPTS_VALUE,需 fallback 到stream->duration * time_base) - 视频流信息藏在
AVFormatContext->streams[i]中:codecpar->width/height是解码后尺寸,codecpar->codec_type == AVMEDIA_TYPE_VIDEO才是视频流 - 用户自定义元数据(如
©nam,©day)在AVFormatContext->metadata字典里,用av_dict_get(fmt_ctx->metadata, "title", nullptr, AV_DICT_MATCH_CASE)取
提取帧率和关键帧间隔不能只看 AVStream->r_frame_rate
r_frame_rate 是容器声称的“推荐帧率”,但 MP4 中它常被设为 0/0 或错误值(尤其由手机录制的文件)。真实帧率得结合 time_base 和 avg_frame_rate 推导,而关键帧(I-frame)间隔需扫描 AVPacket->flags & AV_PKT_FLAG_KEY。
- 优先用
av_q2d(stream->avg_frame_rate),若为 0.0,则用1.0 / av_q2d(stream->time_base)估算(仅当codecpar->field_order == AV_FIELD_PROGRESSIVE时合理) - MP4 的
sttsbox 存着每组连续帧的时长,但 FFmpeg 不暴露原始 stts 表;想精确计算 GOP 长度,必须解码或至少调用av_read_frame并检查 flag - 注意:
AVStream->nb_frames在 MP4 中几乎总是 0,因为容器不强制存储总帧数
遇到 Invalid data found when processing input 错误先检查文件路径和权限
这个错误看似是格式问题,但在 Linux/macOS 下更常因路径含中文、空格未转义,或文件被其他进程(如视频播放器、云同步工具)独占锁住导致。FFmpeg 的 MP4 demuxer 对损坏容忍度其实很高,真正解析失败前通常已卡在 open 阶段。
- 用
stat <code>your_file.mp4确认文件大小非 0 且可读 - 临时复制文件到
/tmp/test.mp4再试,排除路径字符或挂载选项干扰 - 若仍报错,用
ffprobe -v error -show_entries format=filename,duration -of default <code>file.mp4验证 FFmpeg 命令行能否读取——如果命令行也失败,大概率是文件真损坏或加密(如某些 DRM 包裹的 MP4) - C++ 中传入
avformat_open_input的路径指针必须是 C 风格字符串(std::string.c_str()),不能是临时std::string对象的引用,否则指针悬空
想绕过 FFmpeg 用纯 C++ 解析?libmp4v2 已停更,mp4parse-capi 是更安全的选择
如果你的场景严禁动态链接(如嵌入式)、或需要极小体积(mp4parse-capi(Rust 实现,C ABI 封装),它专为安全解析设计,明确拒绝模糊/歧义 box 结构,且有 fuzz 测试保障。
- 它只解析结构,不处理音视频解码,因此无 codec 依赖,头文件仅
mp4parse.h - 核心函数是
mp4parse_new+mp4parse_read,返回mp4parse_status枚举,错误码比 FFmpeg 更细粒度(如MP4PARSE_STATUS_INVALIDvsMP4PARSE_STATUS_EOF) - 视频轨道信息在
mp4parse_track_info结构体中:video.width/video.height直接可用,但时长需用track.duration除以track.timescale手动算 - 注意:它不解析
udta中的 ID3 或 iTunes 风格元数据,这部分仍需 FFmpeg 或额外解析逻辑
MP4 的 metadata 提取难点不在“怎么读”,而在“读到哪算准”——moov 可能位于文件末尾(需 seek)、mvhd 的 duration 字段是按 timescale 计的整数,而实际播放时长受 B-frame 顺序影响。别迷信单个字段,交叉验证才是常态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











