直接用avio_open读内存会失败,因它仅支持文件路径或URL协议,将内存地址误作路径导致报错;正确做法是构建自定义AVIOContext并设置read_packet回调,再通过avformat_open_input传入。

为什么直接用 avio_open 读内存会失败
FFmpeg 默认的 avio_open 只支持文件路径或 URL 协议(如 file://、http://),不识别纯内存地址。你传一个 uint8_t* 进去,它会当成路径字符串去 fopen,自然报错 Unable to open input 或直接崩溃。
真正要让 FFmpeg 从内存读数据,必须绕过默认 IO 层,手动构造一个 AVIOContext,并绑定自定义的读/写回调函数——也就是所谓“自定义 AVIOContext”。
怎么写一个最小可用的内存读取 AVIOContext
核心是三件事:准备缓冲区、实现 read_packet 回调、调用 avio_open2(注意不是 avio_open)传入 NULL URL 和自定义协议。
-
AVIOContext本身不能直接 new,必须用avio_open2或avio_open_dir(后者不适用),但传NULL作为 URL,并在AVIOInterruptCB和AVDictionary*参数中留空,再靠avio_open2内部用你提供的 buffer 初始化 - 更可靠的做法是:用
avio_context_alloc+avio_open_dyn_buf配合avio_close_dyn_buf做写;读则用avio_open2+ 自定义AVIOContext的方式 - 读回调函数签名必须是:
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),返回实际读取字节数,到末尾返回 0,出错返回负的 AVERROR 值(如AVERROR(EIO)) - 别忘了在
AVInputFormat打开前,用avformat_open_input的第四个参数传入你构造好的AVIOContext*,否则 FFmpeg 还是走默认文件打开逻辑
示例关键片段:
立即学习“C++免费学习笔记(深入)”;
static int mem_read(void *opaque, uint8_t *buf, int buf_size) {
uint8_t **pp = (uint8_t**)opaque;
uint8_t *p = *pp;
int len = min(buf_size, (int)(mem_end - p));
if (len <= 0) return 0;
memcpy(buf, p, len);
*pp = p + len;
return len;
}
<p>// 使用时:
uint8_t <em>mem_data = ...; // 你的内存起始地址
uint8_t </em>mem_ptr = mem_data;
AVIOContext *pb = avio_open2(&mem_ptr, "", AVIO_FLAG_READ, nullptr, nullptr, nullptr);
// 注意:上面这行其实不标准,正确做法是 avio_open2 第二个参数传 NULL,第三个参数传 AVIO_FLAG_READ,再通过 avio_open2 的 options 参数控制——但实际最稳的是手动 avio_context_alloc + 设置 read_packet</p>
AVIOContext 读写共用时要注意缓冲区所有权
FFmpeg 不管理你传进去的内存生命周期,opaque 指针只是透传,不会被拷贝或释放。这意味着:
- 如果你把栈变量地址传给
opaque(比如局部uint8_t buf[1024]),回调执行时该变量可能已销毁,导致野指针读取 - 写场景下,用
avio_open_dyn_buf分配的 buffer 必须用avio_close_dyn_buf获取并自行av_free,否则内存泄漏 - 读场景下,如果数据是临时分配的(比如网络收到的一帧),确保整个解码周期内该内存不被释放——常见错误是回调还在跑,外面已经
free了原始 buffer -
seek回调不是必须实现,但如果格式需要随机访问(如 MP4),不实现会导致avformat_find_stream_info卡住或失败;简单实现可只支持SEEK_SET,返回当前偏移
常见错误现象和对应检查点
调试时遇到这些表现,基本就是 AVIOContext 配置没到位:
- 报错
Invalid data found when processing input:大概率是read_packet返回了负值(比如 -1),但没映射成AVERROR,FFmpeg 当成有效数据解析了 -
avformat_find_stream_info卡住或超时:没实现seek回调,且容器格式依赖 seek(如 MP4、MKV);或read_packet在 EOF 后仍返回正数 - 解码出乱码/花屏:内存数据被提前覆盖或读越界,检查
mem_end边界是否传准,以及read_packet是否严格按buf_size限制拷贝 - 程序崩溃在
avio_read内部:AVIOContext的buffer字段为 NULL 或未对齐,FFmpeg 要求 buffer 地址按 32 字节对齐(可用av_malloc分配)
最易忽略的是:哪怕只读不写,也得确保 AVIOContext->write_packet 设为 nullptr,否则某些封装器会误调用它;同理,只写不读也要清空 read_packet 并设 seekable = 0。


















