【发现一个问题】ffmpeg c api:从内存打开一个mp4文件的时候,没法不拷贝
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
我使用如下的方法,从内存中打开一个已经加载好的 mp4 文件:
avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, 0,
inst, read_packet, NULL, seek);
fmt_ctx = avformat_alloc_context();
fmt_ctx->pb = avio_ctx;
其中,read_packet 实现了一个回调函数,函数中使用 memcpy() 把 mp4 的数据块,拷贝到 avio_ctx 内部的缓冲区。
明显的问题是:既然 mp4 文件已经在内存中,为什么不能直接用指针指向这片数据,从而避免拷贝。
于是我把上述的一段代码修改为:
avio_ctx = avio_alloc_context(data, data_size, 0, NULL, NULL, NULL, NULL);
运行时出现错误:
test_each_frame_to_jpg_bin(32498,0x207e03ac0) malloc: *** error for object 0x108e40000: pointer being freed was not allocated
test_each_frame_to_jpg_bin(32498,0x207e03ac0) malloc: *** set a breakpoint in malloc_error_break to debug
通过调试器跟踪,发现了问题所在:
//libavformat/aviobuf.c
int ffio_rewind_with_probe_data(AVIOContext *s, unsigned char **bufp, int buf_size)
{
// ....
av_free(s->buffer); // 第一次解析 mp4 的格式结束后,这里会释放缓冲区。而 mp4 文件的内存数据使用了 mmap,导致无法释放。
s->buf_ptr = s->buffer = buf;
s->buffer_size = alloc_size;
s->pos = buf_size;
s->buf_end = s->buf_ptr + buf_size;
s->eof_reached = 0;
return 0;
}
由此可见,ffmpeg c api 的流程设计上,是不允许不拷贝的。
后面我会考虑直接解析mp4,绕过 ffmpeg 的 api.

浙公网安备 33010602011771号