Reputation: 2748
This maddening thread describes the problem I'm having: a memory leak on shutdown due to some stuff allocated when avformat_new_stream
is called.
Here's the valgrind stack trace from the leak:
So clearly the problem is that when a AVFormatContext
's stream's codec context's priv_data
field is somehow not being freed.
My code frees the AVFormatContext
with avformat_free_context
. This calls ff_free_stream
, which calls free_stream
, which frees a few of the stream's codec context fields itself - but not the priv_data
field!
Compared and contrast with the corresponding code in avcodec_close
.
The suggested solution to the problem from the thread: "close the codec firstly before calling av_format_free_context
". Presumably this refers to calling avcodec_free_context
? - but I'm already doing this! Roughly following the structure in the muxing example, I have an encoder context created by my code, that's used to track the uncompressed input data. Then there's another encoder context created internally by avformat_new_stream
(as above), which is used internally by FFmpeg. I close the former, because it was opened using avcodec_open2
, but I don't close the latter, because it wasn't. I am following the maddening thread's advice, and yet here I am.
Furthermore, reading between the lines, using avcodec_free_context
to free the AVStream
's codec context is no good anyway, because when doing this (a) AVStream
's codec
field is deprecated, so this gives a bunch of warnings, and (b) there are no NULL
checks in free_stream
, so this crashes at runtime.
What I have done for now is drag in the appropriate bit of code from avcodec_close
, and put it in my own code just ahead of the call to avformat_free_context
:
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
for(unsigned i=0;i<avf_context->nb_streams;++i) {
AVStream *st=avf_context->streams[i];
if(st->codec->priv_data&&
st->codec->codec&&
st->codec->codec->priv_class)
{
av_opt_free(st->codec->priv_data);
}
av_freep(&st->codec->priv_data);
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
So that fixes the leak, and it's clearly (to my eyes) a bug, and I need to file a bug report or something.
However the corresponding bug report is marked as fixed and closed... along with a link back to the maddening thread, and no further explanation. (This is why it is maddening!) So maybe I'm just using FFmpeg wrongly?
Can anybody confirm whether this is actually a bug in FFmpeg or not?
If it isn't a bug, what's the right sequence of calls to make?
(I'm using FFmpeg built locally from commit 03eb0515c12637dbd20c2e3ca8503d7b47cf583a. I had similar-looking problems with the one you get from the Ubuntu 16 package manager, which prompted me to build it myself with symbols and so on.)
Upvotes: 5
Views: 2712
Reputation: 37600
I think you are using libav API incorrectly. As part of API control mechanism each library has a version.h
file (for example ./libavformat/version.h
) that defines a set of macros controlling public API of that library.
typedef struct AVStream {
int index; /**< stream index in AVFormatContext */
/**
* Format-specific stream ID.
* decoding: set by libavformat
* encoding: set by the user, replaced by libavformat if left unset
*/
int id;
#if FF_API_LAVF_AVCTX
/**
* @deprecated use the codecpar struct instead
*/
attribute_deprecated
AVCodecContext *codec;
#endif
void *priv_data;
#if FF_API_LAVF_FRAC
/**
* @deprecated this field is unused
*/
attribute_deprecated
struct AVFrac pts;
#endif
When you encounter deprecation warnings you should look for corresponding API control macro and compile libav and your code that uses libav with this macro set to 0 (with -DFF_API_LAVF_AVCTX=0
in case of codec
field for example) overriding version.h
content and ensuring that this deprecated API is not used anymore.
Upvotes: 0