編輯:關於Android編程
前面四篇文章分別介紹了音頻開發必備的基礎知識、如何采集一幀音頻、如何播放一幀音頻、如何存儲和解析wav格式的文件,建議有興趣的小伙伴們先讀一讀,本文則重點關注如何對一幀音頻數據進行編碼和解碼。
1. Android 官方的 MediaCodec API
首先,我們了解一下 Android 官方提供的音頻編解碼的 API,即 MediaCodec 類,該 API 是在 Andorid 4.1 (API 16) 版本引入的,因此只能工作於 Android 4.1 以上的手機上。
1.1 MediaCodec 基本介紹
(1)提供了一套訪問 Android 底層多媒體模塊的接口,主要是音視頻的編解碼接口
(2)Android 底層多媒體模塊采用的是 OpenMax 框架,任何 Android 底層編解碼模塊的實現,都必須遵循 OpenMax 標准。Google 官方默認提供了一系列的軟件編解碼器:包括:OMX.google.h264.encoder,OMX.google.h264.encoder, OMX.google.aac.encoder, OMX.google.aac.decoder 等等,而硬件編解碼功能,則需要由芯片廠商依照 OpenMax 框架標准來完成,所以,一般采用不同芯片型號的手機,硬件編解碼的實現和性能是不同的
(3)Android 應用層統一由 MediaCodec API 來提供各種音視頻編解碼功能,由參數配置來決定采用何種編解碼算法、是否采用硬件編解碼加速等等
1.2 MediaCodec 核心原理
我不准備詳細介紹 MediaCodec API 的每個函數是怎麼用,示例代碼大家可以在後面給出的資源鏈接中查看和學習。
這裡我准備重點介紹一下 MediaCodec 的核心工作原理,因為只有搞清楚了這一點,你才會明白為什麼 MediaCodec API 提供的接口是這個樣子的。
MediaCodec 使用的基本流程是:
-createEncoderByType/createDecoderByType -configure -start -while(1){ -dequeueInputBuffer -queueInputBuffer -dequeueOutputBuffer -releaseOutputBuffer } -stop -release
由此可以看到,Buffer 隊列的操作是其最核心的部分之一,關於 MediaCodec 的 Buffer 隊列 ,示意圖如下:
MediaCodec 架構上采用了2個緩沖區隊列,異步處理數據,下面描述的 Client 和 MediaCodec 模塊是並行工作的(注:這裡的 Client 就是指 “開發者,API 的使用者”):
(1)Client 從 input 緩沖區隊列申請 empty buffer [dequeueInputBuffer]
(2)Client 把需要編解碼的數據拷貝到 empty buffer,然後放入input緩沖區隊列 [queueInputBuffer]
(3)MediaCodec 模塊從 input緩沖區隊列取一幀數據進行編解碼處理
(4)編解碼處理結束後,MediaCodec 將原始數據 buffer 置為 empty 後放回 input 緩沖區隊列,將編解碼後的數據放入到 output 緩沖區隊列
(5)Client 從 output 緩沖區隊列申請編解碼後的 buffer[dequeueOutputBuffer]
(6)Client 對編解碼後的 buffer 進行渲染/播放
(7)渲染/播放完成後,Client 再將該 buffer 放回 output 緩沖區隊列 [releaseOutputBuffer]
MediaCodec 在架構上,其實是采用了一種基於“環形緩沖區”的“生產者-消費者”模式,它設計了 2 個基於 idx 序號的“環形緩沖區” ,注意,是 2 個,一個在 input 端, 一個在 output 端。
我曾經在 Github 上分享過一段 Linux C 代碼,名叫:“rw_queue”,就是這種環形緩沖區的簡化版,大家有興趣可以看看,地址:https://github.com/Jhuster/clib/tree/master/rw_queue
基於 idx 的環形緩沖區的總體示意圖如下,圖中,wp 代表 “寫指針”,指向的是 “empty buffer”, 而 rp 代表 “讀指針”,指向的是 “filled buffer”:
“生產者”和“消費者”其實是共用這一個緩沖區隊列,“生產者”負責從隊列中取出未使用的 Buffer,填入數據,然後放回隊列,“消費者”則負責取出填入數據後的 Buffer,進行處理,處理結束後,再把 Buffer 標記為“空”,退回到隊列中去以供“生產者”繼續填充數據。
在 input 端,“Client”是這個環形緩沖區“生產者”,“MediaoCodec 模塊”是“消費者”。
在 output 端,“MediaoCodec 模塊”是這個環形緩沖區“生產者”,而“Client”則變成了“消費者”。
這就是其核心的工作原理,其實並不復雜,大家靜下心來,很快就能理解其中的奧妙。
1.3 參考資源
關於 MediaCodec 的示例代碼,網上其實也很多了,我就直接給出一些個人覺得不錯的鏈接,有興趣的小伙伴們可以去研究一下。
(1)Android 官方文檔: 《MediaCodec》
(2)《Android MediaCodec stuff》
(3)《HWEncoderExperiments》
(4)一些開源的播放器 Android 源碼,如 VLC、ijkplayer
2. 第三方音頻編解碼的庫
官方的 MediaCodec API 雖然支持硬件編解碼加速,但是問題和局限還是很多的,一方面是只能在 Android 4.1 以上機型上才能使用,另一方面,由於 Android 手機種類繁多,廠商對底層源碼的修改各不相同,導致 MediaCodec API 在實際使用中,會遇到很多坑,有很多兼容性的問題,因此,我們也可以考慮采用第三方的編解碼庫。
這裡,我簡單推薦幾款第三方音頻編解碼庫(可以移植到 Android 平台的),大家可以直接去官網或者項目主頁了解其詳細信息。
(1) opus 編解碼庫
很喜歡 opus,低碼率下 opus 完勝曾經優勢明顯的 HE AAC,我曾經用它實現了一款 Android 局域網的VoIP網絡電話應用:“飛鴿電話”,效果很不錯。
opus 官網地址:https://www.opus-codec.org
注:如今 Android 5.0 已經官方支持 opus 格式了,關於 Android 支持的多媒體格式列表可以查看 Android developer guide:《Supported Media Formats》
(2) Speex 編解碼庫
老牌的音頻處理庫,不僅是編解碼,還提供了包括音頻去噪、回聲消除、靜音檢測等功能,官網地址:http://www.speex.org
(3) ffmpeg
大名鼎鼎的 ffmpeg 肯定不能錯過,官網:https://www.ffmpeg.org
(4)Android AAC Encoder
一款輕量級的 Android aac 編碼庫:https://github.com/timsu/android-aac-enc
(5)opencore-amr-android
從 opencore 抽取出來的 amr 編解碼庫,地址:https://github.com/kevinho/opencore-amr-android
(6)iLBC-Android
iLBC 是著名的 WebRTC 項目的音頻編解碼模塊,iLBC-Android 是從中抽取 iLBC 模塊移植到 Android 平台的個人項目,地址:https://github.com/lukeweber/iLBC-Android
關於第三方編解碼庫就簡單介紹到這裡了,最後三個是個人項目,我沒有使用過,真心感謝這些作者的無私奉獻,另外,更多的第三方庫歡迎大家留言或者來信補充。
Android 圖形特效
拿到美工效果圖,咱們程序員就得畫得一模一樣。 為了不被老板噴,只能多練啊。聽說你覺得前面幾篇都so easy,那今天就帶你做個相對比較復雜的。今天的效果圖如下(左邊是ui
一般來說 真機調試 是最快的, 所以建議 大家 直接用真機調試。
導語,EventBus大家應該不陌生,EventBus是一款針對Android優化的發布/訂閱事件總線。主要功能是替代Intent,Handler,Broa