[Libav-user] Memory leak after cropping 300/900 pictures

CHAUVET Guillaume cg85 at hotmail.com
Tue Sep 25 23:17:58 CEST 2012


Hello,
I try to use FFMpeg, this wonderful library through C language. But I encounter a problem : I have 900 pictures to crop, but at the image number 305, my app crash with message "Failed to allocate packet of size 34296000". I stuck because I don't know where is located my memory leak (av_malloc return NULL and my application consume more than 1800 Mb of RAM) ...
Softwares used to build my project :
- Pelles C (32 bits)
- Windows 7 (32 bits)
- ffmpeg-20120919-git-cb3591e-win32-dev.7z and appropriate dlls version (from zeranoe distrib)
 
A snippet from my application :
 
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <dirent.h>
#include <direct.h>
#include <sys/stat.h>
#include "libavcodec/avcodec.h"
#include "libavutil/opt.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
 
typedef struct {
 AVCodec *codec;
 AVCodecContext *context;
 int index;
} DataThumb;
 
static BOOL write_image(AVCodecContext *pCodecCtx, AVFrame *pFrame, char *outfile)
{
  BOOL result = FALSE;
  AVCodecContext *pOCodecCtx = avcodec_alloc_context3(avcodec_find_encoder(pCodecCtx->codec_id));
  //
  // Allocate the output codec context
  //
  if (pOCodecCtx != NULL)
  {
    //
    // Initialise format parameters
    //
    pOCodecCtx->bit_rate = pCodecCtx->bit_rate;
    pOCodecCtx->width = pFrame->width;
    pOCodecCtx->height = pFrame->height;
   pOCodecCtx->pix_fmt = pCodecCtx->pix_fmt;
    pOCodecCtx->codec_id = CODEC_ID_MJPEG;
   pOCodecCtx->time_base = (AVRational) {1, 1};
    pOCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    //
    // Allocate the JPEG encoder
    //
    AVCodec *pOCodec = avcodec_find_encoder(pOCodecCtx->codec_id);
    if (pOCodec != NULL)
    {
     //
    // Open the JPEG encoder
     //
     if (avcodec_open2(pOCodecCtx, pOCodec, NULL) >= 0)
     {
      //
      // Initialise the "VBR" settings
      //
      pOCodecCtx->qmin = pOCodecCtx->qmax = 4;
     pOCodecCtx->mb_lmin = pOCodecCtx->lmin = pOCodecCtx->qmin * FF_QP2LAMBDA;
      pOCodecCtx->mb_lmax = pOCodecCtx->lmax = pOCodecCtx->qmax * FF_QP2LAMBDA;
      pOCodecCtx->flags = CODEC_FLAG_QSCALE;
      pOCodecCtx->global_quality = pOCodecCtx->qmin * FF_QP2LAMBDA;
      //
      // Set the timestamp and quality parameters
      //
      pFrame->pts = 1;
      pFrame->quality = pOCodecCtx->global_quality;
      AVPacket packet;
      av_init_packet(&packet);
      packet.data = NULL;
      packet.size = 0;
      //
      // Write JPEG to file
      //
     FILE *file = fopen(outfile, "wb");
      int got_output;
     if (avcodec_encode_video2(pOCodecCtx, &packet, pFrame, &got_output) < 0)
      {
        result = FALSE;
      }
      else if(got_output)
      {
       fwrite(packet.data, 1, packet.size, file);
      }
      fclose(file);
      av_free_packet(&packet);
     result = TRUE;
     }
   }
    avcodec_close(pOCodecCtx);
  }

 return result;
}

static BOOL sample_crop(char *source, char *destination, FLOAT ratio)
{
  BOOL result = FALSE;
  AVFormatContext *pFormatCtx = avformat_alloc_context();
  if(avformat_open_input(&pFormatCtx, source, NULL, NULL) == 0)
  {
    av_dump_format(pFormatCtx, 0, source, 0);
    AVCodecContext *pCodecCtx = pFormatCtx->streams[0]->codec;
    pCodecCtx->pix_fmt = PIX_FMT_YUV444P;
    AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if(pCodec != NULL)
   {
     if (avcodec_open2(pCodecCtx, pCodec, NULL) >= 0)
    {
      AVFrame *pFrame = avcodec_alloc_frame();
      if(pFrame != NULL)
     {
      // Read frame
       AVPacket packet;
       int frameFinished;
       while (av_read_frame(pFormatCtx, &packet) >= 0)
       {
        if (packet.stream_index == 0)
       {
         if (avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet) > 0)
          {
           pFrame->quality = 4;
           av_free_packet(&packet);
           // Il nous faut déterminer le plus grand rectangle
           // tout en respectant un certain ratio
           int minimum = 0;
           int maximum = pFrame->width;
           do
          {
            int mid = minimum + (maximum + minimum) / 2;
           if(mid / ratio <= pFrame->height)
           {
             minimum = mid + 1;
            }
           else
           {
             maximum = mid - 1;
            }
           } while(maximum < minimum);
           // On a enfin les nouvelles dimensions :
           AVFrame *cropped = avcodec_alloc_frame();
           cropped->width = maximum;
           cropped->height = roundf(maximum / ratio);
           const int left = (int) (pFrame->width-cropped->width) / 2;
           const int top = (int) (pFrame->height-cropped->height) / 2;
           avpicture_alloc((AVPicture *) cropped, pCodecCtx->pix_fmt, cropped->width, cropped->height);
           if(av_picture_crop((AVPicture *) cropped, (AVPicture *) pFrame, pCodecCtx->pix_fmt, top, left) >= 0)
          {
            // L'image est retaillé : on la sauvegarde dans le fichier de sortie
           if(write_image(pCodecCtx, cropped, destination) == TRUE)
           {
             result = TRUE;
            }
           }
           av_free(cropped);
           break;
          }
         }
        }
       av_free(pFrame);
      }
     }
     avcodec_close(pCodecCtx);
    }
  }
  avformat_close_input(&pFormatCtx);
  return result;
}

static DataThumb *sample_open(UINT width, UINT height, enum AVCodecID codec, UINT fps)
{
  DataThumb *result = (DataThumb *)av_malloc(sizeof(DataThumb));
  result->codec = avcodec_find_encoder(codec);
  if (result->codec != NULL)
  {
    result->index = 0;
    result->context = avcodec_alloc_context3(result->codec);
    result->context->width = width;
    result->context->height = height;
    result->context->time_base = (AVRational) {1, fps};
    result->context->pix_fmt = PIX_FMT_YUV444P;
   result->context->bit_rate = 5 * 1000 * 1000;
    result->context->gop_size = fps / 12;
    result->context->max_b_frames = 1;
    if (result->codec->id == AV_CODEC_ID_H264)
     av_opt_set(result->context->priv_data, "preset", "veryslow", 0);
    if (avcodec_open2(result->context, result->codec, NULL) >= 0)
    {
     return result;
    }
  }
 av_free(result);
 return NULL;
}

static void sample_close(DataThumb *tla)
{
 avcodec_close(tla->context);
 av_free(tla);
}
 
#define MAXPATH 10 * 1024
int main(int argc, char *argv[])
{
 if(argc < 3) {
   printf("\n\tusage : %s {input folder} {output folder}\n", argv[0]);
 }
 else
 {
    avcodec_register_all();
    av_register_all();
    DataThumb *tla = sample_open(1920, 1080, AV_CODEC_ID_H264, 25);
    _DIR *d = _opendir(argv[1]);
    if (d)
    {
     int index = 1;
     struct _dirent *dir;
     _mkdir(argv[2]);
     while ((dir = _readdir(d)) != NULL)
     {
      char inputfile[MAXPATH];
      struct _stat statbuf;
      sprintf(inputfile, "%s\\%s", argv[1], dir->d_name);
      _stat(inputfile, &statbuf);
      if(!_S_ISDIR(statbuf.st_mode))
     {
       char outputfile[MAXPATH]; 
      sprintf(outputfile, "%s\\%04d.jpg", argv[2], index);
       sample_crop(inputfile, outputfile, 16. / 9);
       index++;
      }
     }
    _closedir(d);
  }
   sample_close(tla);
 }
 return 0;
}
Sincerly,
Guillaume 		 	   		  


More information about the Libav-user mailing list