<div>Hi,<br></div><div>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</div>
<div><br></div><div>QVideoEncoder.h partial code:</div><div><br></div><div>class QVideoEncoder : public VirtualEncoder<br>{<br>    Q_OBJECT<br>    Q_INTERFACES(VirtualPlugin)<br>    Q_INTERFACES(VirtualEncoder)<br>    <br>
    private:<br>  <br>      static bool _initialized_;<br>    <br>      long long int _time;<br>      long long int _frames;<br>      bool _running;<br>      float _level;<br>      int _fps;<br>      QString _format;<br>      QString _name;<br>
      <br>      int _count;<br>      unsigned int _width;<br>      unsigned int _height;<br>      unsigned int _bitrate;<br>      unsigned int _gop;<br>    VirtualLog *_log;<br>      bool _ok;<br><br>  //QByteArray <br>    <br>
        VFSHandle *_handle;<br>    <br>     VirtualFS *_vfs;<br>    <br>        QMutex *ptr;<br>    <br>      // FFmpeg stuff<br>      ffmpeg::AVFormatContext *FormatCtx;<br>      ffmpeg::AVOutputFormat *OutputFormat;<br>      ffmpeg::AVCodecContext *CodecCtx;<br>
      ffmpeg::AVStream *VideoStream;<br>      ffmpeg::AVCodec *codec;<br>      ffmpeg::AVFrame *frame;<br>      uint8_t *picture_buf;<br>      int outbuf_size;<br>      uint8_t* outbuf;<br>      ffmpeg::SwsContext *img_convert_ctx;<br>
     // ffmpeg::AVPacket *pkt;<br></div><div><br></div><div>//{...}</div><div><br></div><div>};</div><div><br></div><div><br></div><div><br></div><div>QVideoEncoder.cxx partial code:</div><div><br></div><div>bool QVideoEncoder::createFile(QString fileName,unsigned w,unsigned h,unsigned bitrate,unsigned gop)<br>
{<br>   close();<br><br>   QMutexLocker lock(locker());<br>     <br>   _width = w;<br>   _height = h;<br>   _gop = gop;<br>   _bitrate = bitrate;<br><br>   initVars();<br>   _frames = 0;<br>   _time  = 0;<br>   <br>   <br>   if(!isSizeValid())<br>
   {<br>      writeLog(QString("QVideoEncoder::createFile: invalid image size"),LogType::ERROR);<br>      return false;<br>   }<br>   <br>   if(!(OutputFormat = ffmpeg::av_guess_format(format().toStdString().c_str(), NULL , NULL)))<br>
      OutputFormat = ffmpeg::av_guess_format("mpeg", NULL, NULL);<br>   <br>   if(!(FormatCtx = ffmpeg::avformat_alloc_context()))<br>   {<br>         writeLog(QString("QVideoEncoder::createFile: failed to allocate format context"),LogType::ERROR);<br>
        return false;<br>   }<br>   <br>   FormatCtx->oformat = OutputFormat;<br>   snprintf(FormatCtx->filename, sizeof(FormatCtx->filename), "%s", fileName.toStdString().c_str());<br><br>   if(!(VideoStream = av_new_stream(FormatCtx,0)))<br>
   {<br>   writeLog(QString("QVideoEncoder::createFile: failed to open stream"),LogType::ERROR);<br>      return false;<br>   }<br>   <br>   CodecCtx = VideoStream->codec;<br>   <br>   CodecCtx->codec_id = OutputFormat->video_codec;<br>
   CodecCtx->codec_type = ffmpeg::CODEC_TYPE_VIDEO;<br>   CodecCtx->thread_count = threadCount();<br>   <br>   if(!(codec = avcodec_find_encoder(CodecCtx->codec_id)))<br>   {<br>        writeLog(QString("QVideoEncoder::createFile: failed to find specified encoder"),LogType::ERROR);<br>
        return false;<br>   }<br>   <br>   avcodec_get_context_defaults(CodecCtx); //trust me ffmpeg knows it better than ya'all ;-)<br>   CodecCtx->width = w;<br>   CodecCtx->height = h;<br>   <br>   int t = fps();<br>
<br>   <br>   ffmpeg::AVRational fps = (ffmpeg::AVRational){1,t};<br>   <br>   if (codec && codec->supported_framerates)<br>            fps = codec->supported_framerates[ffmpeg::av_find_nearest_q_idx(fps, codec->supported_framerates)];<br>
<br>   setFps(fps.den);<br>   <br>      <br>   CodecCtx->time_base.den = fps.den;<br>   CodecCtx->time_base.num = fps.num;<br>   CodecCtx->pix_fmt = ffmpeg::PIX_FMT_YUV420P;<br>CodecCtx->compression_level = compressionLevel();</div>
<div>CodecCtx->qblur = 0.2;<br>   <br>     CodecCtx->me_range = 16;<br>        CodecCtx->max_qdiff = 4;<br>        CodecCtx->qmin = 10;<br>        CodecCtx->qmax = 51;<br><br>   CodecCtx->gop_size = this->fps();<br>
<br>   if(FormatCtx->oformat->flags & AVFMT_GLOBALHEADER)<br>      CodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;<br><br><br>   if (av_set_parameters(FormatCtx, NULL) < 0)<br>   {<br> writeLog(QString("QVideoEncoder::createFile: failed to set a/v parameters"),LogType::ERROR);<br>
        return false;<br>   }<br>  <br>   if (avcodec_open(CodecCtx, codec) < 0)<br>   {<br>   writeLog(QString("QVideoEncoder::createFile: failed to open a/v codec"),LogType::ERROR);<br>    return false;<br>   }<br><br>
   if(!initOutputBuf())<br>   {<br> writeLog(QString("QVideoEncoder::createFile: failed to init output buff"),LogType::ERROR);<br>  return false;<br>   }<br>   <br>   if(!initFrame())<br>   {<br>   writeLog(QString("QVideoEncoder::createFile: failed to init a/v frame"),LogType::ERROR);<br>
        return false;<br>   }<br>   <br>   VFSHandle *handle = _vfs->open(fileName);<br>     <br>   setVFSHandle(handle);<br>    <br>   <br>   if(avio_open_dyn_buf(&FormatCtx->pb) < 0)<br>   {<br>   writeLog(QString("QVideoEncoder::createFile: failed to open dynamic buffer"),LogType::ERROR);<br>
        return false;<br>   }<br>   <br>   av_write_header(FormatCtx);<br>   <br>   uint8_t *p = 0;<br>   int len = avio_close_dyn_buf(FormatCtx->pb,&p);<br>    <br>   if(len)<br>   {<br>  if(handle)<br>            handle->write((const char*)p,len);<br>
   <br>   <br>   }<br>   <br>   if(p)<br> ffmpeg::av_free(p);<br>   <br>   _ok = true;<br><br>   if(!_editor)<br>   _editor = /*new GLFrameEditor(width(),height());*/ new BasicFrameEditor(width(),height());<br>   <br>   return true;<br>
}<br></div><div><br></div><div>int QVideoEncoder::encodeImage(const QImage &i)<br>{ <br>    QMutexLocker lock(locker());<br>  <br>   //QImage i;<br>  <br>   if(!isOk())<br>      return -1;<br>    <br>    ++_frames;<br>    int t = 1000/fps();<br>
    _time += t;<br>   <br>  <br>  convertImage_sws(i);     // SWS conversion<br>   frame->pts = _time*90;<br>   <br>     int out_size = ffmpeg::avcodec_encode_video(CodecCtx,outbuf,outbuf_size,frame);<br><br>   if (out_size > 0)<br>
   {    <br>         <br>   ffmpeg::AVPacket pkt;<br> //ffmpeg::AVPacket *pkt = &_pkt;<br>  pkt.destruct = ffmpeg::av_destruct_packet;<br>    av_init_packet(&pkt);<br><br>      <br>      //qDebug() << &pkt;<br>      <br>         <br>
        if (pkt.dts != AV_NOPTS_VALUE)<br>                pkt.dts = av_rescale_q(pkt.dts, CodecCtx->time_base, VideoStream->time_base);<br>                    <br>     if (pkt.pts != AV_NOPTS_VALUE)<br>                pkt.pts = av_rescale_q(pkt.pts, CodecCtx->time_base, VideoStream->time_base);<br>
                    <br>  pkt.duration = av_rescale_q(pkt.duration, CodecCtx->time_base, VideoStream->time_base);<br>    <br>   if(CodecCtx->coded_frame->key_frame)<br>            pkt.flags |= PKT_FLAG_KEY;<br><br>  pkt.stream_index= VideoStream->index;<br>
        pkt.data = outbuf;<br>    pkt.size = out_size;<br>  pkt.duration = 1000/fps();<br><br>      <br>  if(avio_open_dyn_buf(&FormatCtx->pb) < 0)<br>   {<br>             writeLog(QString("QVideoEncoder::encodeImage: failed to open dynamic buffer"),LogType::ERROR);<br>
                return false;<br> }<br>     <br>      int ret = av_write_frame(FormatCtx, &pkt);<br>      <br>        uint8_t *p = 0;<br>       int len = avio_close_dyn_buf(FormatCtx->pb,&p);<br><br>      if(len)<br>       {<br>             if(ret < 0)<br>                {<br>                     qDebug() << "dupa";<br>
                        return -1;<br>            }<br>             <br>              if(vfsHandle())<br>               {       <br>                      vfsHandle()->write((const char*)p,len);<br>                    vfsHandle()->flush();<br>              }<br>     }<br>     <br>      if(p)<br>         ffmpeg::av_free(p);<br>   <br>      //if(pkt)<br>     //ffmpeg::av_free_packet(&pkt);<br>
   }<br><br>   return out_size;<br>}<br></div><div><br></div><div>bool QVideoEncoder::convertImage_sws(const QImage &img)<br>{<br>        //QMutexLocker lock(locker());<br>        <br>   if((const unsigned int)img.width() != width() || (const unsigned int) img.height() != height())<br>
        return false;<br>   <br>   if(img.format()!= QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32)<br>       return false;<br>   <br>   ffmpeg::SwsContext *ctx;<br>   //img_convert_ctx = /*Cached*/<br>   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);<br>
   //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);<br>   <br>  //qDebug() << "context info" <<  img_convert_ctx;<br>
   <br>   //img_convert_ctx = ctx;<br>   <br>   if (img_convert_ctx == NULL)<br>      return false;<br><br>   const uint8_t *srcplanes[3];<br>   srcplanes[0]= (const uint8_t*) img.bits();<br>   srcplanes[1]= 0;<br>   srcplanes[2]= 0;<br>
<br>   int srcstride[3];<br>   srcstride[0]= img.bytesPerLine();<br>   srcstride[1]= 0;<br>   srcstride[2]= 0;<br><br><br>   ffmpeg::sws_scale(img_convert_ctx, srcplanes, srcstride,0, height(), frame->data, frame->linesize);<br>
<br>   ffmpeg::sws_freeContext(img_convert_ctx);<br>   img_convert_ctx = 0;<br>   <br>   return true;<br>}<br></div><div><br></div><div>bool QVideoEncoder::close()<br>{<br>      QMutexLocker lock(locker());<br>  <br>      <br>    if(!isOk())<br>
      return false;<br>   <br>    if(avio_open_dyn_buf(&FormatCtx->pb) < 0)<br>    {<br>      writeLog(QString("QVideoEncoder::close: failed to open dynamic buffer"),LogType::ERROR);<br>    return false;<br>    }<br>
   <br>   av_write_trailer(FormatCtx);<br>   <br>   uint8_t *p = 0;<br>    <br>   int len = avio_close_dyn_buf(FormatCtx->pb,&p);<br>   <br>    if(len)<br>    {<br>       //_file.write((const char*) p,len);<br>   if(vfsHandle())<br>
        {<br>             vfsHandle()->write((const char*)p,len);    <br>                vfsHandle()->flush();<br>      }<br>    }<br>    <br>        vfsHandle()->close();<br>      delete vfsHandle();<br>   setVFSHandle(0);<br>    <br>    if(p)<br>     ffmpeg::av_free(p);<br>
<br>   //ffmpeg::av_freep(&VideoStream->codec->stats_in);<br>   //avcodec_close(VideoStream->codec);<br>   <br>   freeFrame();<br>   freeOutputBuf();<br><br>   for(unsigned int i = 0; i < FormatCtx->nb_streams; i++)<br>
   {<br>      ffmpeg::av_freep(&FormatCtx->streams[i]->codec->subtitle_header);<br>      ffmpeg::av_freep(&FormatCtx->streams[i]->codec->stats_in);<br>      ffmpeg::avcodec_close(FormatCtx->streams[i]->codec);<br>
      ffmpeg::av_freep(&FormatCtx->streams[i]->codec);<br>      ffmpeg::av_freep(&FormatCtx->streams[i]);<br>   }<br><br>   //avio_close(FormatCtx->pb);<br>   //ffmpeg::avformat_free_context(FormatCtx); //sigsegv<br>
   av_free(FormatCtx);<br>   <br>   return true;<br><br>}<br></div>