需求
最近做一个项目需要播放一些简单的音频,而这些音频以二进制的形式存储在数据库中。而且需要保证音频的音频播放的实时性。故研究下如何从内存数据中解码音频。
开发
原帖中给的代码已经十分详细了。不过有几个需要注意的点原帖中并未提及。
1.回调函数filliobuffer中的第一个参数
int fillIiobuffer(void * opaque, uint8_t * buf, int bufsize)
回调函数内存读取的回调函数中第一个参数其实是在avio_alloc_context
函数中第四个参数设置的。
在回调函数中回将指针传回。这里可以用来标记一些自定义信息。如在我的实际项目代码中用它来传递数据。
int fillIiobuffer(void * opaque, uint8_t * buf, int bufsize)
{
QByteArray* ba = static_cast<QByteArray*>(opaque);
if (ba == nullptr || ba->isEmpty())
{
return 0;
}
int realSize = 0;
if (bufsize > ba->size())
{
realSize = ba->size();
memset(buf,0,bufsize);
}
else
{
realSize = bufsize;
}
if (!memcpy_s(buf, realSize, ba->data(), realSize))
{
ba->remove(0, realSize);
return realSize;
}
return 0;
}
由于回调函数写成了一个全局函数,而其他操作封装到了一个类里面。这里需要将用来存储实际未解码内存数据的成员变量以指针的形式传入回调函数中。
具体是这样写的。
bool XRealTimePlayer::openAudioBuf(QByteArray ba)
{
m_AudioData = ba;
...
AVIOContext *avio = avio_alloc_context(m_iobuffer, 32768, 0, &m_AudioData, fillIiobuffer, nullptr, nullptr);
m_AVFormatFromBuf->pb = avio;
...
}
2.内存的释放
因为实例需要反复使用,这里就需要进行一些内存释放工作。
经过反复测试发现只有这样做才不会出错,具体为什么,对不对。我也知道,反正目前没有发现内存泄漏。
if (m_AVFormatFromBuf)
{
//av_free(m_iobuffer); //注意这里
avio_context_free(&m_AVFormatFromBuf->pb);
avformat_close_input(&m_AVFormatFromBuf);
avformat_free_context(m_AVFormatFromBuf);
}
m_iobuffer = (unsigned char *)av_malloc(32768);
m_AVFormatFromBuf = avformat_alloc_context();
AVIOContext *avio = avio_alloc_context(m_iobuffer, 32768, 0, &m_AudioData, fillIiobuffer, nullptr, nullptr);
m_AVFormatFromBuf->pb = avio;
应该有些人会注意到,我申请的m_ioBuffer并没有释放。而且这个空间还不小。但它就是没有引起内存泄漏,就是这么神奇。
如果我把它释放了,就是把//av_free(m_iobuffer);这句注释打开的话。在第三次播放的时候必然堆损坏。不知道为什么。
在源码中对avio_alloc_context函数第一个参数的注释是这样的。
/*
* @param buffer Memory block for input/output operations via AVIOContext.
* The buffer must be allocated with av_malloc() and friends.
* It may be freed and replaced with a new buffer by libavformat.
* AVIOContext.buffer holds the buffer currently in use,
* which must be later freed with av_free().
* /
大概意思就是这个参数可能会被一个新的叫libavformat.AVIOContext.buffer的内存空间取代。而且这个libavformat.AVIOContext.buffer需要进行释放。
因此经过再次测试我们需要释放libavformat.AVIOContext.buffer这个变量。
所以释放空间的代码需要这么写
if (m_AVFormatFromBuf)
{
//av_free(m_iobuffer); //注意这里
av_free(m_AVFormatFromBuf->pb->buffer);
avio_context_free(&m_AVFormatFromBuf->pb);
avformat_close_input(&m_AVFormatFromBuf);
avformat_free_context(m_AVFormatFromBuf);
}
m_iobuffer = (unsigned char *)av_malloc(32768);
m_AVFormatFromBuf = avformat_alloc_context();
AVIOContext *avio = avio_alloc_context(m_iobuffer, 32768, 0, &m_AudioData, fillIiobuffer, nullptr, nullptr);
m_AVFormatFromBuf->pb = avio;
原文链接:ffmpeg解码内存中的数据 - 资料 - 我爱音视频网 - 构建全国最权威的音视频技术交流分享论坛
本文福利,领取最新最全C++音视频学习提升资料,内容包括(C/C++,Linux 服务器开发,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓文章底部↓↓↓↓见下面