[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