[Libav-user] ffmpeg based encoder memory leak

Paweł Ciejka pawel.ciejka at gmail.com
Mon Aug 8 09:57:20 CEST 2011


Hi,
please give me some advice i wrote simple ffmpeg based encoder and i cant
correct memory leak in it, so far I have found that it occurs when i am
closing the AVFormatContext and AVStreams on the moment I am trying to
understand the source code of ffmpeg.c

QVideoEncoder.h partial code:

class QVideoEncoder : public VirtualEncoder
{
Q_OBJECT
Q_INTERFACES(VirtualPlugin)
Q_INTERFACES(VirtualEncoder)

private:

static bool _initialized_;

long long int _time;
long long int _frames;
bool _running;
float _level;
int _fps;
QString _format;
QString _name;

int _count;
unsigned int _width;
unsigned int _height;
unsigned int _bitrate;
unsigned int _gop;
VirtualLog *_log;
bool _ok;

//QByteArray

VFSHandle *_handle;

VirtualFS *_vfs;

QMutex *ptr;

// FFmpeg stuff
ffmpeg::AVFormatContext *FormatCtx;
ffmpeg::AVOutputFormat *OutputFormat;
ffmpeg::AVCodecContext *CodecCtx;
ffmpeg::AVStream *VideoStream;
ffmpeg::AVCodec *codec;
ffmpeg::AVFrame *frame;
uint8_t *picture_buf;
int outbuf_size;
uint8_t* outbuf;
ffmpeg::SwsContext *img_convert_ctx;
// ffmpeg::AVPacket *pkt;

//{...}

};



QVideoEncoder.cxx partial code:

bool QVideoEncoder::createFile(QString fileName,unsigned w,unsigned
h,unsigned bitrate,unsigned gop)
{
close();

QMutexLocker lock(locker());

_width = w;
_height = h;
_gop = gop;
_bitrate = bitrate;

initVars();
_frames = 0;
_time = 0;


if(!isSizeValid())
{
writeLog(QString("QVideoEncoder::createFile: invalid image
size"),LogType::ERROR);
return false;
}

if(!(OutputFormat = ffmpeg::av_guess_format(format().toStdString().c_str(),
NULL , NULL)))
OutputFormat = ffmpeg::av_guess_format("mpeg", NULL, NULL);

if(!(FormatCtx = ffmpeg::avformat_alloc_context()))
{
writeLog(QString("QVideoEncoder::createFile: failed to allocate format
context"),LogType::ERROR);
return false;
}

FormatCtx->oformat = OutputFormat;
snprintf(FormatCtx->filename, sizeof(FormatCtx->filename), "%s",
fileName.toStdString().c_str());

if(!(VideoStream = av_new_stream(FormatCtx,0)))
{
writeLog(QString("QVideoEncoder::createFile: failed to open
stream"),LogType::ERROR);
return false;
}

CodecCtx = VideoStream->codec;

CodecCtx->codec_id = OutputFormat->video_codec;
CodecCtx->codec_type = ffmpeg::CODEC_TYPE_VIDEO;
CodecCtx->thread_count = threadCount();

if(!(codec = avcodec_find_encoder(CodecCtx->codec_id)))
{
writeLog(QString("QVideoEncoder::createFile: failed to find specified
encoder"),LogType::ERROR);
return false;
}

avcodec_get_context_defaults(CodecCtx); //trust me ffmpeg knows it better
than ya'all ;-)
CodecCtx->width = w;
CodecCtx->height = h;

int t = fps();


ffmpeg::AVRational fps = (ffmpeg::AVRational){1,t};

if (codec && codec->supported_framerates)
fps = codec->supported_framerates[ffmpeg::av_find_nearest_q_idx(fps,
codec->supported_framerates)];

setFps(fps.den);


CodecCtx->time_base.den = fps.den;
CodecCtx->time_base.num = fps.num;
CodecCtx->pix_fmt = ffmpeg::PIX_FMT_YUV420P;
CodecCtx->compression_level = compressionLevel();
CodecCtx->qblur = 0.2;

CodecCtx->me_range = 16;
CodecCtx->max_qdiff = 4;
CodecCtx->qmin = 10;
CodecCtx->qmax = 51;

CodecCtx->gop_size = this->fps();

if(FormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
CodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;


if (av_set_parameters(FormatCtx, NULL) < 0)
{
writeLog(QString("QVideoEncoder::createFile: failed to set a/v
parameters"),LogType::ERROR);
return false;
}

if (avcodec_open(CodecCtx, codec) < 0)
{
writeLog(QString("QVideoEncoder::createFile: failed to open a/v
codec"),LogType::ERROR);
return false;
}

if(!initOutputBuf())
{
writeLog(QString("QVideoEncoder::createFile: failed to init output
buff"),LogType::ERROR);
return false;
}

if(!initFrame())
{
writeLog(QString("QVideoEncoder::createFile: failed to init a/v
frame"),LogType::ERROR);
return false;
}

VFSHandle *handle = _vfs->open(fileName);

setVFSHandle(handle);


if(avio_open_dyn_buf(&FormatCtx->pb) < 0)
{
writeLog(QString("QVideoEncoder::createFile: failed to open dynamic
buffer"),LogType::ERROR);
return false;
}

av_write_header(FormatCtx);

uint8_t *p = 0;
int len = avio_close_dyn_buf(FormatCtx->pb,&p);

if(len)
{
if(handle)
handle->write((const char*)p,len);


}

if(p)
ffmpeg::av_free(p);

_ok = true;

if(!_editor)
_editor = /*new GLFrameEditor(width(),height());*/ new
BasicFrameEditor(width(),height());

return true;
}

int QVideoEncoder::encodeImage(const QImage &i)
{
QMutexLocker lock(locker());

//QImage i;

if(!isOk())
return -1;

++_frames;
int t = 1000/fps();
_time += t;


convertImage_sws(i); // SWS conversion
frame->pts = _time*90;

int out_size =
ffmpeg::avcodec_encode_video(CodecCtx,outbuf,outbuf_size,frame);

if (out_size > 0)
{

ffmpeg::AVPacket pkt;
//ffmpeg::AVPacket *pkt = &_pkt;
pkt.destruct = ffmpeg::av_destruct_packet;
av_init_packet(&pkt);


//qDebug() << &pkt;


if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, CodecCtx->time_base,
VideoStream->time_base);

if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, CodecCtx->time_base,
VideoStream->time_base);

pkt.duration = av_rescale_q(pkt.duration, CodecCtx->time_base,
VideoStream->time_base);

if(CodecCtx->coded_frame->key_frame)
pkt.flags |= PKT_FLAG_KEY;

pkt.stream_index= VideoStream->index;
pkt.data = outbuf;
pkt.size = out_size;
pkt.duration = 1000/fps();


if(avio_open_dyn_buf(&FormatCtx->pb) < 0)
{
writeLog(QString("QVideoEncoder::encodeImage: failed to open dynamic
buffer"),LogType::ERROR);
return false;
}

int ret = av_write_frame(FormatCtx, &pkt);

uint8_t *p = 0;
int len = avio_close_dyn_buf(FormatCtx->pb,&p);

if(len)
{
if(ret < 0)
{
qDebug() << "dupa";
return -1;
}

if(vfsHandle())
{
vfsHandle()->write((const char*)p,len);
vfsHandle()->flush();
}
}

if(p)
ffmpeg::av_free(p);

//if(pkt)
//ffmpeg::av_free_packet(&pkt);
}

return out_size;
}

bool QVideoEncoder::convertImage_sws(const QImage &img)
{
//QMutexLocker lock(locker());

if((const unsigned int)img.width() != width() || (const unsigned int)
img.height() != height())
return false;

if(img.format()!= QImage::Format_RGB32 && img.format() !=
QImage::Format_ARGB32)
return false;

ffmpeg::SwsContext *ctx;
//img_convert_ctx = /*Cached*/
img_convert_ctx =
ffmpeg::sws_getContext(/*img_convert_ctx,*/width(),height(),ffmpeg::PIX_FMT_BGRA,width(),height(),ffmpeg::PIX_FMT_YUV420P,SWS_BICUBIC,
NULL, NULL, NULL);
//img_convert_ctx =
ffmpeg::sws_getCachedContext(img_convert_ctx,getWidth(),getHeight(),ffmpeg::PIX_FMT_BGRA,getWidth(),getHeight(),ffmpeg::PIX_FMT_YUV420P,SWS_FAST_BILINEAR,
NULL, NULL, NULL);

//qDebug() << "context info" << img_convert_ctx;

//img_convert_ctx = ctx;

if (img_convert_ctx == NULL)
return false;

const uint8_t *srcplanes[3];
srcplanes[0]= (const uint8_t*) img.bits();
srcplanes[1]= 0;
srcplanes[2]= 0;

int srcstride[3];
srcstride[0]= img.bytesPerLine();
srcstride[1]= 0;
srcstride[2]= 0;


ffmpeg::sws_scale(img_convert_ctx, srcplanes, srcstride,0, height(),
frame->data, frame->linesize);

ffmpeg::sws_freeContext(img_convert_ctx);
img_convert_ctx = 0;

return true;
}

bool QVideoEncoder::close()
{
QMutexLocker lock(locker());


if(!isOk())
return false;

if(avio_open_dyn_buf(&FormatCtx->pb) < 0)
{
writeLog(QString("QVideoEncoder::close: failed to open dynamic
buffer"),LogType::ERROR);
return false;
}

av_write_trailer(FormatCtx);

uint8_t *p = 0;

int len = avio_close_dyn_buf(FormatCtx->pb,&p);

if(len)
{
//_file.write((const char*) p,len);
if(vfsHandle())
{
vfsHandle()->write((const char*)p,len);
vfsHandle()->flush();
}
}

vfsHandle()->close();
delete vfsHandle();
setVFSHandle(0);

if(p)
ffmpeg::av_free(p);

//ffmpeg::av_freep(&VideoStream->codec->stats_in);
//avcodec_close(VideoStream->codec);

freeFrame();
freeOutputBuf();

for(unsigned int i = 0; i < FormatCtx->nb_streams; i++)
{
ffmpeg::av_freep(&FormatCtx->streams[i]->codec->subtitle_header);
ffmpeg::av_freep(&FormatCtx->streams[i]->codec->stats_in);
ffmpeg::avcodec_close(FormatCtx->streams[i]->codec);
ffmpeg::av_freep(&FormatCtx->streams[i]->codec);
ffmpeg::av_freep(&FormatCtx->streams[i]);
}

//avio_close(FormatCtx->pb);
  //ffmpeg::avformat_free_context(FormatCtx); //sigsegv
av_free(FormatCtx);

return true;

}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20110808/0fba7578/attachment.html>


More information about the Libav-user mailing list