[Libav-user] Possible memory leak in avformat_find_stream_info, how to deal with it?
Wodzu
brucedickinson at wp.pl
Tue Feb 26 11:57:34 EET 2019
Hello,
I am trying to transmux (remux?) from raw h264 to mp4. My input is in a
stream, output goes to a file. Everything works, but I've noticed that if I
repeat my function multiple times, allocation of memory grows and it is not
entirely released back.
I was able to find first function which is causing me this problems and it
is avformat_find_stream_info. I looked for it in Internet and I saw that
there is a one expected leak of size 24 bytes, but in my tests it goes way
over it.
Here is an example code, stripped to reproduce the leak:
extern "C" {
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
}
#include <iostream>
#include <fstream>
int ReadFunction(void* opaque, uint8_t* buf, int buf_size) noexcept
{
auto& input_stream = *reinterpret_cast<std::istream*>(opaque);
input_stream.read(reinterpret_cast<char*>(buf), buf_size);
if (input_stream.good())
return (int)input_stream.gcount();
else
{
if (input_stream.eof())
return AVERROR_EOF;
else
return AVERROR_EXTERNAL;
}
}
int64_t SeekFunction(void* opaque, int64_t offset, int whence) noexcept
{
auto& me = *reinterpret_cast<std::istream*>(opaque);
switch (whence)
{
case AVSEEK_SIZE:
return AVERROR_EXTERNAL;
case SEEK_SET:
me.seekg(offset, std::ios_base::beg);
return me.good() ? (int64_t)me.tellg() : AVERROR_EXTERNAL;
case SEEK_CUR:
me.seekg(offset, std::ios_base::cur);
return me.good() ? (int64_t)me.tellg() : AVERROR_EXTERNAL;
case SEEK_END:
me.seekg(offset, std::ios_base::end);
return me.good() ? (int64_t)me.tellg() : AVERROR_EXTERNAL;
default:
return AVERROR_EXTERNAL;
}
}
void Transmux(std::istream& input, const std::string& output_file_path)
noexcept
{
AVFormatContext* input_context = avformat_alloc_context();
if (!input_context)
std::cout << "Could not allocate input context.\n";
input_context->flags = AVFMT_FLAG_CUSTOM_IO;
unsigned char* buffer = reinterpret_cast<unsigned char*>(av_malloc(8192));
if (!buffer)
std::cout << "Could not allocate buffer.\n";
AVIOContext* io_context = avio_alloc_context(buffer, 8192, 0,
reinterpret_cast<void*>(static_cast<std::istream*>(&input)), &ReadFunction,
nullptr, &SeekFunction);
if (!io_context)
std::cout << "Could not allocate io context.\n";
input_context->pb = io_context;
if (avformat_open_input(&input_context, "", NULL, NULL) < 0)
std::cout << "Could not open input.\n ";
if (avformat_find_stream_info(input_context, NULL) < 0) // Comment out
this and there is no leak.
std::cout << "Could not find stream info.\n";
av_freep(&io_context->buffer);
avio_context_free(&io_context);
avformat_close_input(&input_context);
}
int main()
{
std::ifstream stream("E:\\Encoder\\libx264_movie.dat", std::ios::binary);
if (stream.fail())
std::cout << "Could not open file.\n ";
for (int Index = 0; Index < 1000; Index++) // More iterations means more
memory allocated but it does not grow linearly.
{
stream.clear();
stream.seekg(0, std::ios_base::beg);
Transmux(stream, "E:\\Encoder\\output.mp4");
}
std::cout << "Finished.\n";
stream.close();
int n;
std::cin >> n;
}
If I comment out avformat_find_stream_info() the amount of allocated memory
at the end of program is always the same regardless of number of times I
repeat Transmux() function.
If I leave avformat_find_stream_info() then not all memory is released back.
The more times I repeat Transmux() the more memory is left allocated. I do
not use Linux and Valgrind, I am not
Experienced enough to do so. I am developing under Windows with libraries
distributed with ffmpeg 4.0.0. I know that my testing for leak is very crude
but it definitely show some pattern.
Take a look:
Iterations Memory (KB)
1 2848
10 3708
100 4040
200 4040
500 4596
1000 5588
Am I not freeing something?
One way of dealing with it (as a workaround) would be to reuse input_context
and io_context without allocating/freeing it but I don't know if this is
possible?
Thanks for any help.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://ffmpeg.org/pipermail/libav-user/attachments/20190226/47722484/attachment.html>
More information about the Libav-user
mailing list