音視頻開發之旅(64) - 部分android手機上編碼的視頻在ios上無法播放

目錄

  1. 問題描述
  2. 問題分析
  3. 問題原因
  4. 問題解決
  5. 資料
  6. 收穫

一、問題描述

用小米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則是腳痛醫腳的方案。

五、 資料

  1. H.264 and H.265 (HEVC)
  2. ffmpeg 常用命令
  3. H264編碼profile & level控制
  4. Using ffprobe to get info from a file in a nice JSON format
  5. Android MediaCodec參數筆記_
  6. Android MediaCodec h264編碼無法設爲high profile

六、收穫

通過本篇的學習

  1. 分析解決部分android設備上編碼的視頻,ios不能播放的問題
  2. 進一步熟悉Profile、Level的意義

感謝你的閱讀
歡迎關注公衆號“音視頻開發之旅”,一起學習成長。
歡迎交流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章