Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ffmpeg/libavcodec memory management

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.

like image 275
Jason C Avatar asked Aug 02 '13 19:08

Jason C


People also ask

How to enable hardware decoders in FFmpeg?

Also hardware decoders will not apply left/top Cropping. Decoders are configured elements in FFmpeg which allow the decoding of multimedia streams. When you configure your FFmpeg build, all the supported native decoders are enabled by default. Decoders requiring an external library must be enabled manually via the corresponding --enable-lib option.

What is the libavcodec library?

The libavcodec library provides a generic encoding/decoding framework and contains multiple decoders and encoders for audio, video and subtitle streams, and several bitstream filters.

Which options are supported by FFmpeg’s FLAC encoder?

The following options are supported by FFmpeg’s flac encoder. Sets the compression level, which chooses defaults for many other options if they are not set explicitly. Valid values are from 0 to 12, 5 is the default.

How do I decode AMR-NB without the FFmpeg library?

An FFmpeg native decoder for AMR-NB exists, so users can decode AMR-NB without this library. libopencore-amrwb decoder wrapper. libopencore-amrwb allows libavcodec to decode the Adaptive Multi-Rate Wideband audio codec. Using it requires the presence of the libopencore-amrwb headers and library during configuration.


1 Answers

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.

like image 168
Anton Khirnov Avatar answered Oct 01 '22 13:10

Anton Khirnov