內容原創,轉載請注明出處
一、引言
??移動App發展到今時今日,幾乎所有應用程式里都有音視頻相關功能,總結起來大概有音視頻錄制,音視頻播放,音視頻特效處理,音視頻傳輸這幾方面內容,
??比較熱門的短視頻應用抖音與快手,K歌應用唱吧與全民K歌,以及網易云新出的音街,還有聽歌的網易云音樂和qq音樂等,雖然每種應用的運營模式不一樣,但是從技術實作上大同小異,短視頻類軟體的視頻處理更豐富,有非常炫酷的濾鏡,貼紙,K歌類軟體對音樂的細節處理的較多,諸如音量,音效,音調,
??筆者是唱吧較早的用戶,發展至今,唱吧涵蓋的音視頻技術相對比較全面,原唱吧音視頻技術負責人展曉凱老師在《音視頻進階指南》一書中對移動端音視頻最佳實踐給出了具體實作,所以就以唱吧為參考,探索移動端的音視頻相關技術,(代碼實作上基于安卓,不過對于音視頻這種偏底層的操作,各平臺實作思路大致一樣,另外,筆者未曾在唱吧作業過,若有侵權或其他行為,請留言溝通,若想與筆者共同探討移動音視頻技術,歡迎留言或微信smzh_james探討),
涉及技術目錄一覽
一、音頻錄制(錄音,音頻解碼,音頻重采樣,音頻混合)
二、音頻播放與效果處理 (音量,音調,音效)
三、視頻錄制 (Camera相關,視頻編碼)
四、視頻特效處理(美顏,濾鏡,貼紙)
五、視頻播放(視頻解碼,視頻渲染, 音視頻同步)
六、音視頻混合
(內容鏈接會陸續更新)
二、效果對比與技術實作淺析
參考唱吧App的界面,做了一款簡易的K歌軟體,黑白風格,但是涵蓋了大多數功能,以下稱為SuperKtv,效果對比如下圖,
(一)K歌串列頁

??圖1是SuperKtv,圖2是唱吧,
??SuperKtv實作比較簡單,直接獲取手機上現有音頻檔案以串列展示,為后續功能提供一個入口,實作上沒啥難度,做開發的都懂,就不再贅述,
(二)音頻錄制頁

??前兩幅圖是SuperKtv的音頻錄制頁,第三幅圖是唱吧音頻錄制頁,
-
歌詞
??對于K歌軟體來說歌詞是很重要的一部,像唱吧這種專業K歌軟體,曲庫很龐大,為了與演唱同步,歌詞一般都帶有時間戳,以便演唱程序中歌詞動態滾動,還有打分功能,從技術方面分析,歌詞和打分功能每首歌應該都不相同,這方面本質不涉及音視頻技術,筆者也沒有太多精力為歌曲自定義歌詞和打分功能,
??為了讓SuperKtv與唱吧有較高的鍥合度,筆者還是想辦法做了這方面的作業,要快速解決SuperKtv的歌詞問題,只能從網路入手,利用 歌詞網https://www.90lrc.cn 強大的搜索功能,使用其搜索介面先搜索歌名,回傳帶搜索結果串列的Html,然后決議Html獲取合適的串列項,一般取第一項最為合適,并取出其中的歌詞鏈接,再通過歌詞鏈接獲取帶歌詞的Html,過濾后即可獲取獲取歌詞文本,顯示效果如上圖1,打分功能的一中實作方法是在演唱程序中匹配動態識別的音高與預定義檔案中的內容, -
錄音
?? K歌軟體的核心功能之一,對于錄音的低延時性能要求較高,這一點上IOS比Android做的要好的多,而且功能很完善,用AudioUnit可以解決大部分問題;Android8.0以下推薦使用OpenSL ES,是OpengSL在嵌入式設備上的精簡實作;Android8.0及以上推薦使用AAudio,一個輕量級錄音介面,為低延時音頻處理而生,據官網檔案描述低延時性能較好,而且給出了Pixel幾款機型的測驗資料,但是因為安卓的機型是在太多,硬體實作上付出的努力不盡相同,所以這兩者在兼容性上均不如AudioRecorder好,Google Android團隊對OpenSL ES和AAudio進行了封裝,命名為Oboe,看起來大有追趕AudioUnit的理想,提供了統一的呼叫介面,使用極為方便,在GitHub上直接能搜到Oboe https://GitHub/Oboe,提供的Demo參考價值很大,但根據GitHub上的反饋來看,使用起來問題不少,主要在雜音和延遲上,期待后續的更新能徹底解決這個安卓從問世以來就一直被詬病的問題,
?? 低延遲錄音的另一個解決方案是計算錄音延遲,設想如果能獲取到錄音延遲,那么在編輯頁混合的時候可以人為的將錄到的聲音提前一段時間,得到的結果幾乎接近于沒有延遲,但要是能這么容易解決的話就不是Android了,錄音的延遲計算并不容易,粗略的計算 錄音延遲 = 硬體延遲 + 緩沖延遲,如果在錄音回呼中有較多計算的話還需要加上計算延遲,截止目前只有AAudio中提供了計算延遲的方法,尷尬的是經實測延遲為0,即便是8.0以上的設備已經占據主流市場,但對于商用軟體來說支持到8.0肯定是遠遠不夠的,硬體的延遲或許只有廠商能夠拿到比較準確的資料,所以和廠商合作也是其中一種解決辦法,對于華為手機來說,華為的Sdk里面提供了相應的Api,使用AudioKit能直接獲取錄音延遲,而且具備耳返功能和七個音效,這應該是迄今聽到的最好的訊息了, -
音頻解碼和重采樣
?? 在K歌軟體錄音的時候一般會播放伴奏或者原唱為演唱者提供參考,底層的Api一般都不提供解碼功能,所以在將資料“填充”到設備緩沖區之前要將伴奏或原唱解碼成原始資料,就是大名鼎鼎的Pcm,歌曲檔案一般是Mp3或者AAC格式,Mp3的編解碼推薦使用Lame,AAC的編解碼推薦使用Fdk-aac,這兩者在速度上迄今為止做到了最好,對于有實時性要求的最合適不過了,可以直接使用或者將這兩個庫編譯到FFmpeg里面,呼叫FFmpeg的Api操作,再退一步,直接使用FFmpeg自帶的解碼演算法也能完成相應功能,當然性能上是有所區別,在解碼上普遍的做法是編譯帶有Lame或Fdk-aac的FFmpeg,呼叫FFmpeg的Api去做編解碼,因為其Api的統一性上很有優勢,
?? 在Android平臺下還可以使用MediaCodec進行解碼,系統自帶Api,使用方便,檔案較多,而且使用硬體解碼,速度上也比軟體解碼快很多,遺憾的是直到Android6.0以河駁供了MediaCodec的C++介面,考慮到和IOS的統一性,推薦使用前者,
?? 重采樣關鍵點是音樂檔案的采樣率、聲道數和采樣深度(也稱量化精度),某一個音樂檔案的采樣率、聲道數、量化精度可以認為是不確定的,但播放平臺硬體支持的采樣率、聲道、采樣深度是有限的、確定的,所以在“填充”資料給音響設備的緩沖區之前的另一項作業是重采樣,直接使用FFmpeg就好了,FFmpeg提供的重采樣功能比較強大,包括采樣率、聲道數和采樣深度都可以改變,參考檔案或在網上搜索都可以 ,需要注意的是網上的FFmpeg重采樣教程大多忽略了一個問題,從單聲道重采樣成雙聲道的時候,為了保證聽覺上音量不變,實際的分貝(響度)會有輕微的變化,這點還需要特別注意, -
音頻內容保存
?? 考慮到K歌軟體錄到的音頻內容在后面的要進行編輯,在磁盤空間不受限制的情況下建議直接保存原始資料,方便后續操作,一首歌的空間一般在100Mb以內,如果考慮磁盤空間的話,可以將錄到的資料編碼保存,編輯的時候再進行解碼,關于音頻編碼部分在保存的時候再詳細分析,要注意的是在保存資料的時候要頻繁讀寫檔案,考慮到性能問題,可以選用異步操作來完成,異步操作的執行緒同步問題可以使用Boost庫中提供的無鎖佇列來完成,
(三)音頻編輯頁


??前兩幅圖是SuperKtv,后兩幅圖是唱吧,在寫這邊文章的時候唱吧的編輯頁進行的改版,頁面布局發生了巨大變化,風格上跟音街比較像,但在筆者模仿唱吧界面的時候,老用戶應該比較清楚,長相跟SuperKtv非常接近,此處比較許遺憾,沒能以最高相似度復原唱吧App,
-
音頻播放
?? K歌軟體的在編輯頁需要音頻播放功能,對低延時性能要求也比較高,目的是將前面錄好的內容和伴奏同時播放,聽起來像是在聽歌星的專輯一樣,在Android平臺上使用OpenSL ES和AAudio是較好的選擇,為達到較好的同步效果,選用低延時Api是必要的,此外,還需要精確控制兩個軌道播放的時間一樣,比較簡陋的做法是打開兩個播放器,一個播放人聲,另一個播放伴奏,以達到同步播放的效果,更具使用價值的是選擇一個播放器,將人聲和伴奏的Pcm資料混合之后播放,后者的同步性要好于前者,效率是也更高,在SuperKtv中使用的是第二種方案,效果還不錯,在播放之前要關注Pcm資料的聲道、采樣率、采樣深度,必要時進行重采樣, -
音量控制
?? 在音頻處理中,對編碼好的音頻處理很難,一般是對原始資料進行處理,在后續的音量、音效、音調處理都是對Pcm處理,
?? 眾所周知聲音是波,音量可以理解為波的振幅,也叫響度,改變音量即改變波的振幅,從數學的角度要增大一個正弦波的振幅只要乘以增益就可以,同樣,音量也是對Pcm資料乘以增益就可以,當然可以直接使用FFmpeg來解決,要注意的是增大振幅之后不能超過每一幀資料的最大值和最小值,以16位整形精度為例,如果最終的數值大于32767或小于-32768,那么音質就會受損,聽起來像雜音一樣, -
音調控制
?? 音調主要由聲音的頻率決定,同時也與聲音強度有關,對一定強度的純音,音調隨頻率的升降而升降;對一定頻率的純音、低頻純音的音調隨聲強增加而下降,高頻純音的音調卻隨強度增加而上升,音調調節推薦使用SoundTouch https://sourceforge.net/projects/soundtouch/),用法比較簡單,而且還具有變速等功能,
?? 音調主要是由聲波的頻率決定的,聯想到數學或物理學中波相關的知識點,可以自己手動實作,簡單理解為將音頻資料重采樣成另一個頻率,但資料內容沒有減少,由傅里葉變換的定義可以知道,任何周期性的波都可以分解成若干個正弦波的疊加,在這里普遍的做法是將Pcm資料經傅里葉變換得到頻域的結果,改變基波的頻率,因為頻率的變化可能導致資料減少或增多,需要再進行插值計算,最后做反向傅里葉變換將資料變換到時域,就可以得到改變頻率的Pcm資料,也就是改變了音調, -
音效控制
?? 因為聲音是波,所以音效也是根據波的一些特性進行處理的,比如回聲效果就是根據波的反射性實作的,展曉凱老師在《音視頻進階指南》一書中給出了用Sox實作音頻效果的具體實作,FFmpeg也可以對音頻進行效果處理,SuperKtv中用兩者均實作了音頻效果處理,Sox在音頻效果處理上功能稍微更全面一些,推薦使用Sox http://sox.sourceforge.net/,被譽為音頻處理方面的瑞士軍刀,遺憾的是這個庫在早些時候已經停止更新了,其功能逐漸被桌面版客戶端AudioCity取代,
?? 音頻效果處理分為混響,均衡,壓縮,混響可以理解為在一個房子里面唱歌有回聲,影響的因素一般有房間的大小、墻壁的反射率(裝修材料等),演唱者所處的位置等,所以通過改變房間大小等引數,就可以模仿專業演播大廳的效果,像維也納演播大廳的混響引數都是已知的,參考這些引數就能模擬出在維也納演播大廳開演唱會的效果,均衡器可以分別調節各種頻率成分信號放大量,一般調音臺上的均衡器僅能對高頻、中頻、低頻三段頻率電信號分別進行調節,均衡器還具備高通濾波和低通濾波的功能,比如唱吧中的留聲機效果就是使用了均衡器,一方面過濾掉某些頻率的諧波,另一方變改變某些頻率信號分量的增益就可以得到留聲機的效果,壓縮器在百度百科上的定義如下:“壓縮器是一種隨著輸入信號電平增大而本身增益減少的放大器,實質上改變的就是輸入與輸出信號的比例,壓縮器是兩種最常見的用于處理音頻信號動態范圍的設備之一”,這個定義應該很明了了,在Sox的實作上主要以調節引數為主,通過這三種效果的疊加,就可以調節出Ktv、錄音機、流行,說唱等不同風格的效果,上圖中的自定義音效是對混響、均衡、壓縮三種效果中一些重要引數提供了可調節入口,其他音效可以理解為一些固定引數根據經驗的組合,以上三種演算法原理可以參考Sox原始碼中reverb.c,bequed.c,compand.c這三個檔案,
(四)視頻錄制頁


??前三幅圖的SuperKtv的視頻錄制界面,后三幅圖是唱吧的視頻錄制界面,
??從功能上對比,SuperKtv美顏面板少了銳化,瘦臉,大眼功能,另外道具功能也沒有實作,稍后具體分析,
?? 音頻部分跟前面一樣,重點分析視頻的錄制,視頻的錄制需要保存帶美顏效果的視頻,當然也可以保存原始視頻畫面在編輯頁進行處理,唱吧中采用了前者,所以SuperKtv中也采用了第一種方案,
-
相機操作及美顏、濾鏡
?? 這一部分內容需要有一定的OpenGL ES基礎,可以理解為對每一幀畫面中的每一個像素進行處理,然后渲染到螢屏上,詳細原理可以參考博主OpenGL ES系列文章
Android OpenGL ES從入門到進階(一)—— 五分鐘開發一款美顏相機
Android OpenGL ES從入門到進階(六)—— OpenGL ES人像美白與磨皮初探
Android OpenGL ES從入門到進階(八)—— 萬能的Lookup濾鏡
上述內容都屬于OpenGL ES基礎部分,本文不再描述,有疑問的可以留言交流, -
貼紙(道具)
?? 在美顏相機類產品中,貼紙功能應該算一個重頭戲,唱吧中稱為道具,目前抖音中的貼紙類功能算比較強大的,這類功能的實作依賴于人臉面部特征點識別,而且對實時性要求比較高,國內商用人臉識別Sdk里面做得比較好的商湯科技和曠視科技,中小型公司的美顏類產品都從這兩家購買Sdk,抖音和FaceU激萌據筆者所知用的是位元組跳動自研的人臉識別Sdk,由于對實時性要求較高,一般都是采用深度學習演算法,訓練好模型之后根據模型識別,如果對實時性要求不高的話可以使用Dlib http://dlib.net/,基于OpenCV的使用比較簡單,這個也是基于深度學習的,官方檔案中給的模型大概有100Mb,畢竟是開源免費的,性能上較商用Sdk有不小差距,經實測,Dlib識別一幅1080 x 720的圖片大概需要400 - 500ms,在某些性能低的手機上甚至需要1000ms,而商用Sdk可以在20ms內完成,這也是為什么有開源免費的,商用的還能賣那么貴的原因,同時啟示我們要尊重知識產權,由于這些限制,SuperKtv中暫時沒有動態貼紙功能,
?? 關于貼紙的使用,可以參考另一篇博客 Android OpenGL ES從入門到進階(七)—— OpenGL ES 2D貼紙與Blend混合 這是一篇關于靜態貼紙的文章,動態貼紙稍微麻煩一些,需要根據面部特征點時時改變貼紙的位置和角度,有的還需要做平移和縮放,貼紙的變化規則需要提前定義好,以商湯Sdk為例,貼紙的運動規則定義在一個json檔案中,使用貼紙先決議json內容,然后隨時間做周期運動,這就是動態貼紙的大致原理,
- 視頻編碼
?? 不同于音頻,原始視頻占用磁盤空間非常大,如果錄到的視頻保存成原始資料的話那不可想象,所以在錄制視頻之后要編碼之后進行保存,視頻編碼格式很多,移動端流行H264和H265,SuperKtv中采用的事H264編碼,所以文中也以H264為例分析,
?? 如果保存了帶美顏效果的視頻后不需要對畫面進行二次編輯(比如唱吧),在Android平臺首選MediaCodec配合Surface,一方面使用硬體編碼速度要優于軟體編碼,另一方面系統自帶Api使用上會更方便,Mediacodec可以將Surface上的資料直接編碼,只需要將編碼后的資料寫檔案即可,這非常契合SuperKtv的需求,但硬體編碼的兼容性不是很好,尤其是安卓的機型成千上萬種,總有幾款手機使用起來有這樣那樣的問題,考慮到這樣的情況有時候也會采用軟體編碼,軟體編碼H264推薦使用X264,演算法性能上要優于FFmpeg自帶的H264編碼演算法,但是普遍的用法是將X264編譯到FFmpeg里面,用統一的介面呼叫,這種方法稍微麻煩一些,先要將相機的回呼資料做美顏、濾鏡等處理,然后再根據需求看是否需要進行資料格式轉換,因為Android的Camera API有兩套,Camera1推薦使用NV21,Camera2推薦使用Yuv420p,用FFmpeg編碼的時候,由于顏色空間的特殊性,以及X264只支持Yuv420p格式編碼,為方便使用,建議將資料統一轉換為Yuv420p格式再進行編碼,轉換演算法網上有,這里推薦使用LibYuv,功能很強大,這一部分內容要求要對影像的幾種顏色空間有所了解,特別是RGBA系列和YUV系列,
?? 如果在編輯頁面要對原始視頻進行二次編輯,那么只能保存原始畫面,這時候可以使用MediaCodec,也可以使用FFmpeg,在這種需求下二者的卻別不是很大了,硬體編碼速度快,但兼容性稍差,軟體編碼兼容性好,但速度稍慢,可適當取舍而定,當然FFmpeg也是支持硬體編碼的,只是編譯的時候需要做一些額外的處理,但如果是硬體編碼,為何不直接使用系統API呢,
(五)音視頻編輯頁


??前兩幅圖是SuperKtv的實作,后兩幅圖是唱吧的實作,
??同樣的,唱吧在音視頻編輯頁面也進行了較大改版,唱吧在演唱功能下沒有實作對視頻的編輯,所以也跟隨了唱吧的風格,主要是對音頻的編輯,功能實作上跟前面提到的音頻編輯一樣,比較重要的一點是視頻播放,涉及到視頻解碼和音視頻同步,如果說要實作視頻的編輯功能,有兩種思路,一中是用OpenGL ES處理后后臺保存,另一種是使用FFmpeg或OpenCV對資料處理后保存,推薦使用OpenGL ES進行視頻編輯,
-
視頻解碼
?? Android平臺推薦使用MediaCodec解碼,可以直接解碼到Surface上進行顯示,這省去了很多額外的操作(資料格式轉換和渲染),
當然也可以使用X264或FFmpeg進行解碼,將解碼之后的資料拷貝到ANative_Window提供的緩沖區用以顯示,這比起FFmpeg編碼已經方便很多了,若需要使用OpenGL ES對視頻進行編輯,需要將資料轉換成紋理,并上傳到OpenGL ES提供的緩沖區用來顯示,唱吧匯入外部視頻可以編輯,可以用上述思路均可實作, -
音視頻同步
?? 音視頻同步是視頻播放很重要的一個環節,直接影響到前面所有作業的結果,音視頻同步一般使用時間戳同步,這要求在編碼的時候加上正確的時間戳,Camera的回呼里面有當前幀的時間戳,以微秒為單位,跟MediaCodec所需單位一致,編碼時使用較方便,FFmpeg的時間戳跟MediaCodec不同,使用的是根據時間基計算出來的,編碼時只需要加上當前幀的索引就可以,同步的原因是因為音頻在單位時間內的播放資料量是固定的,只需給播放Api回呼填充資料就可以,但視頻沒有相應的機制,在畫面上顯示的內容以及什么時候顯示都是由外界控制,假如用解碼速度控制的話,如果解碼速度太快,在很短的時間內就能播放完一個較長視頻,如果解碼速度太慢,就會導致畫面卡頓,同步的程序大致可以描述如下:如果當前幀播放快了,那下一陣繼續播放當前幀,相當于等待,如果當前幀播放太慢,那就丟棄,播放下一幀或下下一幀,這樣就能控制視頻播放的速度了,同步的方法一般有音頻向視頻同步,視頻向音頻同步,二者向基準時間同步,普片選用視頻向音頻同步,因為音頻在單位時間內播放的資料固定的,
(六)保存和作品串列頁

??第一幅圖是保存的界面,第二幅圖是保存后的作品串列頁面,界面簡單,沒有與唱吧進行對比,
??保存的目的是為了讓保存的結果和編輯頁面調節后的效果一樣,相當于重復一遍編輯頁面的操作,只不過要變成后臺操作,前臺唯一需要顯示的是保存進度,后臺處理過的資料直接進行編碼即可,
-
音頻編碼
?? 前面提到,為方便編輯,錄到聲音后保存成了原始資料,但音頻的結果必然是成品(編碼后的)的,所以在保存之前先要編碼,移動端音頻編碼一般使用Mp3合適或者AAC格式,Mp3編碼推薦使用Lame,AAC編碼推薦使用Fdk-aac,也可以使用MediaCodec 或者FFmpeg自帶編碼演算法,對于SuperKtv的保存需求來說,編碼速度影響不是很大,所以選哪一種都可以,在了解MP3格式和AAC格式的區別之后,任選一種使用哪種方法都可以達到很好的效果,有一個不同點是MediaCodec編碼的AAC是不帶ADTS的裸流,如果此處是最終音頻檔案,需要手動添加ADTS,而使用Fdk-aac編碼之后會自動加上ADTS, -
音視頻合并
?? 截止這一步驟,前面生成的音視頻檔案都是單獨的,對于音頻錄制來說到這一步就已經完成了,對于視頻來說還需要將音頻和視頻合并成一個檔案,音視頻合并可以理解為將兩個檔案合并成一個檔案,通過某種規則將兩個型別的資料區分,使用的時候能夠單獨拿到音頻和視頻資料,有點類似于編輯頁面音視頻的同步的感覺,使用Android提供API MediaMuxer或者使用FFmpeg均可以,使用MediaMuxer合并音視頻的時候,若音頻是AAC格式,需要提供AAC裸流,使用FFmpeg的話就不用,甚至可以直接用命令來完成,合并完之后就是普遍意義上的視頻,是可以直接發布的作品,
(七)本地作品播放頁

??第一幅推是音頻播放界面,第二幅圖是視頻播放界面,界面簡單,沒有與唱吧進行對比,
?? 前面做了好多作業,最后的結果只是一個檔案,一種是音頻檔案,類似于.mp3,常用的還有.m4a等;另一種是視頻檔案,類似于.mp4,常用格式還有.flv等,對于這樣的檔案每個人應該都很熟悉,手機自帶功能就能夠播放,所以在SuperKtv中欣賞或者分享個人作品的時候沒必要自己再寫一套播放器,使用現成的就可以,甚至直接呼叫系統API MediaPlayer就可以,關于播放器的使用,安卓平臺下推薦使用EXOPlayer,這是谷歌基于MediaCodec的一款開源播放器,支持音、視頻及其常用格式,使用硬體解碼,還帶有一些基礎控制元件,定制性較高,SuperKtv就是基于ExoPlayer做的本地作品播放功能,效果展示如上圖,使用體驗也很不錯,
三、總結
?? 本文是以“唱吧App”為參考,基于Android平臺,總結了移動端音視頻技術的實作策略,適合有一定音視頻基礎的開發人員,可以作為技術方案參考,由于時間精力有限,實作細節隨后以文章形式發布,若有疑問歡迎大家留言交流,
轉載請注明出處,
友情鏈接:
1、FFmpeg http://ffmpeg.org/ (音視頻必備神器)
2、Sox http://sox.sourceforge.net/ (音頻界瑞士軍刀)
3、SoundTouch https://sourceforge.net/projects/soundtouch/ (音調、變速)
4、Dlib http://dlib.net/ (人臉特征點識別開源庫)
5、Oboe https://GitHub/Oboe (Android平臺低延時音頻介面)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/195255.html
標籤:其他
上一篇:小程式createInnerAudioContext()音頻播放iOS端真機除錯無聲音且不執行play函式
下一篇:新手提問
