ffmpeg 的 api 和 数据结构都是 c 风格,当我在 c++ 中使用它们时,很自然就想到用智能指针去管理(例如 AVFormatContext*
、AVCodecContext*
等),因为可以自定义删除器,将 ffmpeg 提供的 free
操作放进去;但 ffmpeg 中的一些 api 需要传入裸指针,一些 api 甚至会在内部直接分配空间,这样子用智能指针管理的想法会不会是没有必要的?
拿 AVFormatContext
来举例,正常可以像这样得到一个被智能指针管理的 AVFormatContext
结构
auto deleter = [](AVFormatContext* f){ if(f) avformat_free_context(f);};std::unique_ptr<AVFormatContext, decltype(deleter)> fmt(avformat_alloc_context(), deleter);
但和它相关的一个 api 是 avformat_open_input
,它的函数声明如下(以下贴出一部分实现)
int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options); // demux.c 下 avformat_open_input 的一部分实现int avformat_open_input(AVFormatContext **ps, const char *filename, const AVInputFormat *fmt, AVDictionary **options){ ... AVFormatContext *s = *ps; ... if (!s && !(s = avformat_alloc_context())) return AVERROR(ENOMEM); ...}
可以看到 avformat_open_input
需要一个二级指针,所以需要直接传入裸指针。如果想要将一个初始化的 unique_ptr<AVFormatContext>
搭配 avformat_open_input
使用,就需要像这样(网上看到的做法)
auto deleter = [](AVFormatContext* f){ if(f) avformat_free_context(f);};std::unique_ptr<AVFormatContext, decltype(deleter)> fmt(avformat_alloc_context(), deleter);auto tmp = fmt.get();avformat_open_input(&tmp, ...);
到这里我就开始怀疑用 unique_ptr
管理 AVFormatContext
的意义了,不过以上这个例子还好,只是观感上没那么优雅。但以下的例子让我质疑用智能指针做管理的必要。
AVFormatContext
还有一个相关的 api 是 avformat_alloc_output_context2
,以下是函数声明和部分实现:
int avformat_alloc_output_context2(AVFormatContext **ctx, const AVOutputFormat *oformat, const char *format_name, const char *filename); int avformat_alloc_output_context2(AVFormatContext **avctx, const AVOutputFormat *oformat, const char *format, const char *filename){ AVFormatContext *s = avformat_alloc_context(); int ret = 0; *avctx = NULL; ... *avctx = s;}
可以看到,avformat_alloc_output_context2
同样需要传入二级指针,但与 avformat_open_input
的区别在于,它内部直接将 *avctx = NULL
,并没有判断其是否为空,同时还将分配了新的内存地址给 avctx
,这也就意味着以下的操作会造成内存泄漏:
auto deleter = [](AVFormatContext* f){ if(f) avformat_free_context(f);};std::unique_ptr<AVFormatContext, decltype(deleter)> fmt(avformat_alloc_context(), deleter);auto tmp = fmt.get();avformat_alloc_output_context2(&tmp, ...);
至此让我产生用智能指针管理 ffmpeg 数据结构的必要性,有没有大佬来解答一下。