正确分配并填充FFmpeg中的帧 [英] Correctly Allocate And Fill Frame In FFmpeg

查看:131
本文介绍了正确分配并填充FFmpeg中的帧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用BGR图像填充Frame进行编码,并且出现内存泄漏.我想我找到了问题的根源,但它似乎是一个图书馆问题.由于FFmpeg是一个非常成熟的库,因此我认为我在滥用它,我希望得到正确使用方法的指导.

I am filling a Frame with a BGR image for encoding, and I am getting a memory leak. I think I got to the source of the problem but it appears to be a library issue instead. Since FFmpeg is such a mature library, I think I am misusing it and I would like to be instructed on how to do it correctly.

我正在使用以下方式分配Frame:

I am allocating a Frame using:

AVFrame *bgrFrame = av_frame_alloc();

然后我使用以下方法在Frame中分配图像:

And later I allocate the image in the Frame using:

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

然后,我使用以下方法填充分配的图像:

Then I fill the image allocated using:

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

originalBGRImage是OpenCV Mat的位置.

Where originalBGRImage is an OpenCV Mat.

这会导致内存泄漏,很明显,av_image_alloc()分配了内存,而av_image_fill_pointers()也在相同的指针上分配了内存(我可以看到bgrFrame->data[0]在调用之间进行更改).

And this has a memory leak, apparently, av_image_alloc() allocates memory, and av_image_fill_pointers() also allocates memory, on the same pointers (I can see bgrFrame->data[0] changing between calls).

如果我打电话

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

av_image_alloc()之后就可以了,但是如果在av_image_fill_pointers()之后调用它,即使bgrFrame->data[0]不是NULL,程序也会崩溃,我觉得很好奇.

After av_image_alloc(), it's fine, but if I call it after av_image_fill_pointers(), the program crashes, even though bgrFrame->data[0] is not NULL, which I find very curious.

正在查看FFmpeg的av_image_alloc() 源代码,我看到它在调用av_image_fill_pointers()在其中两次,一次分配一个缓冲区buff ....,随后在av_image_fill_pointers()源代码data[0]被图像指针替代,它是(我认为)内存泄漏的源头,因为data[0]保留了先前av_image_alloc()buf打电话.

Looking FFmpeg's av_image_alloc() source code, I see it calls av_image_fill_pointers() twice inside it, once allocating a buffer buff....and later in av_image_fill_pointers() source code, data[0] is substituted by the image pointer, which is (I think) the source of the memory leak, since data[0] was holding buf from the previous av_image_alloc() call.

这带来了最后一个问题:用图像填充框架的正确方法是什么?.

So this brings the final question: What's the correct way of filling a frame with an image?.

推荐答案

您应该分配一次框架.

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.在我的应用程序中,我垂直镜像:

Yes, the cast (AVPicture*) is allowed https://stackoverflow.com/a/20498359/2079934 . In subsequent frames, you can write into the this frame. Since your OpenCV raw data is BGR and you need RGB or YUV, you can use sws_scale. In my application, I mirror vertically:

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中读取,而无需复制数据.)

(You can adapt PIX_FMT_RGB24 to your needs and read from cv::Mat without copying data.)

这篇关于正确分配并填充FFmpeg中的帧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆