FFmpeg处理音频时AVAudioFifo内存泄漏的解决办法

本文所给出的是在使用AVAudioFifo处理buffer时出现内存泄漏问题的解决办法

受项目的限制,FFmpeg的版本为2.4.6

没有验证新版本是否还有这样的问题,但可以用做参考。

首先以下公共的部分不变:

AVCodecContext* m_pCodecCtx;    //AVCodecContext的初始化部分省略
AVAudioFifo*    m_pAudioFifo;

void init_frame(AVFrame* &pFrame)
{
	//初始化AVFrame
	pFrame = av_frame_alloc();
	pFrame->format = m_pCodecCtx->sample_fmt;
	pFrame->channels = m_pCodecCtx->channels;
	pFrame->channel_layout = m_pCodecCtx->channel_layout;
	pFrame->nb_samples = m_pCodecCtx->frame_size;
	av_frame_get_buffer(pFrame, 0);
}

以下是有内存泄漏的代码:

void FifoDemo(const SW_UINT8* pInputData, SW_UINT32 iSize)
{
    //避免重复定义AVFrame
    AVFrame* pFrame;
    init_frame(pFrame);

    while(1){
        //将输入数据保存到fifo
        av_audio_fifo_write(m_pAudioFifo, (void**)pInputData, nDataSize);

        //释放内存
        if (pInputData)
            av_freep(&pInputData[0]);
        av_freep(pInputData);
        
        if (av_audio_fifo_size(m_pAudioFifo) < m_pCodecCtx->frame_size)
            break;

        //从fifo中读取数据到AVFrame
        av_audio_fifo_read(m_pAudioFifo, (void**)pFrame->data, m_pCodecCtx->frame_size);

        //初始化AVPacket
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.data = NULL;
        pkt.size = 0;

        //将AVFrame中的数据编码到AVPacket
        int got_pkt = 0;
        int ret = avcodec_encode_audio2(m_pCodecCtx, &pkt, pFrame, &got_pkt);
        if (ret < 0 || got_pkt != 1) {
            av_packet_unref(&pkt);
            return false;
        }
       
        //重置AVFrame
        av_frame_unref(&pFrame);
        
        /*使用AVPacket
        ......
        ......*/
        
        //释放AVPacket
        av_packet_unref(&pkt);
    }
    
	av_audio_fifo_free(m_pAudioFifo);
}

以下是没有内存泄漏的代码:

void FifoDemo(const SW_UINT8* pInputData, SW_UINT32 iSize)
{
    while(1){
        //将输入数据保存到fifo
        av_audio_fifo_write(m_pAudioFifo, (void**)pInputData, nDataSize);

        //释放内存
        if (pInputData)
            av_freep(&pInputData[0]);
        av_freep(pInputData);
        
        if (av_audio_fifo_size(m_pAudioFifo) < m_pCodecCtx->frame_size)
            break;

        //从fifo中读取数据到AVFrame
        AVFrame* pFrame;
        init_frame(pFrame);
        av_audio_fifo_read(m_pAudioFifo, (void**)pFrame->data, m_pCodecCtx->frame_size);

        //初始化AVPacket
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.data = NULL;
        pkt.size = 0;

        //将AVFrame中的数据编码到AVPacket
        int got_pkt = 0;
        int ret = avcodec_encode_audio2(m_pCodecCtx, &pkt, pFrame, &got_pkt);
        if (ret < 0 || got_pkt != 1) {
            av_packet_unref(&pkt);
            return false;
        }
        
        //释放AVFrame
        av_frame_free(&pFrame);
        
        /*使用AVPacket
        ......
        ......*/
        
        //释放AVPacket
        av_packet_unref(&pkt);
    }
    
	av_audio_fifo_free(m_pAudioFifo);
}

通过对比可以看出,不同的点只有两处:

1、AVFrame的定义

有内存泄漏:为了避免重复定义和初始化AVFrame,所以只定义了一次,然后每次用完重置。

没有内存泄漏:每次执行av_audio_fifo_read前都重新定义和初始化AVFrame。

2、AVFrame的释放

有内存泄漏:使用av_frame_unref()进行重置。

没有内存泄漏:使用av_frame_free()进行释放。

题主在发现内存泄漏进行排查时,发现问题出在av_audio_fifo_read,前后绕了很久,对比了官网的样例程序才发现上述的使用区别,验证后确认内存泄漏的确出在这里。

虽然内存泄漏的量不会很大,但如果持续运行的时间较长(例如几分钟以上),还是能够很明显的观察到内存泄漏的现象,

而且出于程序开发的严谨性,也应该尽量避免内存泄漏这样危险的现象发生。

 

参考文档

https://ffmpeg.org/doxygen/2.4/transcode_aac_8c-example.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值