mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
fix(video): fix memory leak caused by unfreed buffers in CoreVideoSource
Fixes a memory leak caused by old code within CoreVideoSource in the way AVFrame buffers are allocated.
This commit is contained in:
parent
50f67b3cef
commit
3df6b990ae
|
@ -70,22 +70,19 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe)
|
||||||
AVFrame* avframe = av_frame_alloc();
|
AVFrame* avframe = av_frame_alloc();
|
||||||
if (!avframe)
|
if (!avframe)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
avframe->width = width;
|
avframe->width = width;
|
||||||
avframe->height = height;
|
avframe->height = height;
|
||||||
avframe->format = AV_PIX_FMT_YUV420P;
|
avframe->format = AV_PIX_FMT_YUV420P;
|
||||||
|
|
||||||
int imgBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);
|
int bufSize = av_image_alloc(avframe->data, avframe->linesize,
|
||||||
uint8_t* buf = (uint8_t*)av_malloc(imgBufferSize);
|
width, height,
|
||||||
if (!buf)
|
static_cast<AVPixelFormat>(AV_PIX_FMT_YUV420P), VideoFrame::frameAlignment);
|
||||||
{
|
|
||||||
|
if(bufSize < 0){
|
||||||
av_frame_free(&avframe);
|
av_frame_free(&avframe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
avframe->opaque = buf;
|
|
||||||
|
|
||||||
uint8_t** data = avframe->data;
|
|
||||||
int* linesize = avframe->linesize;
|
|
||||||
av_image_fill_arrays(data, linesize, buf, AV_PIX_FMT_YUV420P, width, height, 1);
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
|
@ -96,14 +93,13 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe)
|
||||||
|
|
||||||
for (int j = 0; j < size; j++)
|
for (int j = 0; j < size; j++)
|
||||||
{
|
{
|
||||||
uint8_t *dst = avframe->data[i] + dstStride * j;
|
uint8_t* dst = avframe->data[i] + dstStride * j;
|
||||||
uint8_t *src = vpxframe->planes[i] + srcStride * j;
|
uint8_t* src = vpxframe->planes[i] + srcStride * j;
|
||||||
memcpy(dst, src, minStride);
|
memcpy(dst, src, minStride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vframe = std::make_shared<VideoFrame>(avframe);
|
vframe = std::make_shared<VideoFrame>(avframe, true);
|
||||||
|
|
||||||
emit frameAvailable(vframe);
|
emit frameAvailable(vframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,19 +24,20 @@ extern "C"{
|
||||||
#include <libswscale/swscale.h>
|
#include <libswscale/swscale.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoFrame::VideoFrame(AVFrame* sourceFrame, QRect dimensions, int pixFmt, std::function<void ()> destructCallback)
|
VideoFrame::VideoFrame(AVFrame* sourceFrame, QRect dimensions, int pixFmt, std::function<void ()> destructCallback, bool freeSourceFrame)
|
||||||
: sourceDimensions(dimensions),
|
: sourceDimensions(dimensions),
|
||||||
sourcePixelFormat(pixFmt),
|
sourcePixelFormat(pixFmt),
|
||||||
|
freeSourceFrame(freeSourceFrame),
|
||||||
destructCallback(destructCallback)
|
destructCallback(destructCallback)
|
||||||
{
|
{
|
||||||
frameBuffer[pixFmt][dimensionsToKey(dimensions.size())] = sourceFrame;
|
frameBuffer[pixFmt][dimensionsToKey(dimensions.size())] = sourceFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoFrame::VideoFrame(AVFrame* sourceFrame, std::function<void ()> destructCallback)
|
VideoFrame::VideoFrame(AVFrame* sourceFrame, std::function<void ()> destructCallback, bool freeSourceFrame)
|
||||||
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, destructCallback){}
|
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, destructCallback, freeSourceFrame){}
|
||||||
|
|
||||||
VideoFrame::VideoFrame(AVFrame* sourceFrame)
|
VideoFrame::VideoFrame(AVFrame* sourceFrame, bool freeSourceFrame)
|
||||||
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, nullptr){}
|
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, nullptr, freeSourceFrame){}
|
||||||
|
|
||||||
VideoFrame::~VideoFrame()
|
VideoFrame::~VideoFrame()
|
||||||
{
|
{
|
||||||
|
@ -248,6 +249,11 @@ AVFrame* VideoFrame::generateAVFrame(const QSize& dimensions, const int pixelFor
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate AVFrame fields
|
||||||
|
ret->width = dimensions.width();
|
||||||
|
ret->height = dimensions.height();
|
||||||
|
ret->format = pixelFormat;
|
||||||
|
|
||||||
int bufSize = av_image_alloc(ret->data, ret->linesize,
|
int bufSize = av_image_alloc(ret->data, ret->linesize,
|
||||||
dimensions.width(), dimensions.height(),
|
dimensions.width(), dimensions.height(),
|
||||||
static_cast<AVPixelFormat>(pixelFormat), frameAlignment);
|
static_cast<AVPixelFormat>(pixelFormat), frameAlignment);
|
||||||
|
@ -267,6 +273,8 @@ AVFrame* VideoFrame::generateAVFrame(const QSize& dimensions, const int pixelFor
|
||||||
resizeAlgo, nullptr, nullptr, nullptr);
|
resizeAlgo, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
if(!swsCtx){
|
if(!swsCtx){
|
||||||
|
av_freep(&ret->data[0]);
|
||||||
|
av_frame_unref(ret);
|
||||||
av_frame_free(&ret);
|
av_frame_free(&ret);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -274,13 +282,8 @@ AVFrame* VideoFrame::generateAVFrame(const QSize& dimensions, const int pixelFor
|
||||||
AVFrame* source = frameBuffer[sourcePixelFormat][dimensionsToKey(sourceDimensions.size())];
|
AVFrame* source = frameBuffer[sourcePixelFormat][dimensionsToKey(sourceDimensions.size())];
|
||||||
|
|
||||||
sws_scale(swsCtx, source->data, source->linesize, 0, sourceDimensions.height(), ret->data, ret->linesize);
|
sws_scale(swsCtx, source->data, source->linesize, 0, sourceDimensions.height(), ret->data, ret->linesize);
|
||||||
|
|
||||||
// Populate AVFrame fields
|
|
||||||
ret->width = dimensions.width();
|
|
||||||
ret->height = dimensions.height();
|
|
||||||
ret->format = pixelFormat;
|
|
||||||
|
|
||||||
sws_freeContext(swsCtx);
|
sws_freeContext(swsCtx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +295,7 @@ void VideoFrame::storeAVFrame(AVFrame* frame, const QSize& dimensions, const int
|
||||||
AVFrame* old_ret = frameBuffer[pixelFormat][dimensionsToKey(dimensions)];
|
AVFrame* old_ret = frameBuffer[pixelFormat][dimensionsToKey(dimensions)];
|
||||||
|
|
||||||
// Free old frame
|
// Free old frame
|
||||||
av_freep(&frame->data[0]);
|
av_freep(&old_ret->data[0]);
|
||||||
av_frame_unref(old_ret);
|
av_frame_unref(old_ret);
|
||||||
av_frame_free(&old_ret);
|
av_frame_free(&old_ret);
|
||||||
}
|
}
|
||||||
|
@ -312,9 +315,13 @@ void VideoFrame::deleteFrameBuffer()
|
||||||
{
|
{
|
||||||
AVFrame* frame = dimKeyIter.value();
|
AVFrame* frame = dimKeyIter.value();
|
||||||
|
|
||||||
// We only need to free allocated buffers for derived frames and not the original source
|
// Treat source frame and derived frames separately
|
||||||
if(pixFmtIter.key() == sourcePixelFormat && dimKeyIter.key() == sourceKey)
|
if(pixFmtIter.key() == sourcePixelFormat && dimKeyIter.key() == sourceKey)
|
||||||
{
|
{
|
||||||
|
if(freeSourceFrame)
|
||||||
|
{
|
||||||
|
av_freep(&frame->data[0]);
|
||||||
|
}
|
||||||
av_frame_unref(frame);
|
av_frame_unref(frame);
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,10 +56,11 @@ public:
|
||||||
* @param destructCallback callback function to run upon destruction of the VideoFrame
|
* @param destructCallback callback function to run upon destruction of the VideoFrame
|
||||||
* this callback is only run when destroying a valid VideoFrame (e.g. a VideoFrame instance in
|
* this callback is only run when destroying a valid VideoFrame (e.g. a VideoFrame instance in
|
||||||
* which releaseFrame() was called upon it will not call the callback).
|
* which releaseFrame() was called upon it will not call the callback).
|
||||||
|
* @param freeSourceFrame whether to free the source frame buffers or not.
|
||||||
*/
|
*/
|
||||||
VideoFrame(AVFrame* sourceFrame, QRect dimensions, int pixFmt, std::function<void()> destructCallback);
|
VideoFrame(AVFrame* sourceFrame, QRect dimensions, int pixFmt, std::function<void()> destructCallback, bool freeSourceFrame = false);
|
||||||
VideoFrame(AVFrame* sourceFrame, std::function<void()> destructCallback);
|
VideoFrame(AVFrame* sourceFrame, std::function<void()> destructCallback, bool freeSourceFrame = false);
|
||||||
VideoFrame(AVFrame* sourceFrame);
|
VideoFrame(AVFrame* sourceFrame, bool freeSourceFrame = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor for VideoFrame.
|
* Destructor for VideoFrame.
|
||||||
|
@ -218,6 +219,7 @@ private:
|
||||||
// Source frame
|
// Source frame
|
||||||
const QRect sourceDimensions;
|
const QRect sourceDimensions;
|
||||||
const int sourcePixelFormat;
|
const int sourcePixelFormat;
|
||||||
|
const bool freeSourceFrame;
|
||||||
|
|
||||||
// Destructor callback
|
// Destructor callback
|
||||||
const std::function<void ()> destructCallback;
|
const std::function<void ()> destructCallback;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user