音頻編碼實戰

隨著5G時代的到來,音視頻領域將會大放異彩。

5G讓所有人興奮,用戶期待,因為5G網絡更快更穩定延遲更低。運營商和上下游產業也期待,大家都想在5G時代分一杯羹。

近幾年抖音快手B站等App的火熱,已經說明問題了。隨著WiFi設施的全面普及,流量費用的進一步下降,使得我們隨時隨地刷視頻成為了可能。回想起我大學時代,那個時候流量很貴,貴到什麼程度呢?1M流量要10塊錢!大家想一想,1M流量10塊錢,1G流量1萬塊錢,你還敢用4G刷視頻麼?4G時代,大家刷短視頻,5G時代,大家刷長視頻。基於這個判斷,音視頻相關技術是未來幾年的熱點,除了抖音快手,新的現象級客戶端有可能會出現。

作為移動開發人員,如何跟上熱點學習音視頻技術呢?

音頻編碼實戰

今天來說說音頻編碼實戰

FFmpeg流程

從本地文件讀取PCM數據進行AAC格式編碼,然後將編碼後的AAC數據存儲到本地文件。

示例的流程如下所示。

音頻編碼實戰

關鍵函數說明:

  • avcodec_find_encoder:根據指定的AVCodecID查找註冊的編碼器。
  • avcodec_alloc_context3:為AVCodecContext分配內存。
  • avcodec_open2:打開編碼器。
  • avcodec_send_frame:將AVFrame非壓縮數據給編碼器。
  • avcodec_receive_packet:獲取到編碼後的AVPacket數據,收到的packet需要自己釋放內存。
  • av_frame_get_buffer: 為音頻或視頻幀分配新的buffer。在調用這個函數之前,必須在AVFame上設置好以下屬性:format(視頻為像素格式,音頻為樣本格式)、nb_samples(樣本個數,針對音頻)、channel_layout(通道類型,針對音頻)、width/height(寬高,針對視頻)。
  • av_frame_make_writable:確保AVFrame是可寫的,使用av_frame_make_writable()的問題是,在最壞的情況下,它會在您使用encode再次更改整個輸入frame之前複製它. 如果frame不可寫,
  • av_frame_make_writable()將分配新的緩衝區,並複製這個輸入input frame數據,避免和編碼器需要緩存該幀時造成衝突。
  • av_samples_fill_arrays 填充音頻幀


對於 flush encoder的操作:

編碼器通常的沖洗方法:調用一次 avcodec_send_frame(NULL)(返回成功),然後不停調用

avcodec_receive_packet() 直到其返回 AVERROR_EOF,取出所有緩存幀,

2avcodec_receive_packet() 返回 AVERROR_EOF 這一次是沒有有效數據的,僅僅獲取到一

個結束標誌

PCM樣本格式

PCM(Pulse Code Modulation,脈衝編碼調製)音頻數據是未經壓縮的音頻採樣數據裸流,它是由模擬信

號經過採樣、量化、編碼轉換成的標準數字音頻數據。

描述PCM數據的6個參數:

1. Sample Rate : 採樣頻率。8kHz(電話)、44.1kHz(CD)、48kHz(DVD)。

2. Sample Size : 量化位數。通常該值為16-bit。

3. Number of Channels : 通道個數。常用的音頻有立體聲(stereo)和單聲道(mono)兩種類型,立體聲包

含左聲道和右聲道。另外還有環繞立體聲等其它不太常用的類型。

4. Sign : 表示樣本數據是否是有符號位,比如用一字節表示的樣本數據,有符號的話表示範圍為-128 ~

127,無符號是0 ~ 255。有符號位16bits數據取值範圍為-32768~32767。

5. Byte Ordering : 字節序。字節序是little-endian還是big-endian。通常均為little-endian。字節序說

明見第4節。

6. Integer Or Floating Point : 整形或浮點型。大多數格式的PCM樣本數據使用整形表示,而在一些對

精度要求高的應用方面,使用浮點類型表示PCM樣本數據(浮點數 float值域為 [-1.0, 1.0])。

推薦的PCM數據播放工具:

ffplay, 使用示例如下:

<code>1 //播放格式為f32le,雙聲道,採樣頻率48000Hz的PCM數據
2 ffplay -f f32le -ac 2 -ar 48000 pcm_audio/<code> 
  • Audacity:一款免費開源的跨平臺音頻處理軟件。
  • Adobe Auditon。導入原始數據,打開的時候需要選擇採樣率、格式和字節序。

FFmpeg支持的PCM數據格式

使⽤ffmpeg -formats命令,獲取ffmpeg支持的音視頻格式,其中我們可以找到支持的PCM格式。

<code>1 DE alaw PCM A-law
2 DE f32be PCM 32-bit floating-point big-endian
3 DE f32le PCM 32-bit floating-point little-endian
4 DE f64be PCM 64-bit floating-point big-endian
5 DE f64le PCM 64-bit floating-point little-endian
6 DE mulaw PCM mu-law
37 DE s16be PCM signed 16-bit big-endian
8 DE s16le PCM signed 16-bit little-endian
9 DE s24be PCM signed 24-bit big-endian
10 DE s24le PCM signed 24-bit little-endian
11 DE s32be PCM signed 32-bit big-endian
12 DE s32le PCM signed 32-bit little-endian
13 DE s8 PCM signed 8-bit
14 DE u16be PCM unsigned 16-bit big-endian
15 DE u16le PCM unsigned 16-bit little-endian
16 DE u24be PCM unsigned 24-bit big-endian
17 DE u24le PCM unsigned 24-bit little-endian
18 DE u32be PCM unsigned 32-bit big-endian
19 DE u32le PCM unsigned 32-bit little-endian
20 DE u8 PCM unsigned 8-bit/<code>

s是有符號,u是無符號,f是浮點數。

be是大端,le是小端。

FFmpeg中Packed和Planar的PCM數據區別

FFmpeg中音視頻數據基本上都有Packed和Planar兩種存儲存式,對於雙聲道音頻來說,

Packed方式為兩個聲道的數據交錯存儲;Planar方式為兩個聲道分開存儲。假設一個L/R為⼀

個採樣點,數據存儲的方式如下所示:

  • Packed: L R L R L R L R
  • Planar: L L L L ... R R R R...

packed格式

<code>1 AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
2 AV_SAMPLE_FMT_S16, ///< signed 16 bits
3 AV_SAMPLE_FMT_S32, ///< signed 32 bits
4 AV_SAMPLE_FMT_FLT, ///< float
5 AV_SAMPLE_FMT_DBL, ///< double/<code>

只能保存在AVFrame的uint8_t *data[0];

音頻保持格式如下:

<code>LRLRLR.../<code>

planar為FFmpeg內部存儲音頻使的採樣格式,所有的Planar格式後都有字P標識。

<code>1 AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
2 AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
3 AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
4 AV_SAMPLE_FMT_FLTP, ///< float, planar
5 AV_SAMPLE_FMT_DBLP, ///< double, planar
6 AV_SAMPLE_FMT_S64, ///< signed 64 bits
7 AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar/<code>

plane 0: LLLLLLLLLLLLLLLLLLLLLLLLLL...

plane 1: RRRRRRRRRRRRRRRRRRRR....

plane 0對於uint8_t *data[0];

plane 1對於uint8_t *data[1];

FFmpeg默認的AAC編碼器不⽀持AV_SAMPLE_FMT_S16格式的編碼,只支持

AV_SAMPLE_FMT_FLTP,這種格式是按平面存儲,樣點是float類型,所謂平面也就是

<code>每個聲道單獨存儲.如左聲道存儲到data[0]中,右聲道存儲到data[1]中。/<code> 

FFmpeg音頻解碼後和編碼前的數據是存放在AVFrame結構中的。

  • Packed格式,frame.data[0]或frame.extended_data[0]包含所有的音頻數據中。
  • Planar格式,frame.data[i]或者frame.extended_data[i]表示第i個聲道的數據(假設聲道0是第一個), AVFrame.data數組大小固定為8,如果聲道數超過8,需要從frame.extended_data獲取聲道數據。

補充說明

  • Planar模式是ffmpeg內部存儲模式,我們實際使用 的音頻文件都是Packed模式的。
  • FFmpeg解碼不同格式的音頻輸出的音頻採樣格式不是一樣。測試發現,其中AAC解碼輸出的數據為浮點型的 AV_SAMPLE_FMT_FLTP 格式,MP3解碼輸出的數據為 AV_SAMPLE_FMT_S16P 格式(使用的mp3文件為16位深)。具體採樣格式可以查看解碼後的AVFrame中的format成員或編解碼器的AVCodecContext中的sample_fmt成員。
  • Planar或者Packed模式直接影響到保存文件時寫文件的操作,操作數據的時候一定要先檢測音頻採樣格式。

PCM字節序

談到字節序的問題,必然牽涉到兩大CPU派系。那就是Motorola的PowerPC系列CPU和Intel的x86系列

CPU。PowerPC系列採用big endian方式存儲數據,而x86系列則採用little endian方式存儲數據。那麼

究竟什麼是big endian,什麼又是little endian?

big endian是指低地址存放最高有效字節(MSB,Most Significant Bit),而little endian則是低地址

存放最低有效字節(LSB,Least Significant Bit)。

下圖像加以說明。比如數字0x12345678在兩種不同字節序CPU中的存儲順序如下所示:

Big Endian

低地址 ⾼高地址

---------------------------------------------------------------------------

-->

| 12 | 34 | 56 | 78 |

Little Endian

低地址 ⾼高地址

---------------------------------------------------------------------------

-->

| 78 | 56 | 34 | 12 |

所有網絡協議都是採用big endian的方式來傳輸數據的。所以也把big endian方式稱之為網絡字節序。當

兩臺採用不同字節序的主機通信時,在發送數據之前都必須經過字節序的轉換成為往絡字節序後再進行傳

輸。

更多音視頻學習,關注

回覆:1 領取 音視頻資料

音頻編碼實戰

音視頻課程學習大綱

音頻編碼實戰


分享到:


相關文章: