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);
};
//創(chuàng)建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);
};
//創(chuàng)建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只是其中一種實現,寫好的代碼可以隨意切換編碼器對象。或者策略模式,設計一個編碼器接口,調用時根據編碼格式選擇合適的編碼器??偟膩碚f,這個對象的設計和實現不算特別難,就是在細節(jié)的地方需要注意,比如錯誤提示,邊界值處理等。
以上就是C++使用fdk-aac實現將音頻PCM編碼成aac的詳細內容,更多關于C++音頻編碼的資料請關注腳本之家其它相關文章!
相關文章
C++ 標準庫中的 <algorithm> 頭文件算法操作總結
C++ 標準庫中的 <algorithm> 頭文件提供了大量有用的算法,主要用于操作容器(如 vector, list, array 等),這些算法通常通過迭代器來操作容器元素,本文給大家介紹C++ 標準庫中的 <algorithm> 頭文件算法總結,感興趣的朋友一起看看吧2025-04-04

