2013-08-02 6 views
4

Документация libavcodec не очень специфична в том, когда нужно выделять выделенные данные и как их освобождать. После прочтения документации и примеров я собрал образец программы ниже. В источнике есть некоторые конкретные вопросы, но мой общий вопрос: я освобождаю всю память правильно в коде ниже? Я понимаю, что нижеприведенная программа не выполняет никакой очистки после ошибок - основное внимание уделяется окончательной очистке.ffmpeg/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. Что мне нужно освободить в цикле обработки кадра; или ливав позаботится об управлении памятью для меня?
  2. Действительно ли av_free - правильный способ бесплатно SwsContext?
  3. Кадр цикла выходит, когда av_read_frame возвращает < 0. В этом случае мне все еще нужно av_free_packet, когда все будет готово?
  4. Нужно ли мне звонить av_free_packet каждый раз через цикл или будет av_read_frame бесплатно или повторно использовать старый AVPacket?
  5. Я могу просто av_freeAVFrame s в конце цикла вместо того, чтобы перераспределять их каждый раз через, правильно? Кажется, он работает нормально, но я хотел бы подтвердить, что он работает, потому что он должен, а не удачей.
  6. Нужно ли av_free(codec)AVCodec или сделать что-нибудь еще после avcodec_close на AVCodecContext?
  7. Нужно ли av_free(format)AVFormatContext или сделать что-нибудь еще после av_close_input_file?

Я также понимаю, что некоторые из этих функций устарели в текущих версиях libav. По причинам, которые здесь не актуальны, я должен их использовать.

ответ

6

Эти функции не просто устарели, они были удалены некоторое время назад. Поэтому вам стоит подумать об обновлении.

Во всяком случае, так как для ваших вопросов:

1) нет, больше ничего, чтобы освободить

2) нет, используйте

3) нет, если av_read_frame() возвращает ошибку, то пакет делает не содержат каких-либо достоверных данных

4) да, вы должны освободить пакет после того, как вы сделали с ним и до следующего av_read_frame() вызова

5) да, это вполне допустимо

6) нет, контекст кодека сам выделяется libavformat так av_close_input_file() является ответственность за освобождение его. Так что вам больше нечего делать.

7) no, av_close_input_file() освобождает контекст формата, поэтому вам больше нечего делать.

+0

Отлично, спасибо за ваше время. Мне бы хотелось обновиться, но последняя версия недоступна на платформе, на которой я развиваюсь, и создание из источника, к сожалению, сложно на этой платформе. Еще раз спасибо! –

+0

Спасибо за разъяснение. – hyperspasm