文章目錄
Android 直播推流流程 : 手機採集視頻 / 音頻數據 , 視頻數據使用 H.264 編碼 , 音頻數據使用 AAC 編碼 , 最後將音視頻數據都打包到 RTMP 數據包中 , 使用 RTMP 協議上傳到 RTMP 服務器中 ;
視頻推流 : 之前的一系列博客中完成手機端採集視頻數據操作 , 並將視頻數據傳遞給 JNI , 在 NDK 中使用 x264 將圖像轉爲 H.264 格式的視頻 , 最後將 H.264 格式的視頻打包到 RTMP 數據包中 , 上傳到 RTMP 服務器中 ;
音頻推流 : 開始進行音頻直播推流操作 , 先採集音頻 , 將音頻編碼爲 AAC 格式 , 將編碼後的音頻打包成 RTMP 包 , 然後推流到服務器中 ;
NV21 格式圖像編碼爲 H.264 視頻 , 需要設置 x264 編碼器參數 , 對應 【Android RTMP】x264 編碼器初始化及設置 ( 獲取 x264 編碼參數 | 編碼規格 | 碼率 | 幀率 | B幀個數 | 關鍵幀間隔 | 關鍵幀解碼數據 SPS PPS ) 博客 ;
本博客中講解的是 , PCM 音頻採樣編碼爲 AAC 音頻 , 如何設置 FACC 編碼器參數 ;
一、 頭文件、成員變量準備
1 . 導入包 : 使用 FACC 編碼器前 , 必須導入 facc.h 頭文件 ;
#include <faac.h>
2 . 成員變量定義 : 在初始化 FACC 編碼器時 , 需要預先定義一些成員變量 , 這些變量在後續設置編碼器參數 , 音頻編碼時都需要使用到 ;
① 輸入樣本個數 : 輸入到 FAAC 編碼器中的需要進行編碼的 PCM 樣本個數 , 表示FAAC 編碼器最多一次可以接收的樣本個數 ,
unsigned long mInputSamples;
注意 : 是樣本個數 , 不是字節數 , 如果採樣位數是 位 , 那麼 , 如果採樣位數是 位 , ;
② FAAC 編碼器最大輸出字節數 : 該參數 mMaxOutputBytes 與上面的 mInputSamples 都要傳入 FAAC 編碼器創建函數中 , 用於接收創建 FAAC 編碼器後的返回值 , 創建之前這些值是不知道的 ;
unsigned long mMaxOutputBytes;
③ FAAC 編碼器 : 用於將 PCM 音頻採樣編碼成 AAC 格式 ;
faacEncHandle mFaacEncHandle;
④ FAAC 編碼輸出緩衝區 : FAAC 編碼後的 AAC 裸數據, 存儲到該緩衝區中 , 該緩衝區在初始化 FAAC 編碼器時創建 ; 初始化完成後 , 知道 FAAC 最大輸出緩衝區大小後 , 創建該輸出緩衝區 , 其大小是 mMaxOutputBytes 字節 ;
unsigned char* mFaacEncodeOutputBuffer;
二、 創建 FAAC 編碼器
1 . 調用 faacEncOpen 函數 , 創建 FAAC 編碼器 ;
2 . 函數原型解析 :
faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate,
unsigned int numChannels,
unsigned long *inputSamples,
unsigned long *maxOutputBytes
);
① unsigned long sampleRate 參數 : 音頻採樣率 ;
② unsigned int numChannels 參數 : 音頻通道參數 ;
③ unsigned long *mInputSamples 參數 : 輸入樣本個數, 需要進行編碼的 PCM 音頻樣本個數 , FAAC 編碼器最多一次可以接收的樣本個數 ;
④ unsigned long *mMaxOutputBytes 參數 : 輸出數據最大字節數 ;
⑤ faacEncHandle 返回值 : FAAC 音頻編碼器 ;
3 . 創建 FAAC 編碼器 代碼示例 :
mFaacEncHandle = faacEncOpen(sampleRateInHz, channelConfig, &mInputSamples, &mMaxOutputBytes);
三、 獲取並設置 FAAC 編碼器參數
1 . 獲取編碼器參數 : 先獲取參數, 然後設置參數, 最後再設置回去
faacEncConfigurationPtr configurationPtr = faacEncGetCurrentConfiguration(mFaacEncHandle);
2 . 設置編碼器參數 : 爲 mFaacEncHandle 音頻編碼器設置 configurationPtr 編碼器參數
faacEncSetConfiguration(mFaacEncHandle, configurationPtr);
先獲取 FAAC 編碼器參數 faacEncConfigurationPtr 結構體 , 然後設置編碼器參數 , 最後再將編碼器參數 設置回 FAAC 編碼器 FaacEncHandle ;
四、 設置 FAAC 編碼器編碼標準
設置 FAAC 編碼器編碼標準 : 可以設置 MPEG2 , 或 MPEG4 , 目前一般設置 MPEG4 標準 ;
// 設置編碼格式標準, 使用 MPEG4 新標準
configurationPtr->mpegVersion = MPEG4;
五、 設置 FAAC 編碼器 AAC 編碼規格
1 . AAC 編碼規格 : 種 ;
- MPEG-2 AAC LC低複雜度規格(Low Complexity)
- MPEG-2 AAC Main主規格
- MPEG-2 AAC SSR可變採樣率規格(Scaleable Sample Rate)
- MPEG-4 AAC LC低複雜度規格(Low Complexity)
- MPEG-4 AAC Main主規格, MPEG-4 AAC SSR可變採樣率規格(Scaleable Sample Rate)
- MPEG-4 AAC LTP長時期預測規格(Long Term Predicition)
- MPEG-4 AAC LD低延遲規格(Low Delay)
- MPEG-4 AAC HE高效率規格(High Efficiency)
2 . 這裏選擇低複雜度規格 : MPEG-4 AAC LC低複雜度規格(Low Complexity) 是最常用的 AAC 編碼規格, 即兼顧了編碼效率, 有保證了音質;
( 使用更高音質, 極大降低編碼效率, 音質提升效果有限 ; 再提升編碼效率, 會使音質降低很多 )
configurationPtr->aacObjectType = LOW;
六、 設置 FAAC 編碼器輸入、輸出格式
1 . 設置編碼器的輸入格式 : 這裏設置輸入的 PCM 的採樣位數是 位 ;
configurationPtr->inputFormat = FAAC_INPUT_16BIT;
2 . 設置編碼器的輸出格式 : 這裏設置輸出格式 0, 就是 FAAC 將 PCM 採樣進行編碼, 編碼出的格式是 AAC 原始數據 , 即沒有解碼信息的 ADIF 和 ADTS 的 AAC 純樣本裸數據 ;
configurationPtr->outputFormat = 0;
參考 【Android RTMP】音頻數據採集編碼 ( AAC 音頻格式解析 | FLV 音頻數據標籤解析 | AAC 音頻數據標籤頭 | 音頻解碼配置信息 ) 博客的 AAC 格式音頻解析 , AAC 有兩種格式 :
- 音頻數據交換格式 ( Audio Data Interchange Format )
- 音頻數據傳輸流格式 ( Audio Data Transport Stream )
此處使用的不是上述兩種格式的任意一種 , 而是 AAC 的純樣本裸數據 ;
七、 FAAC 設置音頻編碼參數代碼
1 . 成員變量定義代碼 :
/**
* 輸入樣本個數, 需要進行編碼的 PCM 音頻樣本個數
* FAAC 編碼器最多一次可以接收的樣本個數
* 傳遞下面兩個數值的地址到 faacEncOpen 函數中, 用於當做返回值使用
*
* 該數據需要返回給 Java 層
* Java 層每次從 AudioRecord 中讀取 mInputSamples 個數據
*/
unsigned long mInputSamples;
/**
* FAAC 編碼器最多一次可以接收的樣本個數
* 傳遞下面兩個數值的地址到 faacEncOpen 函數中, 用於當做返回值使用
*/
unsigned long mMaxOutputBytes;
/**
* PCM 音頻 FAAC 編碼器
* 將 PCM 採樣數據編碼成 FAAC 編碼器
*/
faacEncHandle mFaacEncHandle;
/**
* FAAC 編碼輸出緩衝區
* FAAC 編碼後的 AAC 裸數據, 存儲到該緩衝區中
* 該緩衝區在初始化 FAAC 編碼器時創建
*/
unsigned char* mFaacEncodeOutputBuffer;
2 . FACC 編碼器參數初始化代碼 :
/**
* 設置音頻編碼參數
* @param sampleRateInHz 音頻採樣率
* @param channelConfig 音頻採樣通道, 單聲道 / 立體聲
*/
void AudioChannel::setAudioEncoderParameters(int sampleRateInHz, int channelConfig) {
// 設置音頻通道參數, 單聲道 / 立體聲
mChannelConfig = channelConfig;
/*
打開編碼器
faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate,
unsigned int numChannels,
unsigned long *mInputSamples,
unsigned long *mMaxOutputBytes);
unsigned long sampleRate 參數 : 音頻採樣率
unsigned int numChannels 參數 : 音頻通道參數
unsigned long *mInputSamples 參數 : 輸入樣本個數, 需要進行編碼的 PCM 音頻樣本個數
FAAC 編碼器最多一次可以接收的樣本個數
unsigned long *mMaxOutputBytes 參數 : 輸出數據最大字節數
faacEncHandle 返回值 : FAAC 音頻編碼器
注意上述 樣本個數, 字節個數 區別 : 16 位採樣位數, 一個樣本有 2 字節
*/
mFaacEncHandle = faacEncOpen(sampleRateInHz, channelConfig, &mInputSamples, &mMaxOutputBytes);
// 獲取編碼器當前參數
// 先獲取參數, 然後設置參數, 最後再設置回去
faacEncConfigurationPtr configurationPtr = faacEncGetCurrentConfiguration(mFaacEncHandle);
// 設置編碼格式標準, 使用 MPEG4 新標準
configurationPtr->mpegVersion = MPEG4;
/*
設置 AAC 編碼規格, 有 9 種
MPEG-2 AAC LC低複雜度規格(Low Complexity), MPEG-2 AAC Main主規格, MPEG-2 AAC SSR可變採樣率規格(Scaleable Sample Rate)
MPEG-4 AAC LC低複雜度規格(Low Complexity), MPEG-4 AAC Main主規格, MPEG-4 AAC SSR可變採樣率規格(Scaleable Sample Rate)
MPEG-4 AAC LTP長時期預測規格(Long Term Predicition), MPEG-4 AAC LD低延遲規格(Low Delay), MPEG-4 AAC HE高效率規格(High Efficiency)
這裏選擇低複雜度規格, 可選參數有 4 種
MPEG-4 AAC LC低複雜度規格(Low Complexity) 是最常用的 AAC 編碼規格, 即兼顧了編碼效率, 有保證了音質;
使用更高音質, 極大降低編碼效率, 音質提升效果有限
再提升編碼效率, 會使音質降低很多
*/
configurationPtr->aacObjectType = LOW;
// 採樣位數 16 位
configurationPtr->inputFormat = FAAC_INPUT_16BIT;
/*
AAC 音頻文件有兩種格式 ADIF 和 ADTS
AAC 文件解碼時 : 音頻解碼信息定義在頭部, 後續音頻數據解碼按照音頻數據長度
音頻數據交換格式 ( Audio Data Interchange Format ) , 只有一份音頻解碼信息 , 存儲在文件開頭
這種格式適合存儲音頻文件 , 節省空間 , 但是必須從開始播放纔可以 , 從中間位置無法播放 ;
音頻數據傳輸流格式 ( Audio Data Transport Stream ) , 每隔一段音頻數據
就會有一份音頻解碼信息 , 這種格式適合音頻流傳輸 , 可以在任何位置開始解碼播放 ;
RTMP 推流時, 不使用上述兩種格式
推流視頻時, 先將 SPS, PPS 解碼數據包的信息推流到服務器上
推流音頻時, 也是將解碼相關的數據先推流到服務器中
AAC 編碼時, 會編碼成 ADTS 數據
但是推流音頻時, 推流的是 AAC 裸數據, 需要將 ADTS 音頻格式中的頭信息去掉
博客中截圖 FLV 第一幀 AAC 音頻數據標籤 和 後續 AAC 音頻數據標籤
這裏設置輸出格式 0, 就是 FAAC 將 PCM 採樣進行編碼, 編碼出的格式是 AAC 原始數據
即沒有解碼信息的 ADIF 和 ADTS 的 AAC 純樣本裸數據
*/
configurationPtr->outputFormat = 0;
// 爲 mFaacEncHandle 音頻編碼器設置 configurationPtr 編碼器參數
faacEncSetConfiguration(mFaacEncHandle, configurationPtr);
// 初始化輸出緩衝區, 保存 FAAC 編碼輸出數據
mFaacEncodeOutputBuffer = new unsigned char[mMaxOutputBytes];
}