一、問題背景
? ? ? ?考慮到Vulkan高性能的優勢,項目組決定打包設置為vulkan優先,opengl es次之的方案;但由于部分低端設備或者部分模擬器對Vulkan的兼容性良莠不齊,導致諸如使用VideoPlayer組件無法正常播放視頻等問題頻發,而這些問題在opengl es模式下不存在。鑒于Unity官方未在2022系列修復該問題,以及本項目優先使用Vulkan模式的需求,本方案決定在UnityPlayerActivity.java源文件或者自定義的UnityPlayerActivity入手,檢測設備是否支持特定特性,進而顯示指定以哪種模式啟動unity運行時。
二、問題原因
? ? ? ?根據問題設備日志可以發現,視頻為正常播放的根本原因可能原因在于設備廠商在定制vulkan驅動時,未充分兼容其所需特性,甚至不支持指定特性,并且在回退操作中可能處理不恰當,進而導致視頻播放異常。
? ? ? ? unity中在移動平臺下對mp4視頻文件默認處理成H264編碼格式(對應MIME為"video/avc"),在運行時優先使用硬件解碼,在不支持硬件解碼時回退到軟件解碼,而部分設備在vulkan模式下這個回退操作有問題,因此在啟動unity運行時前先檢測視頻解碼器是否支持硬件解碼,支持則走vulkan模式,不支持則走opengl es模式;對于部分特殊較老設備即使支持硬件解碼也會有問題,直接過濾解碼器關鍵字,強制設為opengl es模式。
三、解決辦法
? ? ? ?在UnityPlayerActivity.java源文件中新加硬件加速檢測方法,并在unity運行時啟動前檢測,根據檢測結果設置unity運行時啟動參數,vulkan為"-force-vulkan",opengl es為"-force-opengl";
//判斷指定MimeType視頻在當前平臺下是否支持硬件加速,不支持的話,在vulkan模式下大概率無法播放視頻,則切換為opengl es模式 public boolean isHardwareDecodeSupported(String mimeType) {Log.e("User", "---------------------------------mimeType Check-------------------------------");MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);ArrayList<String> ignoreList=new ArrayList<>();ignoreList.add("mtk");//mtk的soc比較低端,很容易出問題,直接忽略boolean _s = false;for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {if (codecInfo.isEncoder()) continue; // 僅檢查解碼器for (String type : codecInfo.getSupportedTypes()) {if (type.equalsIgnoreCase(mimeType)) {String name = codecInfo.getName().toLowerCase();Log.e("User", "decoder name:" + name);// 檢查是否為硬件加速if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {boolean support = false;try {support = codecInfo.isHardwareAccelerated();if (support) {for (String ignore:ignoreList){if (name.contains(ignore)) {Log.e("User", "ignore:" + name);return false;}}}} catch (Exception e) {Log.e("User", "isHardwareAccelerated not find");}if (support)Log.e("User", "HardwareAccelerate support:true");elseLog.e("User", "HardwareAccelerate support:false");if (!_s && support) {_s = support;}}}}}return _s;}
// Setup activity layout@Override protected void onCreate(Bundle savedInstanceState){requestWindowFeature(Window.FEATURE_NO_TITLE);super.onCreate(savedInstanceState);String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity"));boolean vulkansupport=isHardwareDecodeSupported("video/avc");// H.264 的 MIME 類型為 video/avcif(vulkansupport){cmdLine+=" -force-vulkan";Log.e("User","start in Vulkan mode!"+cmdLine);}else{cmdLine+=" -force-gles";Log.e("User","start in OpenGL ES mode!"+cmdLine);}getIntent().putExtra("unity", cmdLine);mUnityPlayer = new UnityPlayer(this, this);setContentView(mUnityPlayer);mUnityPlayer.requestFocus();}
? ? ? 引入依賴的java類
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import java.util.ArrayList;
四、相關參考
1、https://blog.csdn.net/gaozhaoyuyu/article/details/136299359
2、https://forum.unity.com/threads/videoplayer-dont-play-well-on-android-with-exynos-2100-s21-ultra.1460107/
3、https://forum.unity.com/threads/video-lags-on-android-device-in-unity-version-2022-3-14f1.1529137/#post-9541912