使用 ffmpeg 时内存泄漏
Memory leak when using ffmpeg
我实现了一个类,它生成了一个用于读取和排队帧的线程,主线程通过OpenGL显示这些帧。在将图像数据绑定到 OpenGL 纹理后,我尝试释放分配的内存,但似乎有些内存没有正确释放。内存使用量不断增长,直到系统内存不足,最终帧读取器线程由于内存分配失败而无法抓取新帧。有人可以帮我解决我可能错过的事情吗?谢谢。
这是帧读取器线程的代码:
void AVIReader::frameReaderThreadFunc()
{
AVPacket packet;
while (readFrames) {
// Allocate necessary memory
AVFrame* pFrame = av_frame_alloc();
if (pFrame == nullptr)
{
continue;
}
AVFrame* pFrameRGB = av_frame_alloc();
if (pFrameRGB == nullptr)
{
av_frame_free(&pFrame);
continue;
}
// Determine required buffer size and allocate buffer
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
uint8_t* buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
if (buffer == nullptr)
{
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
continue;
}
// Assign appropriate parts of buffer to image planes in pFrameRGB
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
if (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
int frameFinished;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished) {
// Convert the image from its native format to RGB
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
VideoFrame vf;
vf.frame = pFrameRGB;
vf.pts = av_frame_get_best_effort_timestamp(pFrame) * time_base;
frameQueue.enqueue(vf);
av_frame_unref(pFrame);
av_frame_free(&pFrame);
}
}
//av_packet_unref(&packet);
av_free_packet(&packet);
}
}
}
这是抓取排队帧并将其绑定到 OpenGL 纹理的代码。我显式保存上一帧,直到我用下一帧切换它。否则,它似乎会导致段错误。
void AVIReader::GrabAVIFrame()
{
if (curFrame.pts >= clock_pts)
{
return;
}
if (frameQueue.empty())
return;
// Get a packet from the queue
VideoFrame videoFrame = frameQueue.top();
while (!frameQueue.empty() && frameQueue.top().pts < clock_pts)
{
videoFrame = frameQueue.dequeue();
}
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, videoFrame.frame->data[0]);
// release previous frame
if (curFrame.frame)
{
av_free(curFrame.frame->data[0]);
}
av_frame_unref(curFrame.frame);
// set current frame to new frame
curFrame = videoFrame;
}
frameQueue 是一个线程安全的优先级队列,它保存定义为:
class VideoFrame {
public:
AVFrame* frame;
double pts;
};
更新:将当前帧设置为新帧的顺序中存在一个愚蠢的错误。尝试了一些东西后,我忘了把它换回来。我也采纳了@ivan_onys的建议,但这似乎并不能解决问题。
更新2:我采纳了邦迪@Al建议无条件释放pFrame和数据包,但问题仍然存在。
由于缓冲区包含需要在glTexSubImage2D()中使用的实际图像数据,因此在屏幕上显示完之前,我无法释放它(否则会出现段错误)。 avpicture_fill() 分配 frame->data[0] = 缓冲区,所以我认为调用 av_free(curFrame.frame->data[0]); 在纹理映射后的前一帧上,新帧应该释放分配的缓冲区。
以下是更新的帧读取器线程代码:
void AVIReader::frameReaderThreadFunc()
{
AVPacket packet;
while (readFrames) {
// Allocate necessary memory
AVFrame* pFrame = av_frame_alloc();
if (pFrame == nullptr)
{
continue;
}
AVFrame* pFrameRGB = av_frame_alloc();
if (pFrameRGB == nullptr)
{
av_frame_free(&pFrame);
continue;
}
// Determine required buffer size and allocate buffer
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
pCodecCtx->height);
uint8_t* buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
if (buffer == nullptr)
{
av_frame_free(&pFrame);
av_frame_free(&pFrameRGB);
continue;
}
// Assign appropriate parts of buffer to image planes in pFrameRGB
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
pCodecCtx->width, pCodecCtx->height);
if (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStream) {
// Decode video frame
int frameFinished;
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished) {
// Convert the image from its native format to RGB
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
VideoFrame vf;
vf.frame = pFrameRGB;
vf.pts = av_frame_get_best_effort_timestamp(pFrame) * time_base;
frameQueue.enqueue(vf);
}
}
}
av_frame_unref(pFrame);
av_frame_free(&pFrame);
av_packet_unref(&packet);
av_free_packet(&packet);
}
}
已解决:事实证明,当数据包来自非视频流(例如音频)时,就会发生泄漏。我还需要释放在 GrabAVIFrame() 的 while 循环中跳过的帧上的资源。
你永远不会释放buffer
.检查您的流动路径,就像现在一样,它没有真正的意义。另外,考虑一下ivan_onys回答的内容。
编辑:
正如我所写,检查流程。您有三个分配:
- pFrame
- pFrameRGB
- 缓冲区
但是只有在true
此命令时才能释放它们:
if (av_read_frame(pFormatCtx, &packet) >= 0)
和if (frameFinished)
和buffer
永远不会发布。
这似乎是问题所在。我会在while
结束之前发布所有指针:
if (av_read_frame(pFormatCtx, &packet) >= 0) {
...
if (frameFinished) {
// av_frame_unref(pFrame); --> remove this line
// av_frame_free(&pFrame); --> remove this line
}
}
// here is the body from while
// release it here - unconditional
av_packet_unref(&packet);
av_free_packet(&packet);
av_free(buffer);
} // while
} // frameReaderThreadFunc()
我在这里看到多个问题:
-
尝试释放分配的内存(如果未分配)。
AVFrame* pFrame = av_frame_alloc(); if (pFrame == nullptr) { av_frame_free(&pFrame); continue; }
-
不释放分配的内存(pFrame from 1. 未释放):
AVFrame* pFrameRGB = av_frame_alloc(); if (pFrameRGB == nullptr) { av_frame_free(&pFrameRGB); continue; }
在继续之前,您应该释放上述循环正文中成功分配的所有内存。
- C++功能泄漏内存,我是C++新手,不确定如何解决
- 我的堆栈弹出式磁带的实现是否泄漏内存?
- 将 c++ 向量转换为字符 ** 而不会泄漏内存
- 析构函数 C++ 使泄漏内存
- 构造函数对象赋值是否泄漏内存
- corba :: orb_init泄漏内存
- Gmock泄漏内存
- 如何在不泄漏内存的情况下删除链接列表
- Visual C ODBC关闭记录集泄漏内存
- 为什么泄漏内存比在动态数组上执行 delete[] 慢
- OpenGL正在泄漏内存.哪个对象未释放
- 可以std ::退出泄漏内存
- uiautomation findall泄漏内存
- 为什么在此OpenCL代码中泄漏内存,为什么要泄漏内存
- pthread在完成后会泄漏内存
- win32 标准::线程泄漏内存
- 返回指向同一变量的指针是否会泄漏内存
- 使用clectType(new any_type())可能会泄漏内存泄漏
- Windows开发:如何确定我的应用程序是否正在泄漏内存
- WinHttp打开泄漏内存