必须先调用avformat_open_input打开媒体,再调用avformat_find_stream_info才能获取完整流级元数据(如分辨率、帧率),否则avstream中codecpar等关键字段为空;容器级元数据通过ctx->metadata字典遍历获取,注意键名大小写和格式差异。

如何用 avformat_open_input 读取视频元数据
直接调用 avformat_open_input 是获取元数据的第一步,但它本身不解析流信息——只打开文件并填充格式上下文的 iformat 和部分全局字段(如 duration、bit_rate)。常见错误是以为打开后就能立刻读到所有信息,结果 ctx->nb_streams 为 0 或 ctx->streams[i]->codecpar 为空。
必须紧接着调用 avformat_find_stream_info,否则大多数流级元数据(分辨率、帧率、编码格式)都不可用。这个函数会尝试解码若干包以推断参数,耗时取决于文件和关键帧分布。
- 传入
NULL作为options参数即可,除非你明确需要覆盖探测行为(比如强制指定fps_probe_size) - 检查返回值:负值表示失败,常见
-541478725(即AVERROR(EINVAL))通常因文件路径错误或不支持格式 - 对某些封装格式(如 MP4),即使不调用该函数,
avformat_open_input也可能填入部分信息,但不可依赖
AVFormatContext 里哪些字段算“元数据”
FFmpeg 的“元数据”分两类:容器级(format-level)和流级(stream-level)。前者存在 AVFormatContext::metadata 字典中,后者分散在每个 AVStream 的 codecpar 和 avg_frame_rate 等字段里。
容器级元数据如标题、作者、创建时间,需遍历 ctx->metadata 字典获取;流级元数据才是实际播放所需的硬信息,比如 H.264 视频流的宽高必须从 stream->codecpar->width 和 stream->codecpar->height 读,而不是 stream->codec->width(后者在未调用 avcodec_open2 前无效)。
-
ctx->duration单位是微秒,除以AV_TIME_BASE得秒数;若为AV_NOPTS_VALUE,说明容器未提供时长,需靠解析帧数+帧率估算 -
stream->r_frame_rate是理论帧率(如 30000/1001),stream->avg_frame_rate是实测平均值,二者可能不同 - 音频采样率来自
stream->codecpar->sample_rate,声道数来自stream->codecpar->channels
为什么 av_dict_get 找不到常见字段如 “title”
不是所有视频文件都嵌入了可读元数据,尤其手机录的 MP4 或网络下载的 MKV 经常为空。更隐蔽的问题是:FFmpeg 默认只解析顶层字典,而某些格式(如 MOV/MP4)把元数据放在私有 box 里,需启用 ffprobe 类似的解析逻辑——但在 C API 中,这由 avformat_open_input 内部处理,只要格式 demuxer 支持,就会填入 ctx->metadata。
真正容易漏掉的是大小写和键名变体:"TITLE"、"title"、"Title" 都可能出现;MP4 常用 "com.apple.quicktime.title" 这类 vendor-specific key。别硬编码查找 "title",应遍历整个字典:
AVDictionaryEntry *tag = NULL;
while ((tag = av_dict_get(ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
printf("%s=%s\n", tag->key, tag->value);
}
- 使用
AV_DICT_IGNORE_SUFFIX可匹配前缀(如查"date"能命中"DATE") - 某些字段(如
"rotate")是整数字符串,需atoi()转换,不是所有 demuxer 都输出它 - AVI 格式几乎不带标准元数据,别指望从
ctx->metadata里读到有用信息
性能与线程安全要注意什么
avformat_open_input 和 avformat_find_stream_info 都是阻塞调用,且后者在低码率或关键帧稀疏的视频里可能卡住几秒。不能在 UI 线程直接调用,尤其移动端。
FFmpeg 的 format context 和 stream 不是线程安全的:多个线程同时读同一个 AVFormatContext* 指针是危险的,哪怕只读元数据。如果要并发分析多个文件,必须为每个文件创建独立的 AVFormatContext 实例,并确保 avformat_close_input 成对调用。
- 调用
avformat_find_stream_info前可设ctx->probesize和ctx->max_analyze_duration限制探测深度,避免卡死 - 释放资源时顺序固定:
avformat_close_input(&ctx)会自动清理内部分配的 stream 和 metadata,无需手动av_dict_free - Windows 上若链接静态 FFmpeg 库,注意
avformat_open_input可能因缺少 DLL(如avcodec-60.dll)而返回AVERROR_UNKNOWN,而非格式不支持
实际解析时最麻烦的从来不是调用哪个函数,而是判断某个字段到底存不存在、单位对不对、要不要 fallback 到计算值——比如 duration 为空时得靠 stream->nb_frames * av_q2d(stream->r_frame_rate) 估算,而这又依赖 nb_frames 是否被正确探测到。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











