抖音刃滓、快手在國內(nèi)迅速走紅仁烹,也帶動了國內(nèi)短視頻的熱潮。短視頻錄制咧虎、編輯等等功能卓缰,是一項系統(tǒng)性、專業(yè)性很強(qiáng)的領(lǐng)域砰诵。經(jīng)過一段時間發(fā)展后征唬,有多種方式可以通向羅馬,但并不是每一條路都好走茁彭。這篇文章將重點(diǎn)介紹下总寒,硬編硬解過程中遇到的坑,也給讀者朋友架構(gòu)方案時提供一點(diǎn)參考理肺。
原文鏈接: https://mp.weixin.qq.com/s/SqP-AcEh5EMbkVDP83cCrw
Camera 使用的坑
雖然和硬編硬解沒有關(guān)系摄闸,但短視頻客戶端不可能繞過這個,這里也列舉下我所遇到的問題哲嘲。
API 使用上的一些坑
Camera API 是 Android 碎片化嚴(yán)重的體現(xiàn)贪薪,不同于 iOS 系列,一共就那幾種機(jī)型眠副。Android 廠商眾多画切,ROM 也百花齊放,同樣的 API 在不同機(jī)型上提現(xiàn)可能完全不同囱怕,也是我們需要在開發(fā)過程中留意的霍弹。下面簡單列舉兩個可能會導(dǎo)致畫面異常的 API毫别。
- setRecordingHint
Sets recording mode hint. This tells the camera that the intent of the application is to record videos MediaRecorder.start(), not to take still pictures Camera.takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback). Using this hint can allow MediaRecorder.start() to start faster or with fewer glitches on output. This should be called before starting preview for the best result, but can be changed while the preview is active. The default value is false. The app can still call takePicture() when the hint is true or call MediaRecorder.start() when the hint is false. But the performance may be worse.
官方的注釋如上,英文很簡單典格,就不翻譯了岛宦。看上去是一個很人畜無害的 API耍缴,但實(shí)際上卻暗藏殺機(jī)砾肺。此方法需要你設(shè)置 video-size,如果不設(shè)置這個防嗡,將會在某些機(jī)型(OPPO A37f, MI 2 , LG 部分手機(jī))上造成拉伸的后果变汪。
RecordingHint 的目的是幫助更快速地進(jìn)行錄制,某些 ROM 在實(shí)現(xiàn)的時候蚁趁,沒有考慮到 Preview Size 和 Video Size 之間的區(qū)別裙盾,例如使用 480 * 864 的分辨率進(jìn)行錄制,輸出的文件大小為 400 * 800他嫡,那么勢必會使得整體畫面出現(xiàn)拉伸的情況番官。
- setVideoStabilization
Enables and disables video stabilization. Use isVideoStabilizationSupported() to determine if calling this method is valid. Video stabilization reduces the shaking due to the motion of the camera in both the preview stream and in recorded videos, including data received from the preview callback. It does not reduce motion blur in images captured with takePicture. Video stabilization can be enabled and disabled while preview or recording is active, but toggling it may cause a jump in the video stream that may be undesirable in a recorded video.
官方文檔上寫著,這個方法可以幫助提高錄制視頻的穩(wěn)定性钢属。使用的時候通過 #isVideoStabilizationSupported
來判斷是否可以使用徘熔。如果妄自使用的話,會造成頁面黑屏淆党,PreviewCallback 沒有任何回調(diào)近顷。這兩個 API 都是官方文檔中提及,但完全沒有任何隱患說明的地方宁否,Camera API 調(diào)用的坑可見一斑。
Camera 效果不一致
如果 UI 妹子對畫面要求比較高缀遍,需要在各大手機(jī)品牌上取得一致效果慕匠,那對于 Android Developer 簡直是一場災(zāi)難。例如同樣的白平衡效果域醇,在 google 旗艦機(jī)型 Pixel 2XL 與 Huawei Honor 的差異就很明顯台谊。一般對于 Android 端,我們不能強(qiáng)求一致的效果譬挚,而是要提供給用戶足夠的自由度锅铅,讓他們在機(jī)器提供的能力范圍內(nèi)拍出較為滿意的效果。
Oppo 的部分機(jī)型自帶美顏效果减宣,而其他較為老舊的機(jī)型則沒有這樣的功能盐须,因而我們對于這些機(jī)型上的默認(rèn)美顏處理可以有不同的策略。
并不是所有機(jī)型都對拍出的照片添加了 Exif 信息漆腌,所以我們不能默認(rèn)照片都是豎直方向的贼邓。如果照片中含有 Exif阶冈,還是要根據(jù)這個來判斷照片方向。
總結(jié)起來說塑径,我們在使用 Android Camera API 時女坑,需要對曝光、色溫统舀、快門這些基本的拍攝概念有一個了解匆骗,這樣才能在遇到各種奇怪情況的時候找到合適的解決方案。
硬編硬解的若干坑
MediaCodec 不一定支持
首當(dāng)其沖的就是 MediaCodec 不一定支持誉简!特別是一些老舊機(jī)型比較突出碉就,在引入 CTS 測試之前,那簡直了(手動微笑)描融。建議在合適的地方铝噩,判斷硬編硬解支持的程度。
這里列舉出 CTS 中測試 MediaCodec 支持程度的鏈接窿克,tests/tests/media/src/android/media/cts/EncodeDecodeTest.java - platform/cts - Git at Google骏庸,大家可以參考這其中的代碼來判斷用戶機(jī)型的支持程度。 如果機(jī)型不支持年叮,大概率在創(chuàng)建 Encoder 的時候就會崩潰具被。
Surface 也不一定支持
MediaCodec 支持的數(shù)據(jù)類型中,有一項就是 Surface只损。Surface 直接使用 native 層的 Buffer一姿,這樣避免映射和拷貝,效率上能高不少跃惫。然而并不是每一種機(jī)型都支持 Surface 格式的叮叹。
我們可以在 createInputSurface 的時候 catch 下異常,如果代碼上沒有問題爆存,那真的就是機(jī)型上不支持 Surface 了蛉顽,那只能老老實(shí)實(shí)用 ByteBuffer 吧(手動扇子臉)。
虛晃一槍的 API
備注:筆者使用的是 Google Pixel 2XL (Version 8.1) 進(jìn)行地測試先较。
編解碼本身靈活性就相對欠缺携冤,可配置的地方就少,但就算在這種情況下那些看上去不錯的接口闲勺,很大概率上只是鏡中月曾棕,水中花,夢里人菜循。
-
BitMode
文檔上寫著三種支持三種碼率模式翘地,CQ的意思是盡量保證幀率,保證圖片質(zhì)量;CBR 則是盡量保證每一幀的碼率子眶,但在一些動作比較大的Video中瀑凝,就很容易模糊;VBR 則是前兩者之間一個中庸的方案臭杰。
但是粤咪,絕大多數(shù)機(jī)型都只支持 VRB 一種。(如果有錯誤渴杆,歡迎指正)
CodecLevel寥枝、CodecProfile
設(shè)置這兩個值,可以改變編碼級別磁奖,不同編碼級別得出的效果不一樣囊拜,級別越高,效果越好比搭。我們可以通過 ffmpeg冠跷,或者 mediaInfo 來查看視頻的編碼級別。筆者在 Pixel 2XL 支持的 level身诺、profile 中蜜托,分別進(jìn)行測試,發(fā)現(xiàn)所有視頻編碼出的效果霉赡,都是Base Media/ Version 2
橄务。又一個并沒有什么卵用的 API,筆者只能認(rèn)為這是 Google 為日后埋下的伏筆了穴亏。同理 getComplexityRange 這個 API蜂挪,可以有 low、upper兩種級別嗓化,但它們的值都是0棠涮,可能 low 和 upper 是雙胞胎吧(手動扇子臉)。
隱式限制很多
MediaCodec 在 Configure 的過程中刺覆,可以設(shè)置各種各樣的顏色格式故爵。但實(shí)際上支持的種類非常有限,調(diào)用前一定要通過 getCapabilitiesForType
來確認(rèn)下隅津。
一般來說,絕大多數(shù)相機(jī)的 Preview 輸出都支持 NV21劲室,因此我們在使用 Camera API 的時候伦仍,可以放心地在 Camera#Parameters setPreviewFormat 使用 NV21 格式。然鵝很洋,MediaCodec 不一定支持 NV21 哦充蓝!這些支持的格式里面,不同廠商表現(xiàn)不一樣哦,高通支持的別家還真不一定支持谓苟。底層在使用的時候官脓,一定要做好判斷。忘了說啦涝焙, getCapabilitiesForType
這個 API 也要處理好異常(手動扇子臉 X3)卑笨。
寫到這里,還需要額外指出一點(diǎn)仑撞,16位對齊的事情赤兴。軟編軟解的時候,可以放心使用 540 * 960 這樣的分辨率隧哮,但在硬編硬解的時候桶良,一定要用 544 * 960,如果沒有16位對齊沮翔,才不說什么 MOTO 機(jī)型直接花屏給你看
的事情陨帆。
結(jié)語
出了上述的問題以外,其他 API 的限制(坑)都不少采蚀,例如 MediaMuxer 基本上和 MPEG-4 綁定死了疲牵。那這么說起來,硬編硬解在 Android 上是不是就不能用呢搏存。其實(shí)也沒那么不堪瑰步,在編解碼速度上比軟編軟解快上不少,筆者簡單進(jìn)行了下對比璧眠,能快上50%(不具有參考性缩焦,機(jī)型越好,差距越少)责静。這里只是寫一篇文章袁滥,分享下在實(shí)際開發(fā)中遇到的坑,給各位讀者大大一點(diǎn)參考灾螃。
文檔信息
- 版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(創(chuàng)意共享3.0許可證)
- 發(fā)表日期:2018年9月1日
- 社交媒體:weibo.com/woaitqs
- Feed訂閱:www.woaitqs.cc/feed.xml