[Libav-user] Memory leak reading videos

Matheus Henrique Klem Galvez mhkgalvez at gmail.com
Tue Jun 4 17:41:29 CEST 2013


Hi all,

I am developing a C++ class that stands between two media libraries, namely
OpenCV and the very ffmpeg. The aim is simple: to read uncompressed .avi
videos with ffmpeg and send frames to OpenCV format in order that OpenCV
might be able to process these frames.

The reason why I am doing such a class rather than doing everything using
OpenCV is that there is a bug with OpenCV still unresolved (as the best of
my knowledge tells me). This bug unfortunately makes the application using
OpenCV crash when trying to read an uncompressed video like those I have to
read.

So, I learned the basics of ffmpeg and was able to develop, compile and run
an application that reads these videos and saves the frames into hard disk,
if I want.  The question is that I tested my functions in a loop and
figured out that there is a huge leak of memory: the memory space allocated
increases very fast.

The structure of the code inside the loop is that:

1) Open file and initialize ffmpeg structures and variables
2) Read 10 frames from the file
3) Close file and release ffmpeg structures and variables

I developed Open() and Close() functions specially to avoid memory
accumulation but for some reason I am not being able to release properly
all ffmpeg resources. I tested the loop without Open() and Close() and it
works properly, so the leak is inside these functions and not inside
reading routine.

Here follows my Open() and Close() routines:

Notice: you will not see the function av_register_all() in my open() code.
It is called inside the class constructor.

Open():

void VideoInterface::open(string filePath) {
    // Check if it is already open
    if (openSuccess) {
        throw GeneralException("There is an already open video in this
interface.");
    }

    // Open video file
    if (avformat_open_input(&formatCtx, filePath.c_str(), NULL, NULL) != 0)
 {
        throw OpenVideoException("Video could not be open.");
    }

    //Retrieve stream information
    if (avformat_find_stream_info(formatCtx, NULL) < 0) {
        throw OpenVideoException("Could not ind stream information for the
given video.");
    }

    // Find first video stream
    vStreamIndex = -1;
    for (int i = 0; i < formatCtx->nb_streams; ++i) {
        if (formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
            vStreamIndex = i;
            break;
        }
    }
    if (vStreamIndex == -1) {
        throw OpenVideoException("Could not find a video stream.");
    }

    // Get a pointer to the codec context for the video stream
    codecCtx = formatCtx->streams[vStreamIndex]->codec;

    /*------------------------------*/
    //Grabbing useful information
    double duration = ((double) formatCtx->duration)/AV_TIME_BASE;
    double fps = 1/av_q2d(codecCtx->time_base);
    int frameCount = duration * fps;
    /*cout << "Numerator:\t" << codecCtx->time_base.num << endl;
    cout << "Denominator:\t" << codecCtx->time_base.den << endl;
    cout << "FPS:\t\t" << fps << endl;
    cout << "Duration:\t" << duration << " secs." << endl;
    cout << "Frame count:\t" << frameCount  << endl;*/

    // Fill VideoInformation structure
    vinfo->duration = duration;
    vinfo->fps = fps;
    vinfo->frameCount = frameCount;
    /*------------------------------*/

    // Find the decoder for the video stream
    codec = avcodec_find_decoder(codecCtx->codec_id);
    if (codec == NULL) {
        throw OpenVideoException("Unsuported codec!");
    }

    // Open codec
    AVDictionary *options = NULL;
    if (avcodec_open2(codecCtx, codec, &options) < 0) {
        throw OpenVideoException("Could not open codec!");
    }

    /*------- Prepare interface for first reading -------*/

    // Allocate an AVFrame structure
    frame = avcodec_alloc_frame();
    frameRGB = avcodec_alloc_frame();
    if (frameRGB == NULL or frame == NULL) {
        throw OpenVideoException("Not able to allocate frame space.");
    }

    // Determine required buffer size and allocate buffer
    int numBytes = avpicture_get_size(PIX_FMT_RGB24, codecCtx->width,
codecCtx->height);
    rawData = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));

    sws_ctx = sws_getContext(codecCtx->width, codecCtx->height,
            codecCtx->pix_fmt, codecCtx->width, codecCtx->height,
PIX_FMT_RGB24,
            SWS_BILINEAR, NULL, NULL, NULL);

    // Assign appropriate parts of buffer to image planes in pFrameRGB
    // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
    // of AVPicture
    avpicture_fill((AVPicture*) frameRGB, rawData, PIX_FMT_RGB24,
            codecCtx->width, codecCtx->height);

    openSuccess = true;
}

Close():

void VideoInterface::close() {
    // Free buffer
    av_free(rawData);

    // Free the RGB image
    av_free(frameRGB);

    // Free the YUV frame
    av_free(frame);

    // Free packet
    av_free_packet(&packet);

    // Close Codec context
    avcodec_close(codecCtx);

    // Close Format context
    avformat_close_input(&formatCtx);

    // Reinit class variables (not ffmpeg at all, and not any dynamically
allocate memory as well)
    init();
}

One possible reason for my problem is that I found out that
avcodec_close(AvCodecContext*) only frees AVCodecContext content, and not
the variable itself. After it I tried to call av_free(codecCtx) but it
generated an error. So, a first approach would be: how can one completely
release AVCodecContext variables?

Thank you all!

-- 
--
Matheus Henrique Klem Galvez
The Catholic University of America, Washington, DC
Universidade Federal do Rio de Janeiro, Rio de Janeiro, Brasil
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130604/f72aaab2/attachment.html>


More information about the Libav-user mailing list