【Android RTMP】音頻數據採集編碼 ( FAAC 音頻編碼參數設置 | FAAC 編碼器創建 | 獲取編碼器參數 | 設置 AAC 編碼規格 | 設置編碼器輸入輸出參數 )



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;

注意 : 是樣本個數 , 不是字節數 , 如果採樣位數是 88 位 , 那麼 =字節數 = 樣本個數 , 如果採樣位數是 1616 位 , =×2字節數 = 樣本個數 \times 2 ;


② 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 編碼規格 : 99 種 ;

  • 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 的採樣位數是 1616 位 ;

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];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章