gpt4 book ai didi

c++ - 使用ffmpeg时内存泄漏

转载 作者:太空狗 更新时间:2023-10-29 21:35:39 27 4
gpt4 key购买 nike

我已经实现了一个类,它产生一个线程来读取和排队帧,主线程通过 OpenGL 显示这些帧。在将图像数据绑定(bind)到 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);
}
}
}

这是获取排队帧并将其绑定(bind)到 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 的建议,但这似乎并没有解决问题。


更新二:我采纳了@Al Bundy的建议无条件释放pFrame和packet,但问题依旧。

因为缓冲区包含需要在 glTexSubImage2D() 中使用的实际图像数据,所以我不能释放它,直到我在屏幕上显示完它(否则我会得到一个段错误)。 avpicture_fill() 分配 frame->data[0] = buffer,所以我认为调用 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 的回答。


编辑:

如我所写,检查流程。您有三个分配:

  • 框架
  • 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()

关于c++ - 使用ffmpeg时内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41775549/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com