ffmpeg / libavcodec内存管理

时间:2013-08-02 19:32:43

标签: memory-leaks ffmpeg libavcodec libav libavformat

libavcodec文档对于何时释放已分配的数据以及如何释放它并不十分具体。阅读完文档和示例后,我将下面的示例程序放在一起。在源代码中有一些特定的问题,但我的一般问题是,我是否在下面的代码中正确释放所有内存?我意识到下面的程序在发生错误后没有进行任何清理 - 重点是最终清理。

testfile()函数是有问题的。

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

}

具体问题:

  1. 在帧处理循环中是否需要释放任何内容;或者libav会为我处理内存管理吗?
  2. av_free是否正确释放SwsContext
  3. av_read_frame返回时,帧循环退出&lt; 0.在这种情况下,完成后我还需要av_free_packet吗?
  4. 我是否需要每次循环调用av_free_packetav_read_frame自动释放/重复使用旧版AVPacket
  5. 我可以在循环结束时av_free AVFrame而不是每次都重新分配它们,对吗?它似乎工作正常,但我想确认它是否有效,因为它应该是,而不是运气。
  6. 我需要av_free(codec) AVCodecavcodec_close AVCodecContext之后做其他事吗?
  7. 我需要av_free(format) AVFormatContext或在av_close_input_file后做其他事吗?
  8. 我也意识到在当前版本的libav中不推荐使用其中一些功能。由于这里不相关的原因,我必须使用它们。

1 个答案:

答案 0 :(得分:6)

这些功能不仅被弃用,它们已经被删除了一段时间。所以你应该考虑升级。

无论如何,关于你的问题:

1)不,没有更多的免费

2)不,使用sws_freeContext()

3)否,如果av_read_frame()返回错误,则数据包不包含任何有效数据

4)是的,你必须在完成后将数据包释放,然后 下一次av_read_frame()调用

5)是的,这是完全有效的

6)不,编解码器上下文本身由libavformat分配,因此av_close_input_file()是 负责解放它。所以你不能再做了。

7)不,av_close_input_file()释放格式上下文,所以你不应该再做任何事了。