2016-02-23 8 views
0

Я заполняю Frame с изображением BGR для кодирования, и я получаю утечку памяти. Я думаю, что я попал в источник проблемы, но, похоже, это проблема с библиотекой. Поскольку FFmpeg - такая зрелая библиотека, я думаю, что я неправильно ее использую, и мне хотелось бы получить инструкции о том, как это сделать правильно.Правильно распределить и заполнить рамку в FFmpeg

Я отведение Frame с помощью:

AVFrame *bgrFrame = av_frame_alloc(); 

А потом я выделяю изображение в Frame с помощью:

av_image_alloc(bgrFrame->data, bgrFrame->linesize, bgrFrame->width, bgrFrame->height, AV_PIX_FMT_BGR24, 32); 

Затем я заполняю изображение выделено с помощью:

av_image_fill_pointers(bgrFrame->data, AV_PIX_FMT_BGR24, bgrFrame->height, originalBGRImage.data, bgrFrame->linesize); 

Где originalBGRImage является OpenCV Mat.

У этого есть утечка памяти, по-видимому, av_image_alloc() выделяет память, а av_image_fill_pointers() также выделяет память на тех же указателях (я вижу bgrFrame->data[0], меняя между вызовами).

Если я называю

av_freep(&bgrFrame->data[0]); 

После av_image_alloc(), это нормально, но если я называю это после того, как av_image_fill_pointers(), происходит сбой программы, даже если bgrFrame->data[0] не NULL, который я нахожу очень любопытным.

Looking FFmpeg, av_image_alloc()source code, я вижу, что вызывает av_image_fill_pointers() дважды внутри него после того, как выделение буфера buff .... а потом в av_image_fill_pointers()source code, data[0] заменяется указателем изображения, который (я думаю) источник утечка памяти, поскольку data[0] держал buf с предыдущего вызова av_image_alloc().

Итак, это задает последний вопрос: Каков правильный способ заполнения рамки изображением?.

+0

Поскольку данные уже есть, вы можете использовать 'avpicture_fill', который не выделяется. В любом случае вам следует выделить только один кадр и повторно использовать его. Кроме того, посмотрите, действительно ли вам нужны 'av_freep' или' av_free'. – SpamBot

+0

Но насколько я знаю, мне нужно предоставить кадр для кодирования, как я конвертирую AVPicture в AVFrame? – mFeinstein

ответ

1

Вы должны выделить свой кадр один раз.

AVFrame* alloc_picture(enum PixelFormat pix_fmt, int width, int height) 
{ 
AVFrame *f = avcodec_alloc_frame(); 
if (!f) 
    return NULL; 
int size = avpicture_get_size(pix_fmt, width, height); 
uint8_t *buffer = (uint8_t *) av_malloc(size); 
if (!buffer) { 
    av_free(f); 
    return NULL; 
} 
avpicture_fill((AVPicture *)f, buffer, pix_fmt, width, height); 
return f; 
} 

Да, бросок (AVPicture *) допускается https://stackoverflow.com/a/20498359/2079934. В следующих кадрах вы можете записать в этот кадр. Поскольку ваши исходные данные OpenCV являются BGR, и вам нужны RGB или YUV, вы можете использовать sws_scale. В моем приложении, я зеркало по вертикали:

struct SwsContext* convertCtx = sws_getContext(width, height, PIX_FMT_RGB24, c->width, c->height, c->pix_fmt, SWS_FAST_BILINEAR, NULL, NULL, NULL); 
avpicture_fill(&pic_raw, (uint8_t*)pixelBuffer, PIX_FMT_RGB24, width, height); 
// flip 
pic_raw.data[0] += (height - 1) * pic_raw.linesize[0]; 
pic_raw.linesize[0] *= -1; 
sws_scale(convertCtx, pic_raw.data, pic_raw.linesize, 0, height, f->data, f->linesize); 
out_size = avcodec_encode_video(c, outputBuffer, outputBufferSize, f); 

(Вы можете адаптировать PIX_FMT_RGB24 к вашим потребностям и читать cv::Mat без копирования данных.)

+0

Я получил его для работы с использованием 'av_fill_arrays()', и я передаю свой указатель изображения BGR и выделенный фрейм (который выделяется только один раз). Я также использую 'sws_scale()' для преобразования, единственным отсутствующим фрагментом был 'av_fill_arrays()' на самом деле. – mFeinstein

0

av_fill_arrays() делает работу. Он заполнит фреймы data[] и linesizes[], но не перераспределяет память.