我正在使用BGR图像填充Frame
进行编码,我收到内存泄漏。我想我得到了问题的根源,但它似乎是一个库问题。由于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
,我也是发现很好奇。
查看FFmpeg的av_image_alloc()
source code,我看到它在其内部调用av_image_fill_pointers()
两次,一次分配缓冲区buff
....稍后在{ {1}} source code,av_image_fill_pointers()
被图像指针取代,这是(我认为)内存泄漏的来源,因为data[0]
持有data[0]
之前的buf
电话。
所以这带来了最后一个问题:用图像填充框架的正确方法是什么?。
答案 0 :(得分:2)
您应该分配一次框架。
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
读取。)
答案 1 :(得分:0)
av_fill_arrays()
完成这项工作。它将填充框架的data[]
和linesizes[]
,但不会重新分配任何内存。