读取图像文件时FFmpeg泄漏

时间:2016-09-16 17:04:33

标签: memory-leaks ffmpeg libavcodec libavformat

使用最近版本的FFmpeg读取图像文件时,我遇到内存泄漏,我无法追踪。

似乎在使用AVFrameavcodec_send_packet填充avcodec_receive_frame之后,我对av_frame_free的调用实际上并没有释放AVBuffer对象与框架。我唯一没有解放的是AVCodecContext。如果我试着这样做,我就会崩溃。

我已经创建了这个示例程序,它就像我能得到它一样简单。这将保持打开,读取然后在循环中关闭相同的图像文件。在我的系统上,这会以惊人的速度泄漏内存。

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

int main(int argc, char **argv) {
    av_register_all();

    while(1) {
        AVFormatContext *fmtCtx = NULL;

        if (avformat_open_input(&fmtCtx, "/path/to/test.jpg", NULL, NULL) == 0) {
            if (avformat_find_stream_info(fmtCtx, NULL) >= 0) {
                for (unsigned int i = 0u; i < fmtCtx -> nb_streams; ++i) {
                    AVStream *stream = fmtCtx -> streams[i];
                    AVCodecContext *codecCtx = stream -> codec;
                    AVCodec *codec = avcodec_find_decoder(codecCtx -> codec_id);

                    if (avcodec_open2(codecCtx, codec, NULL) == 0) {
                        AVPacket packet;

                        if (av_read_frame(fmtCtx, &packet) >= 0) {
                            if (avcodec_send_packet(codecCtx, &packet) == 0) {
                                AVFrame *frame = av_frame_alloc();

                                avcodec_receive_frame(codecCtx, frame);
                                av_frame_free(&frame);
                            }
                        }

                        av_packet_unref(&packet);
                    }
                }
            }

            avformat_close_input(&fmtCtx);
        }
    }

    return 0;
}

1 个答案:

答案 0 :(得分:1)

解决方案是创建在文件打开时自动创建的AVCodecContext的副本,并在avcodec_open2中使用此副本。这允许使用avcodec_free_context删除此副本。

对于FFmpeg的最新版本,avcodec_copy_context已被弃用并替换为AVCodecParameters。使用问题示例程序中的以下片段插入泄漏:

AVCodecParameters *param = avcodec_parameters_alloc();
AVCodecContext *codecCtx = avcodec_alloc_context3(NULL);
AVCodec *codec = avcodec_find_decoder(stream -> codec -> codec_id);

avcodec_parameters_from_context(param, stream -> codec);
avcodec_parameters_to_context(codecCtx, param);
avcodec_parameters_free(&param);
[...]
avcodec_free_context(&codecCtx);