[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