Hello everybody, I have a video demuxing / decoding / filter / encoding / muxing process up and running using NDK on Android. During testing, I discovered a continuous heap grow adding roughly 200kB per second of video processed. The value depends on the video resolution which is HD / 720p in my test case. As I have not been able to find the leak running several code reviews, I extracted the code utilized into a test program and compiled / ran it on my Mac desktop. As Valgrind seems to be not supported for MacOSX Maveriks (10.9), I used the leak template from Instruments - which is part of the MacOSX development environment. Here is a screen shot showing the result:
http://www.gps-laptimer.com/Leaks.png
As you can see, Instruments detects 6059 leaks from any av_buffer_realloc ()
calls and additional 12122 smaller ones calling av_mallocz. Oddly, I have not
found a way to include the full caller hierarchy so far, but it seems pretty
obvious the leaks happen with every video frame or packet processed (the test
video has 6275 frames) which is pretty close the 6059 bigger leaks and double
the smaller ones. Please don’t get the red bars wrong, they appear each 10
seconds as this is the leak sampling rate (i.e. aggregated value for last 10
seconds).
Despite the missing caller hierarchy, is anyone able to derive a theory what’s
wrong - especially the av_buffer_realloc ()s? I pulled the ffmpeg sources
today, so they are recent. I have extracted part of the sources (just to show
the pattern used, several placeholders included, all error handling and pts/dts
calculation removed), so maybe someone can point me to issues in my code that
generates the problem:
Code to read one frame, video frames get decoded and translated from native
pixel format to RGB565, audio packets are simply passed through…
AVPacket packet;
av_init_packet (&packet);
packet.data = NULL;
packet.size = 0;
int ret = av_read_frame (videoSource->pFormatCtx, &packet);
while (ret>=0)
{
if (packet.stream_index==videoSource->videoStream)
{
int frameFinished;
ret = avcodec_decode_video2 (videoSource->pVideoCodecCtx,
videoSource->pVideoFrameRaw, &frameFinished, &packet);
if (ret>=0)
{
if (frameFinished)
{
…
if (!videoSource->pImageConvertRGB565Ctx)
videoSource->pImageConvertRGB565Ctx =
sws_getContext (
videoSource->pVideoCodecCtx->width, videoSource->pVideoCodecCtx->height,
videoSource->pVideoCodecCtx->pix_fmt,
videoSource->pVideoCodecCtx->width, videoSource->pVideoCodecCtx->height,
PIX_FMT_RGB565,
SWS_BICUBIC, NULL, NULL, NULL);
sws_scale (videoSource->pImageConvertRGB565Ctx,
videoSource->pVideoFrameRaw->data,
videoSource->pVideoFrameRaw->linesize,
0, videoSource->pVideoCodecCtx->height,
videoSource->pFrameRGB565->data,
videoSource->pFrameRGB565->linesize);
av_frame_unref (videoSource->pVideoFrameRaw);
break;
}
// The packet has been used by the ffmpeg engine (both if
a frame has been finished or not),
// we must free the content now
av_free_packet (&packet);
}
}
else if (packet.stream_index==videoSource->audioStream)
{
// We do not free the packet here as it is used by AssetWriter
(and freed there once it is written)
videoSource->audioPacket = packet;
break;
}
else
av_free_packet (&packet); // Not needed
if (ret>=0)
ret = av_read_frame (videoSource->pFormatCtx, &packet);
}
Code to write changed video frames:
if (!flush)
{
if (!assetWriter->pImageConvertFromRGB565Ctx)
assetWriter->pImageConvertFromRGB565Ctx = sws_getContext (c->width,
c->height, AV_PIX_FMT_RGB565,
c->width,
c->height, c->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
uint8_t *rgb565Data [AV_NUM_DATA_POINTERS] = {
assetWriter->masterVideoSource->pFrameRGB565Buffer, NULL, NULL, NULL };
int rgb565Linesize [AV_NUM_DATA_POINTERS] = { c->width*2 /*linesize
is twice the width*/, 0, 0, 0 };
sws_scale (assetWriter->pImageConvertFromRGB565Ctx,
rgb565Data, rgb565Linesize,
0, c->height, assetWriter->dst_picture.data,
assetWriter->dst_picture.linesize);
}
int got_packet;
AVPacket packet;
av_init_packet (&packet);
packet.data = NULL;
packet.size = 0;
ret = avcodec_encode_video2 (c, &packet, flush?NULL:assetWriter->frame,
&got_packet);
if (got_packet)
{
ret = write_frame (assetWriter,
&assetWriter->masterVideoSource->pFormatCtx->streams
[assetWriter->masterVideoSource->videoStream]->time_base,
assetWriter->video_st, &packet);
}
av_free_packet (&packet);
Code to write unchanged audio packets:
int ret = 0;
ret = write_frame (assetWriter,
&assetWriter->masterVideoSource->pFormatCtx->streams
[assetWriter->masterVideoSource->audioStream]->time_base,
assetWriter->audio_st,
&assetWriter->masterVideoSource->audioPacket);
av_free_packet (&assetWriter->masterVideoSource->audioPacket);
Thanks, and please let me know if you need more input.
Greetings Harald
-
Harald Schlangmann
Antwerpener Str. 52, 50672 Köln, Germany
+49 151 2265 4439
[email protected]
www.gps-laptimer.de
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ Libav-user mailing list [email protected] http://ffmpeg.org/mailman/listinfo/libav-user
