C++使用fdk-aac实现将音频PCM编码成aac
前言
mp4的音频流通常是aac编码,我们做音视频采集的时候就需要将,采集的音频PCM编码成aac,然后再打包进mp4,而aac编解码库中fdk-aac是性能较好的,使用方式也比较简单。在C++项目中使用,通常再做一层封装,提高模块的复用性和替换性。本文将展示C++将fdk-aac封装成一个编码对象,以及使用示例。
一、接口设计
由于我前面的文章已经给出了fdk-aac的使用示例:《Windows上使用vs编译fdk-aac》,所以在这里直接设计对象的接口。
/// <summary> /// aac编码对象 /// 所有方法采用异常处理进行错误提示,使用时注意使用try-catch,抛出对象为std::exception。 /// 构造方法参数的声道数是最大缓存数量,并非实际声道数,实际声道数由SetChannelMode方法确定,本版本需要确保SetChannelMode的声道数与构造方法参数的声道数一致。 /// </summary> class FdkaacEncoder { public: /// <summary> /// 编码数据到达事件参数 /// </summary> class EncodedDataArrivedEventArgs { public: /// <summary> /// 音频帧 /// </summary> AudioCodingFrame Frame; }; /// <summary> /// 编码数据到达事件 /// </summary> std::function<void(void*,EncodedDataArrivedEventArgs*)> EncodedDataArrived; /// <summary> /// 构造方法 /// </summary> /// <param name="">编码参数</param> FdkaacEncoder(SoundFormat format); /// <summary> /// 析构方法 /// </summary> ~FdkaacEncoder(); /// <summary> /// 获取声音格式 /// </summary> /// <returns>声音格式</returns> SoundFormat GetSoundFormat(); /// <summary> /// 设置比特率 /// </summary> /// <param name="value">比特率,单位byte</param> void SetBitrate(int value); /// <summary> /// 获取比特率 /// </summary> /// <returns>比特率,单位byte</returns> int GetBitrate(); /// <summary> /// 设置封装类型 /// </summary> /// <param name="value">封装类型</param> void SetTransportType(TransportType value); /// <summary> /// 获取封装类型 /// </summary> /// <returns>封装类型</returns> TransportType GetTransportType(); /// <summary> /// 设置比特率模式(CBR、VBR) /// </summary> /// <param name="value">比特率模式</param> void SetBitrateMode(BitrateModde value); /// <summary> /// 获取比特率模式(CBR、VBR) /// </summary> /// <returns>比特率模式</returns> BitrateModde GetBitrateMode(); /// <summary> /// 设置声道顺序 /// </summary> /// <param name="value">声道顺序</param> void SetChannelOrder(ChannelOrder value); /// <summary> /// 获取声道顺序 /// </summary> /// <returns>声道顺序</returns> ChannelOrder GetChannelOrder(); /// <summary> /// 设置声道模式,声道数需要小于等于构造方法设置的声道数。 /// </summary> /// <param name="value">声道模式</param> void SetChannelMode(ChannelMode value); /// <summary> /// 获取声道模式 /// </summary> /// <returns></returns> ChannelMode GetChannelMode(); /// <summary> /// 设置频段复制模式 /// </summary> /// <param name="value">频段复制模式</param> void SetSbrMode(SbrMode value); /// <summary> /// 获取频段复制模式 /// </summary> /// <returns>频段复制模式</returns> SbrMode GetSbrMode(); /// <summary> /// 设置AOT /// </summary> /// <param name="">AOT</param> void SetAudioObjectType(AudioObjectType); /// <summary> /// 获取AOT /// </summary> /// <returns>AOT</returns> AudioObjectType GetAudioObjectType(); /// <summary> /// 写入音频数据 /// 注意数据长度不能过大,否则导致音频不正常,建议2048。 /// </summary> /// <param name="data">音频数据</param> /// <param name="dataLength">数据长度</param> void Write(unsigned char* data, int dataLength); }
二、使用示例
将wav文件编码成acc文件。其中WavFileReader对象参考:《C++ 读取wav文件中的PCM数据》
1.双声道
#include<stdio.h> #include<exception> #include"WavFileReader.h" #include"FdkaacEncoder.h" void main(int argc, char* argv[]) { FILE* f=nullptr; try { //wav文件读取对象 AC::WavFileReader wr; //aac编码对象 //其中参数的声道数是最大缓存数量,并非实际声道数,实际声道数由SetChannelMode方法确定,本版本需要确保SetChannelMode的声道数与构造方法参数的声道数一致。 AC::FdkaacEncoder fe({ 2 ,44100 ,16 }); unsigned char buf[2048]; //设置参数 fe.SetSbrMode(AC::SbrMode_Disable); fe.SetAudioObjectType(AC::AudioObjectType::AUDIOOBJECTTYPE_AAC_LC); fe.SetBitrate(128 * 1024); fe.SetChannelMode(AC::ChannelMode::CHANNELMODE_2); fe.SetChannelOrder(AC::CHANNELORDER_WAV); fe.SetBitrateMode(AC::BitrateModde::BITRATEMODDE_CBR); fe.SetTransportType(AC::TRANSPORTTYPE_MP4_ADTS); //注册编码数据到达事件 fe.EncodedDataArrived = [&](auto s, auto e) { //将得到的编码数据写入文件 fwrite(e->Frame.Data, 1, e->Frame.DataLength, f); }; //创建aac文件 f = fopen("test_music.aac", "wb+"); if (!f) { throw std::exception("create aac file fail,create name:test_music.aac"); } //打开wav文件 if (!wr.OpenWavFile("test_music.wav")) { throw std::exception("open wav file fail,filename:test_music.wav"); } while (1) { //读取wav中的pcm数据 int size = wr.ReadData(buf, 2048); if (size < 1) break; //将pcm数据写入编码器 fe.Write(buf, size); } printf("encode completed\n"); } catch(std::exception e){ printf("%s\n",e.what()); } catch (...) { printf("unknown errror\n"); } if(f) fclose(f); }
2.单声道
#include<stdio.h> #include<exception> #include"WavFileReader.h" #include"FdkaacEncoder.h" void main(int argc, char* argv[]) { FILE* f = nullptr; try { //wav文件读取对象 AC::WavFileReader wr; //aac编码对象 //其中参数的声道数是最大缓存数量,并非实际声道数,实际声道数由SetChannelMode方法确定,本版本需要确保SetChannelMode的声道数与构造方法参数的声道数一致。 AC::FdkaacEncoder fe({ 1 ,44100 ,16 }); unsigned char buf[2048]; //设置参数 fe.SetSbrMode(AC::SbrMode_Disable); fe.SetAudioObjectType(AC::AudioObjectType::AUDIOOBJECTTYPE_AAC_LC); fe.SetBitrate(128 * 1024); fe.SetChannelMode(AC::ChannelMode::CHANNELMODE_1); fe.SetChannelOrder(AC::CHANNELORDER_WAV); fe.SetBitrateMode(AC::BitrateModde::BITRATEMODDE_CBR); fe.SetTransportType(AC::TRANSPORTTYPE_MP4_ADTS); //注册编码数据到达事件 fe.EncodedDataArrived = [&](auto s, auto e) { //将得到的编码数据写入文件 fwrite(e->Frame.Data, 1, e->Frame.DataLength, f); }; //创建aac文件 f = fopen("test_music_1ch441s16b.aac", "wb+"); if (!f) { throw std::exception("create aac file fail,create name:test_music_1ch441s16b.aac"); } //打开wav文件 if (!wr.OpenWavFile("test_music_1ch441s16b.wav")) { throw std::exception("open wav file fail,filename:test_music_1ch441s16b.wav"); } while (1) { //读取wav中的pcm数据 int size = wr.ReadData(buf, 2048); if (size < 1) break; //将pcm数据写入编码器 fe.Write(buf, size); } printf("encode completed\n"); } catch (std::exception e) { printf("%s\n", e.what()); } catch (...) { printf("unknown errror\n"); } if (f) fclose(f); }
总结
以上就是今天要讲的内容,将编码器设计成对象可以灵活的使用在项目中,尤其需要使用设计模式,比如原型模式:一个aac编码器接口可以有不同的实现fdk-aac只是其中一种实现,写好的代码可以随意切换编码器对象。或者策略模式,设计一个编码器接口,调用时根据编码格式选择合适的编码器。总的来说,这个对象的设计和实现不算特别难,就是在细节的地方需要注意,比如错误提示,边界值处理等。
以上就是C++使用fdk-aac实现将音频PCM编码成aac的详细内容,更多关于C++音频编码的资料请关注脚本之家其它相关文章!
最新评论