Соберите AVFrames в буфер - PullRequest
       17

Соберите AVFrames в буфер

1 голос
/ 03 апреля 2020

Я собираю AVFrames в массив и затем освобождаю их, но это вызывает утечку памяти.

extern "C" {
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
}

#include <vector>
#include <iostream>

AVFrame * createFrame() {
    int width = 1280;
    int height = 720;
    AVPixelFormat format = AV_PIX_FMT_YUV420P;
    int buffer_size = av_image_get_buffer_size(format, width, height, 1);
    uint8_t * buffer = (uint8_t *)av_malloc(buffer_size * sizeof(uint8_t));
    memset(buffer, 1, buffer_size);

    uint8_t *src_buf[4];
    int      src_linesize[4];
    av_image_fill_arrays(src_buf, src_linesize, buffer, format, width, height, 1);

    AVFrame * frame = av_frame_alloc();
    frame->width = width;
    frame->height = height;
    frame->format = format;
    av_frame_get_buffer(frame, 0);
    av_image_copy(frame->data, frame->linesize,
                  const_cast<const uint8_t**>(src_buf), const_cast<const int*>(src_linesize),
                  format, width, height);
    av_free(buffer);
    return frame;
}

int main(int argc, char *argv[]) {
    uint32_t count = 1024;

    // fill array with frames
    std::vector<AVFrame*> list;
    for (uint64_t i = 0; i < count; ++i) {
        list.push_back(createFrame());
    }
    // allocated 1385 mb in heap

    // clear all allocated data
    for (auto i = list.begin(); i < list.end(); ++i) {
        if (*i != NULL) {
            av_frame_free(&(*i));
        }
    }
    list.clear();

    // memory-leak of > 360 Mb
}

Но если просто создать кадр и сразу же освободить его, не сохраняя его в вектор, утечки памяти, несмотря на факт, что было создано такое же количество кадров.

Что я делаю не так?

ОБНОВЛЕНИЕ:

Я был не прав. Здесь нет утечки памяти (проверено valgrind), но освобожденная память не сразу возвращается в операционную систему, это меня смутило.

1 Ответ

0 голосов
/ 04 апреля 2020

Вы можете напрямую использовать av_image_fill_arrays для недавно выделенных AVFrame, например, так:

av_image_fill_arrays(frame->data,       /* destination */
                     frame->linesize,   /* destination */
                     buffer,            /* source      */
                     format,            /* source      */
                     width,             /* source & alingment */
                     height, 1);

Избавьтесь от ненужного кода, описанного выше, например, от ручного копирования буфера, и не используйте av_free(buffer); в createFrame или. Функция av_image_fill_arrays не выделяет буфер. Просто использует существующий; av_frame_free in main() позаботится об освобождении.

Вот некоторая документация:

av_image_fill_arrays

Настройка указателей данных и размеры линий на основе указанных параметров изображения и предоставленного массива.

Поля данного изображения заполняются с использованием адреса sr c, который указывает на буфер данных изображения. В зависимости от указанного формата пикселей будут установлены один или несколько указателей на данные изображения и размеры линий. Если задан плоский формат, будет установлено несколько указателей, указывающих на разные плоскости изображения, а размеры линий разных плоскостей будут сохранены в массиве lines_sizes. Вызовите с помощью sr c == NULL, чтобы получить требуемый размер для буфера sr c.

Чтобы выделить буфер и заполнить dst_data и dst_linesize за один вызов, используйте av_image_allo c () .

Надеюсь, это поможет.

...