avcodec_open2方法中的 FFMPEG 内存泄漏

ffmpeg memory leak in the avcodec_open2 method

本文关键字:FFMPEG 内存 泄漏 open2 方法 avcodec      更新时间:2023-10-16

>我开发了一个处理实时视频流的应用程序。问题是它应该作为服务运行,随着时间的推移,我注意到内存增加了一些。当我使用 valgrind 检查应用程序时 - 它没有发现任何与泄漏相关的问题。 所以我用谷歌个人资料工具检查过。这是运行大约 6 小时后的结果(从最新的转储中减去第一个转储之一(:

30.0  35.7%  35.7%     30.0  35.7% av_malloc
28.9  34.4%  70.2%     28.9  34.4% av_reallocp
24.5  29.2%  99.4%     24.5  29.2% x264_malloc

当我检查我看到的图表上的内存时,这些分配与avcodec_open2有关。客户端代码为:

`           g_EncoderMutex.lock();
ffmpeg_encoder_start(OutFileName.c_str(), AV_CODEC_ID_H264, m_FPS, width, height);
for (pts = 0; pts < VideoImages.size(); pts++) {                
m_frame->pts = pts;
ffmpeg_encoder_encode_frame(VideoImages[pts].RGBimage[0]);
}
ffmpeg_encoder_finish();
g_EncoderMutex.unlock()

ffmpeg_encoder_start方法是:

void VideoEncoder::ffmpeg_encoder_start(const char *filename, int codec_id, int fps, int width, int height)
{
int ret;
m_FPS=fps;
AVOutputFormat * fmt = av_guess_format(filename, NULL, NULL);
m_oc = NULL;
avformat_alloc_output_context2(&m_oc, NULL, NULL, filename);
m_stream = avformat_new_stream(m_oc, 0);
AVCodec *codec=NULL;
codec =  avcodec_find_encoder(codec_id);    
if (!codec) 
{
fprintf(stderr, "Codec not foundn");
return; //-1
}
m_c=m_stream->codec;
avcodec_get_context_defaults3(m_c, codec);
m_c->bit_rate = 400000;
m_c->width = width;
m_c->height = height;
m_c->time_base.num = 1;
m_c->time_base.den = m_FPS;
m_c->gop_size = 10;
m_c->max_b_frames = 1;
m_c->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec_id == AV_CODEC_ID_H264)
av_opt_set(m_c->priv_data, "preset", "ultrafast", 0);
if (m_oc->oformat->flags & AVFMT_GLOBALHEADER) 
m_c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
avcodec_open2( m_c, codec, NULL );
m_stream->time_base=(AVRational){1, m_FPS};
if (avio_open(&m_oc->pb, filename, AVIO_FLAG_WRITE) < 0)
{
printf( "Could not open '%s'n", filename);
exit(1);
}            
avformat_write_header(m_oc, NULL);
m_frame = av_frame_alloc();
if (!m_frame) {
printf( "Could not allocate video framen");
exit(1);
}
m_frame->format = m_c->pix_fmt;
m_frame->width  = m_c->width;
m_frame->height = m_c->height;
ret = av_image_alloc(m_frame->data, m_frame->linesize, m_c->width, m_c->height, m_c->pix_fmt, 32);
if (ret < 0) {
printf("Could not allocate raw picture buffern");
exit(1);
}
}

ffmpeg_encoder_encode_frame是:

void VideoEncoder::ffmpeg_encoder_encode_frame(uint8_t *rgb) 
{
int ret, got_output;
ffmpeg_encoder_set_frame_yuv_from_rgb(rgb);
av_init_packet(&m_pkt);
m_pkt.data = NULL;
m_pkt.size = 0;
ret = avcodec_encode_video2(m_c, &m_pkt, m_frame, &got_output);
if (ret < 0) {
printf("Error encoding framen");
exit(1);
}
if (got_output) 
{
av_packet_rescale_ts(&m_pkt,
(AVRational){1, m_FPS}, m_stream->time_base);
m_pkt.stream_index = m_stream->index;
int ret = av_interleaved_write_frame(m_oc, &m_pkt);
av_packet_unref(&m_pkt);
}
}

ffmpeg_encoder_finish代码为:

void VideoEncoder::ffmpeg_encoder_finish(void) 
{
int got_output, ret;
do {
ret = avcodec_encode_video2(m_c, &m_pkt, NULL, &got_output);
if (ret < 0) {
printf( "Error encoding framen");
exit(1);
}
if (got_output) {
av_packet_rescale_ts(&m_pkt,
(AVRational){1, m_FPS}, m_stream->time_base);
m_pkt.stream_index = m_stream->index;
int ret = av_interleaved_write_frame(m_oc, &m_pkt);
av_packet_unref(&m_pkt);
}
} while (got_output);
av_write_trailer(m_oc);
avio_closep(&m_oc->pb);
avformat_free_context(m_oc);
av_freep(&m_frame->data[0]);
av_frame_free(&m_frame);
av_packet_unref(&m_pkt);
sws_freeContext(m_sws_context);
}

此代码在循环中多次运行。 所以我的问题是 - 我做错了什么?也许FFMPEG正在使用某种内部缓冲?如果是这样,如何禁用它?因为内存使用量的这种增加是完全不可接受的。

你没有关闭编码器上下文。将avcodec_close(m_c)添加到ffmpeg_encoder_finish()

见 ffmpeg.org

用户需要调用 avcodec_close(( 和 avformat_free_context(( 来按 avformat_new_stream(( 清理分配。

另外,我不明白m_c是如何分配的。通常它与avcodec_alloc_context一起分配,并且必须与av_free一起释放(当然在关闭之后(。

不要使用valgrind 来检查你自己项目的内存泄漏,使用消毒剂,有了这些,你可以查明泄漏的来源。看看这个: 多线程视频解码器泄漏内存

希望有帮助。

调用"avcodec_free_context(m_c("就足够了,此过程调用"avcodec_close",并且还取消分配"extradata"(如果已分配(和"subtitle_header"(如果已分配(。