目錄
- 問題描述
- 問題分析
- 問題原因
- 問題解決
- 資料
- 收穫
一、問題描述
用小米11 錄製視頻上傳後,在iPhone的Safari瀏覽器或者應用的H5中無法播放,而android設備上的確實可以正常播放。
同樣的操作,在一些其他android的手機上傳的視頻,在ios端卻可以正常的播放。
二、問題分析
拿到(能播放和不能播放)兩個視頻。分析下這兩個視頻有什麼差異。
通過MediaInfo查看兩個視頻的基本信息
不能播放的視頻
{
"@type": "Video",
"StreamOrder": "1",
"ID": "2",
"Format": "AVC",
"Format_Profile": "High",
"Format_Level": "6",
"Format_Settings_CABAC": "Yes",
"Format_Settings_RefFrames": "1",
}
能播放的視頻
{
"@type": "Video",
"Format": "AVC",
"Format_Profile": "Main",
"Format_Level": "3.1",
"Format_Settings_CABAC": "Yes",
}
可以很明顯的看到兩個視頻的Profile和Level不同。
通過ffmpeg把不能播放的視頻進行轉碼,修改profile和level的值,進行本地快速驗證。
ffmpeg -i input.mp4 -profile:v main -level 4.2 output.mp4
ffmpeg -i input.mp4 -profile:v high -level 5.1 output.mp4
ffmpeg -i input.mp4 -profile:v high -level 6 output.mp4
發現只有level大於等於6,在ios上就不能播放。
三、問題原因
我們先來看下Profile和Level是什麼?
3.1 Profile
H.264有四種畫質級別,分別是baseline, extended, main, high:
1、Baseline Profile:基本畫質。支持I/P 幀,只支持無交錯(Progressive)和CAVLC;
2、Extended profile:進階畫質。支持I/P/B/SP/SI 幀,只支持無交錯(Progressive)和CAVLC;(用的少)
3、Main profile:主流畫質。提供I/P/B 幀,支持無交錯(Progressive)和交錯(Interlaced), 也支持CAVLC 和CABAC 的支持;
4、High profile:高級畫質。在main Profile 的基礎上增加了8x8內部預測、自定義量化、 無損視頻編碼和更多的YUV 格式;
H.264 Baseline profile、Extended profile和Main profile都是針對8位樣本數據、4:2:0格式(YUV)的視頻序列。
在相同配置情況下,High profile(HP)可以比Main profile(MP)降低10%的碼率。
根據應用領域的不同,Baseline profile多應用於實時通信領域,Main profile多應用於流媒體領域,High profile則多應用於廣電和存儲領域。
維基百科上有對應的表:
3.2 level
level是一組特定的約束,表示一個profile所需的編解碼性能。指定編解碼器可能使用的最大圖像分辨率、幀率和比特率。一個符合給定level的解碼器必須能夠解碼爲該level和所有低level編碼的所有比特流。
在MediaCodecInfo中有定義各種類型的值
綜上,我們可以知道Profile和Level是影響着視頻編碼的質量和效率。有些設備不支持高Profile、level的編碼。所以需要綜合考慮兼容性和視頻質量。
通過查看代碼發現,android端的視頻編碼時,僅對Profile做了閥值限制,Level沒有判斷處理,就像小米11手機對應解碼器信息返回的Level時6,這樣編碼出來的視頻在某些不支持的該level解碼的設備上就無法解碼播放。
3.3 擴展
另外通過查找資源,發現android在7.0之前的系統,編碼時profile只能是Baseline,如果不是系統會強制的設置爲Baseline。猜測也是爲了兼容性吧。雖然更高的壓縮比帶來很好的收益,但是兼容性(普適性)是優先考慮的點。
使用MediaCodec編碼時,通常是這樣設置的
先配置MediaCodecInfo的profile信息 然後賦給MediaFormat
codec.configure(format,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE);
最後設置給MediaCodec
編碼得到的碼流都是baseline profile的
這是由於android sdk本身的限制導致的
ACodec.cpp裏的對應處理如下:
if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
ALOGW("Use baseline profile instead of %d for AVC recording",
h264type.eProfile);
h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
}
在Android 7.0之後才移除了這段代碼。也就是說要想使用MP要求Android系統版本在7.0及其以上。
四、問題解決方案
4.1 方案一: 用戶上傳後先經過服務端的轉碼後,再下發給用戶
用戶上傳的視頻可能差別很大(封裝格式、編碼格式、採樣率、碼率、幀率、分辨率、YUV存儲格式等等),有些播放器可能對某些視頻支持的不太好。比如:有些設備不支持HEVC的解碼、有些解碼器不支持MPEG-4的編碼格式、有些播放器只支持YUV420P的格式、有些播放器對於幀率很高的視頻卡頓、有些播放器不支持播放4K等高清視頻 等等
針對上述情況,一種比較通用的做法是。用戶上傳後先經過服務端的轉碼後,再下發給其他用戶。進而保證視頻再各種設備上的兼容性。
4.2 方案二、編碼時的profie和level設置上線閥值
profile 最大值設置爲 MediaCodecInfo.CodecProfileLevel.AVCProfileHigh
Level 最大值設置爲 MediaCodecInfo.CodecProfileLevel.AVCLevel52
當從解碼器中遍歷的MediaCodecInfo.CodecProfileLevel的profie和level上述閥值時,用上述最大值。進而保證在各種設備的兼容性。
方案1是更加通用的解決方案,方案2則是腳痛醫腳的方案。
五、 資料
- H.264 and H.265 (HEVC)
- ffmpeg 常用命令
- H264編碼profile & level控制
- Using ffprobe to get info from a file in a nice JSON format
- Android MediaCodec參數筆記_
- Android MediaCodec h264編碼無法設爲high profile
六、收穫
通過本篇的學習
- 分析解決部分android設備上編碼的視頻,ios不能播放的問題
- 進一步熟悉Profile、Level的意義
感謝你的閱讀
歡迎關注公衆號“音視頻開發之旅”,一起學習成長。
歡迎交流