[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