[Libav-user] Memory leak reading videos
Matheus Henrique Klem Galvez
mhkgalvez at gmail.com
Tue Jun 4 17:41:29 CEST 2013
Hi all,
I am developing a C++ class that stands between two media libraries, namely
OpenCV and the very ffmpeg. The aim is simple: to read uncompressed .avi
videos with ffmpeg and send frames to OpenCV format in order that OpenCV
might be able to process these frames.
The reason why I am doing such a class rather than doing everything using
OpenCV is that there is a bug with OpenCV still unresolved (as the best of
my knowledge tells me). This bug unfortunately makes the application using
OpenCV crash when trying to read an uncompressed video like those I have to
read.
So, I learned the basics of ffmpeg and was able to develop, compile and run
an application that reads these videos and saves the frames into hard disk,
if I want. The question is that I tested my functions in a loop and
figured out that there is a huge leak of memory: the memory space allocated
increases very fast.
The structure of the code inside the loop is that:
1) Open file and initialize ffmpeg structures and variables
2) Read 10 frames from the file
3) Close file and release ffmpeg structures and variables
I developed Open() and Close() functions specially to avoid memory
accumulation but for some reason I am not being able to release properly
all ffmpeg resources. I tested the loop without Open() and Close() and it
works properly, so the leak is inside these functions and not inside
reading routine.
Here follows my Open() and Close() routines:
Notice: you will not see the function av_register_all() in my open() code.
It is called inside the class constructor.
Open():
void VideoInterface::open(string filePath) {
// Check if it is already open
if (openSuccess) {
throw GeneralException("There is an already open video in this
interface.");
}
// Open video file
if (avformat_open_input(&formatCtx, filePath.c_str(), NULL, NULL) != 0)
{
throw OpenVideoException("Video could not be open.");
}
//Retrieve stream information
if (avformat_find_stream_info(formatCtx, NULL) < 0) {
throw OpenVideoException("Could not ind stream information for the
given video.");
}
// Find first video stream
vStreamIndex = -1;
for (int i = 0; i < formatCtx->nb_streams; ++i) {
if (formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
vStreamIndex = i;
break;
}
}
if (vStreamIndex == -1) {
throw OpenVideoException("Could not find a video stream.");
}
// Get a pointer to the codec context for the video stream
codecCtx = formatCtx->streams[vStreamIndex]->codec;
/*------------------------------*/
//Grabbing useful information
double duration = ((double) formatCtx->duration)/AV_TIME_BASE;
double fps = 1/av_q2d(codecCtx->time_base);
int frameCount = duration * fps;
/*cout << "Numerator:\t" << codecCtx->time_base.num << endl;
cout << "Denominator:\t" << codecCtx->time_base.den << endl;
cout << "FPS:\t\t" << fps << endl;
cout << "Duration:\t" << duration << " secs." << endl;
cout << "Frame count:\t" << frameCount << endl;*/
// Fill VideoInformation structure
vinfo->duration = duration;
vinfo->fps = fps;
vinfo->frameCount = frameCount;
/*------------------------------*/
// Find the decoder for the video stream
codec = avcodec_find_decoder(codecCtx->codec_id);
if (codec == NULL) {
throw OpenVideoException("Unsuported codec!");
}
// Open codec
AVDictionary *options = NULL;
if (avcodec_open2(codecCtx, codec, &options) < 0) {
throw OpenVideoException("Could not open codec!");
}
/*------- Prepare interface for first reading -------*/
// Allocate an AVFrame structure
frame = avcodec_alloc_frame();
frameRGB = avcodec_alloc_frame();
if (frameRGB == NULL or frame == NULL) {
throw OpenVideoException("Not able to allocate frame space.");
}
// Determine required buffer size and allocate buffer
int numBytes = avpicture_get_size(PIX_FMT_RGB24, codecCtx->width,
codecCtx->height);
rawData = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
sws_ctx = sws_getContext(codecCtx->width, codecCtx->height,
codecCtx->pix_fmt, codecCtx->width, codecCtx->height,
PIX_FMT_RGB24,
SWS_BILINEAR, NULL, NULL, NULL);
// Assign appropriate parts of buffer to image planes in pFrameRGB
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture*) frameRGB, rawData, PIX_FMT_RGB24,
codecCtx->width, codecCtx->height);
openSuccess = true;
}
Close():
void VideoInterface::close() {
// Free buffer
av_free(rawData);
// Free the RGB image
av_free(frameRGB);
// Free the YUV frame
av_free(frame);
// Free packet
av_free_packet(&packet);
// Close Codec context
avcodec_close(codecCtx);
// Close Format context
avformat_close_input(&formatCtx);
// Reinit class variables (not ffmpeg at all, and not any dynamically
allocate memory as well)
init();
}
One possible reason for my problem is that I found out that
avcodec_close(AvCodecContext*) only frees AVCodecContext content, and not
the variable itself. After it I tried to call av_free(codecCtx) but it
generated an error. So, a first approach would be: how can one completely
release AVCodecContext variables?
Thank you all!
--
--
Matheus Henrique Klem Galvez
The Catholic University of America, Washington, DC
Universidade Federal do Rio de Janeiro, Rio de Janeiro, Brasil
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20130604/f72aaab2/attachment.html>
More information about the Libav-user
mailing list