在写这个播放器的时候,遇到了一些内存管理的问题,虽然棘手但是也让我对此有了比较完善的理解,而且很多相关资料并没有跟随FFmpeg的更新,比如缓冲池AVBufferPool
的使用。
使用ffmpeg版本是3.4
AVFrame和AVPacket的内存管理策略
对AVFrame:
av_frame_alloc
只是给AVFrame
分配了内存,它内部的buf还是空的,就相当于造了一个箱子,但箱子里是空的。av_frame_ref
对src的buf增加一个引用,即使用同一个数据,只是这个数据引用计数+1.av_frame_unref
把自身对buf的引用释放掉,数据的引用计数-1。av_frame_free
内部还是调用了unref,只是把传入的frame也置空。
发现还缺了一个buffer初始化的方法,初始化就在解码函数avcodec_send_packet
和avcodec_receive_frame
内部。
然后对于解码有个坑,对avcodec_receive_frame
函数:
Note that the function will always call av_frame_unref(frame)
before doing anything else.
如果你使用同一个frame,每次去接收解码后的数据,那么每次传进去就会把前面的数据释放掉,导致就只有一个frame是有用的。
如果你觉得frame的alloc花费很大,想节省资源,然后又没注意到这个注释的话,很可能就会这么做。
对此有两种方案:
- 继续只使用一个frame来接收,但是在传递给下一步(渲染、播放等)的时候,下一步的模块使用一个新的frame和
av_frame_ref
来接收,而不是直接的赋值。 - 每次解码前构建一个新的AVFrame,把它传给
avcodec_receive_frame
,这样每次都是新的frame,互不干扰。但是在整个流程结束时,要释放这个frame.
方便来说,是第二种方案好;但从模块化角度说,是第一种的更好&