Search code examples
memory-leaksffmpeglibavcodeclibavformat

FFmpeg leak while reading image files


While reading image files using a recent version of FFmpeg I'm encountering a memory leak I'm having trouble tracking down.

It seems that after filling the AVFrame with avcodec_send_packet and avcodec_receive_frame, my call to av_frame_free is not actually deallocating the AVBuffer objects withing the frame. The only thing I'm not freeing is the AVCodecContext. If I try to do that, I get a crash.

I've created this sample program, it is about as simple as I can get it. This will keep opening, reading and then closing the same image file in a loop. On my system this leaks memory at an alarming rate.

#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;
}

Solution

  • The solution is to create a copy of the AVCodecContext that was automatically created when the file was opened and use this copy in avcodec_open2. This allows for this copy to be deleted with avcodec_free_context.

    With recent versions of FFmpeg, avcodec_copy_context has been deprecated and replaced with AVCodecParameters. Using the following snippet in the sample program from the question plugs the leak:

    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);