5
votes

The libavcodec documentation is not very specific about when to free allocated data and how to free it. After reading through documentation and examples, I've put together the sample program below. There are some specific questions inlined in the source but my general question is, am I freeing all memory properly in the code below? I realize the program below doesn't do any cleanup after errors -- the focus is on final cleanup.

The testfile() function is the one in question.

extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
}

#include <cstdio>

using namespace std;


void AVFAIL (int code, const char *what) {
    char msg[500];
    av_strerror(code, msg, sizeof(msg));
    fprintf(stderr, "failed: %s\nerror: %s\n", what, msg);
    exit(2);
}

#define AVCHECK(f) do { int e = (f); if (e < 0) AVFAIL(e, #f); } while (0)
#define AVCHECKPTR(p,f) do { p = (f); if (!p) AVFAIL(AVERROR_UNKNOWN, #f); } while (0)


void testfile (const char *filename) {

    AVFormatContext *format;
    unsigned streamIndex;
    AVStream *stream = NULL;
    AVCodec *codec;
    SwsContext *sws;
    AVPacket packet;
    AVFrame *rawframe;
    AVFrame *rgbframe;
    unsigned char *rgbdata;

    av_register_all();

    // load file header
    AVCHECK(av_open_input_file(&format, filename, NULL, 0, NULL));
    AVCHECK(av_find_stream_info(format));

    // find video stream
    for (streamIndex = 0; streamIndex < format->nb_streams && !stream; ++ streamIndex)
        if (format->streams[streamIndex]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
            stream = format->streams[streamIndex];
    if (!stream) {
        fprintf(stderr, "no video stream\n");
        exit(2);
    }

    // initialize codec
    AVCHECKPTR(codec, avcodec_find_decoder(stream->codec->codec_id));
    AVCHECK(avcodec_open(stream->codec, codec));
    int width = stream->codec->width;
    int height = stream->codec->height;

    // initialize frame buffers
    int rgbbytes = avpicture_get_size(PIX_FMT_RGB24, width, height);
    AVCHECKPTR(rawframe, avcodec_alloc_frame());
    AVCHECKPTR(rgbframe, avcodec_alloc_frame());
    AVCHECKPTR(rgbdata, (unsigned char *)av_mallocz(rgbbytes));
    AVCHECK(avpicture_fill((AVPicture *)rgbframe, rgbdata, PIX_FMT_RGB24, width, height));

    // initialize sws (for conversion to rgb24)
    AVCHECKPTR(sws, sws_getContext(width, height, stream->codec->pix_fmt, width, height, PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL));

    // read all frames fromfile
    while (av_read_frame(format, &packet) >= 0) {       

        int frameok = 0;
        if (packet.stream_index == (int)streamIndex)
            AVCHECK(avcodec_decode_video2(stream->codec, rawframe, &frameok, &packet));

        av_free_packet(&packet); // Q: is this necessary or will next av_read_frame take care of it?

        if (frameok) {
            sws_scale(sws, rawframe->data, rawframe->linesize, 0, height, rgbframe->data, rgbframe->linesize);
            // would process rgbframe here
        }

        // Q: is there anything i need to free here?

    }

    // CLEANUP: Q: am i missing anything / doing anything unnecessary?
    av_free(sws); // Q: is av_free all i need here?
    av_free_packet(&packet); // Q: is this necessary (av_read_frame has returned < 0)?
    av_free(rgbframe);
    av_free(rgbdata); 
    av_free(rawframe); // Q: i can just do this once at end, instead of in loop above, right?
    avcodec_close(stream->codec); // Q: do i need av_free(codec)?
    av_close_input_file(format); // Q: do i need av_free(format)?

}


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

    if (argc != 2) {
        fprintf(stderr, "usage: %s filename\n", argv[0]);
        return 1;
    }

    testfile(argv[1]);

}

Specific questions:

  1. Is there anything I need to free in the frame processing loop; or will libav take care of memory management there for me?
  2. Is av_free the correct way to free an SwsContext?
  3. The frame loop exits when av_read_frame returns < 0. In that case, do I still need to av_free_packet when it's done?
  4. Do I need to call av_free_packet every time through the loop or will av_read_frame free/reuse the old AVPacket automatically?
  5. I can just av_free the AVFrames at the end of the loop instead of reallocating them each time through, correct? It seems to be working fine, but I'd like to confirm that it's working because it's supposed to, rather than by luck.
  6. Do I need to av_free(codec) the AVCodec or do anything else after avcodec_close on the AVCodecContext?
  7. Do I need to av_free(format) the AVFormatContext or do anything else after av_close_input_file?

I also realize that some of these functions are deprecated in current versions of libav. For reasons that are not relevant here, I have to use them.

1

1 Answers

6
votes

Those functions are not just deprecated, they've been removed some time ago. So you should really consider upgrading.

Anyway, as for your questions:

1) no, nothing more to free

2) no, use sws_freeContext()

3) no, if av_read_frame() returns an error then the packet does not contain any valid data

4) yes you have to free the packet after you're done with it and before next av_read_frame() call

5) yes, it's perfectly valid

6) no, the codec context itself is allocated by libavformat so av_close_input_file() is responsible for freeing it. So nothing more for you to do.

7) no, av_close_input_file() frees the format context so there should be nothing more for you to do.