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();
|
||||
if (!avframe)
|
||||
return;
|
||||
|
||||
avframe->width = width;
|
||||
avframe->height = height;
|
||||
avframe->format = AV_PIX_FMT_YUV420P;
|
||||
|
||||
int imgBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);
|
||||
uint8_t* buf = (uint8_t*)av_malloc(imgBufferSize);
|
||||
if (!buf)
|
||||
{
|
||||
int bufSize = av_image_alloc(avframe->data, avframe->linesize,
|
||||
width, height,
|
||||
static_cast<AVPixelFormat>(AV_PIX_FMT_YUV420P), VideoFrame::frameAlignment);
|
||||
|
||||
if(bufSize < 0){
|
||||
av_frame_free(&avframe);
|
||||
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++)
|
||||
{
|
||||
|
@ -96,14 +93,13 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe)
|
|||
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
uint8_t *dst = avframe->data[i] + dstStride * j;
|
||||
uint8_t *src = vpxframe->planes[i] + srcStride * j;
|
||||
uint8_t* dst = avframe->data[i] + dstStride * j;
|
||||
uint8_t* src = vpxframe->planes[i] + srcStride * j;
|
||||
memcpy(dst, src, minStride);
|
||||
}
|
||||
}
|
||||
|
||||
vframe = std::make_shared<VideoFrame>(avframe);
|
||||
|
||||
vframe = std::make_shared<VideoFrame>(avframe, true);
|
||||
emit frameAvailable(vframe);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,19 +24,20 @@ extern "C"{
|
|||
#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),
|
||||
sourcePixelFormat(pixFmt),
|
||||
freeSourceFrame(freeSourceFrame),
|
||||
destructCallback(destructCallback)
|
||||
{
|
||||
frameBuffer[pixFmt][dimensionsToKey(dimensions.size())] = sourceFrame;
|
||||
}
|
||||
|
||||
VideoFrame::VideoFrame(AVFrame* sourceFrame, std::function<void ()> destructCallback)
|
||||
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, destructCallback){}
|
||||
VideoFrame::VideoFrame(AVFrame* sourceFrame, std::function<void ()> destructCallback, bool freeSourceFrame)
|
||||
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, destructCallback, freeSourceFrame){}
|
||||
|
||||
VideoFrame::VideoFrame(AVFrame* sourceFrame)
|
||||
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, nullptr){}
|
||||
VideoFrame::VideoFrame(AVFrame* sourceFrame, bool freeSourceFrame)
|
||||
: VideoFrame(sourceFrame, QRect {0, 0, sourceFrame->width, sourceFrame->height}, sourceFrame->format, nullptr, freeSourceFrame){}
|
||||
|
||||
VideoFrame::~VideoFrame()
|
||||
{
|
||||
|
@ -248,6 +249,11 @@ AVFrame* VideoFrame::generateAVFrame(const QSize& dimensions, const int pixelFor
|
|||
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,
|
||||
dimensions.width(), dimensions.height(),
|
||||
static_cast<AVPixelFormat>(pixelFormat), frameAlignment);
|
||||
|
@ -267,6 +273,8 @@ AVFrame* VideoFrame::generateAVFrame(const QSize& dimensions, const int pixelFor
|
|||
resizeAlgo, nullptr, nullptr, nullptr);
|
||||
|
||||
if(!swsCtx){
|
||||
av_freep(&ret->data[0]);
|
||||
av_frame_unref(ret);
|
||||
av_frame_free(&ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -274,13 +282,8 @@ AVFrame* VideoFrame::generateAVFrame(const QSize& dimensions, const int pixelFor
|
|||
AVFrame* source = frameBuffer[sourcePixelFormat][dimensionsToKey(sourceDimensions.size())];
|
||||
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -292,7 +295,7 @@ void VideoFrame::storeAVFrame(AVFrame* frame, const QSize& dimensions, const int
|
|||
AVFrame* old_ret = frameBuffer[pixelFormat][dimensionsToKey(dimensions)];
|
||||
|
||||
// Free old frame
|
||||
av_freep(&frame->data[0]);
|
||||
av_freep(&old_ret->data[0]);
|
||||
av_frame_unref(old_ret);
|
||||
av_frame_free(&old_ret);
|
||||
}
|
||||
|
@ -312,9 +315,13 @@ void VideoFrame::deleteFrameBuffer()
|
|||
{
|
||||
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(freeSourceFrame)
|
||||
{
|
||||
av_freep(&frame->data[0]);
|
||||
}
|
||||
av_frame_unref(frame);
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
|
|
@ -56,10 +56,11 @@ public:
|
|||
* @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
|
||||
* 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, std::function<void()> destructCallback);
|
||||
VideoFrame(AVFrame* sourceFrame);
|
||||
VideoFrame(AVFrame* sourceFrame, QRect dimensions, int pixFmt, std::function<void()> destructCallback, bool freeSourceFrame = false);
|
||||
VideoFrame(AVFrame* sourceFrame, std::function<void()> destructCallback, bool freeSourceFrame = false);
|
||||
VideoFrame(AVFrame* sourceFrame, bool freeSourceFrame = false);
|
||||
|
||||
/**
|
||||
* Destructor for VideoFrame.
|
||||
|
@ -218,6 +219,7 @@ private:
|
|||
// Source frame
|
||||
const QRect sourceDimensions;
|
||||
const int sourcePixelFormat;
|
||||
const bool freeSourceFrame;
|
||||
|
||||
// Destructor callback
|
||||
const std::function<void ()> destructCallback;
|
||||
|
|
Loading…
Reference in New Issue
Block a user