001package com.baidu.cloud.media.player; 002 003import android.annotation.TargetApi; 004import android.media.MediaCodecInfo; 005import android.media.MediaCodecInfo.CodecCapabilities; 006import android.media.MediaCodecInfo.CodecProfileLevel; 007import android.os.Build; 008import android.text.TextUtils; 009import android.util.Log; 010 011import java.util.Locale; 012import java.util.Map; 013import java.util.TreeMap; 014 015public class BDCloudMediaCodecInfo { 016 private static final String TAG = "BDCloudMediaCodecInfo"; 017 018 public static final int RANK_MAX = 1000; 019 public static final int RANK_TESTED = 800; 020 public static final int RANK_ACCEPTABLE = 700; 021 public static final int RANK_LAST_CHANCE = 600; 022 public static final int RANK_SECURE = 300; 023 public static final int RANK_SOFTWARE = 200; 024 public static final int RANK_NON_STANDARD = 100; 025 public static final int RANK_NO_SENSE = 0; 026 027 public MediaCodecInfo mCodecInfo; 028 public int mRank = 0; 029 public String mMimeType; 030 031 private static Map<String, Integer> sKnownCodecList; 032 033 private static synchronized Map<String, Integer> getKnownCodecList() { 034 if (sKnownCodecList != null) { 035 return sKnownCodecList; 036 } 037 038 sKnownCodecList = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER); 039 040 // ----- Nvidia ----- 041 // Tegra3 042 // Nexus 7 (2012) 043 // Tegra K1 044 // Nexus 9 045 sKnownCodecList.put("OMX.Nvidia.h264.decode", RANK_TESTED); 046 sKnownCodecList.put("OMX.Nvidia.h264.decode.secure", RANK_SECURE); 047 048 // ----- Intel ----- 049 // Atom Z3735 050 // Teclast X98 Air 051 sKnownCodecList.put("OMX.Intel.hw_vd.h264", RANK_TESTED + 1); 052 // Atom Z2560 053 // Dell Venue 7 3730 054 sKnownCodecList.put("OMX.Intel.VideoDecoder.AVC", RANK_TESTED); 055 056 // ----- Qualcomm ----- 057 // MSM8260 058 // Xiaomi MI 1S 059 sKnownCodecList.put("OMX.qcom.video.decoder.avc", RANK_TESTED); 060 sKnownCodecList.put("OMX.ittiam.video.decoder.avc", RANK_NO_SENSE); 061 062 // ----- Samsung ----- 063 // Exynos 3110 064 // Nexus S 065 sKnownCodecList.put("OMX.SEC.avc.dec", RANK_TESTED); 066 sKnownCodecList.put("OMX.SEC.AVC.Decoder", RANK_TESTED - 1); 067 // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100 068 sKnownCodecList.put("OMX.SEC.avcdec", RANK_TESTED - 2); 069 sKnownCodecList.put("OMX.SEC.avc.sw.dec", RANK_SOFTWARE); 070 // Exynos 5 ? 071 sKnownCodecList.put("OMX.Exynos.avc.dec", RANK_TESTED); 072 sKnownCodecList.put("OMX.Exynos.AVC.Decoder", RANK_TESTED - 1); 073 074 // ------ Huawei hisilicon ------ 075 // Kirin 910, Mali 450 MP 076 // Huawei HONOR 3C (H30-L01) 077 sKnownCodecList.put("OMX.k3.video.decoder.avc", RANK_TESTED); 078 // Kirin 920, Mali T624 079 // Huawei HONOR 6 080 sKnownCodecList.put("OMX.IMG.MSVDX.Decoder.AVC", RANK_TESTED); 081 082 // ----- TI ----- 083 // TI OMAP4460 084 // Galaxy Nexus 085 sKnownCodecList.put("OMX.TI.DUCATI1.VIDEO.DECODER", RANK_TESTED); 086 087 // ------ RockChip ------ 088 // Youku TVBox 089 sKnownCodecList.put("OMX.rk.video_decoder.avc", RANK_TESTED); 090 091 // ------ AMLogic ----- 092 // MiBox1, 1s, 2 093 sKnownCodecList.put("OMX.amlogic.avc.decoder.awesome", RANK_TESTED); 094 095 // ------ Marvell ------ 096 // Lenovo A788t 097 sKnownCodecList.put("OMX.MARVELL.VIDEO.HW.CODA7542DECODER", RANK_TESTED); 098 sKnownCodecList.put("OMX.MARVELL.VIDEO.H264DECODER", RANK_SOFTWARE); 099 100 // ----- TODO: need test ----- 101 sKnownCodecList.remove("OMX.Action.Video.Decoder"); 102 sKnownCodecList.remove("OMX.allwinner.video.decoder.avc"); 103 sKnownCodecList.remove("OMX.BRCM.vc4.decoder.avc"); 104 sKnownCodecList.remove("OMX.brcm.video.h264.hw.decoder"); 105 sKnownCodecList.remove("OMX.brcm.video.h264.decoder"); 106 sKnownCodecList.remove("OMX.cosmo.video.decoder.avc"); 107 sKnownCodecList.remove("OMX.duos.h264.decoder"); 108 sKnownCodecList.remove("OMX.hantro.81x0.video.decoder"); 109 sKnownCodecList.remove("OMX.hantro.G1.video.decoder"); 110 sKnownCodecList.remove("OMX.hisi.video.decoder"); 111 sKnownCodecList.remove("OMX.LG.decoder.video.avc"); 112 sKnownCodecList.remove("OMX.MS.AVC.Decoder"); 113 sKnownCodecList.remove("OMX.RENESAS.VIDEO.DECODER.H264"); 114 sKnownCodecList.remove("OMX.RTK.video.decoder"); 115 sKnownCodecList.remove("OMX.sprd.h264.decoder"); 116 sKnownCodecList.remove("OMX.ST.VFM.H264Dec"); 117 sKnownCodecList.remove("OMX.vpu.video_decoder.avc"); 118 sKnownCodecList.remove("OMX.WMT.decoder.avc"); 119 120 // Really ? 121 sKnownCodecList.remove("OMX.bluestacks.hw.decoder"); 122 123 // --------------- 124 // Useless codec 125 // ----- google ----- 126 sKnownCodecList.put("OMX.google.h264.decoder", RANK_SOFTWARE); 127 sKnownCodecList.put("OMX.google.h264.lc.decoder", RANK_SOFTWARE); 128 // ----- huawei k920 ----- 129 sKnownCodecList.put("OMX.k3.ffmpeg.decoder", RANK_SOFTWARE); 130 sKnownCodecList.put("OMX.ffmpeg.video.decoder", RANK_SOFTWARE); 131 // ----- unknown ----- 132 sKnownCodecList.put("OMX.sprd.soft.h264.decoder", RANK_SOFTWARE); 133 134 return sKnownCodecList; 135 } 136 137 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 138 public static BDCloudMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo, String mimeType) { 139 if (codecInfo == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 140 return null; 141 } 142 143 String name = codecInfo.getName(); 144 if (TextUtils.isEmpty(name)) { 145 return null; 146 } 147 148 name = name.toLowerCase(Locale.US); 149 int rank = RANK_NO_SENSE; 150 if (!name.startsWith("omx.")) { 151 rank = RANK_NON_STANDARD; 152 } else if (name.startsWith("omx.pv")) { 153 rank = RANK_SOFTWARE; 154 } else if (name.startsWith("omx.google.")) { 155 rank = RANK_SOFTWARE; 156 } else if (name.startsWith("omx.ffmpeg.")) { 157 rank = RANK_SOFTWARE; 158 } else if (name.startsWith("omx.k3.ffmpeg.")) { 159 rank = RANK_SOFTWARE; 160 } else if (name.startsWith("omx.avcodec.")) { 161 rank = RANK_SOFTWARE; 162 } else if (name.startsWith("omx.ittiam.")) { 163 // unknown codec in qualcomm SoC 164 rank = RANK_NO_SENSE; 165 } else if (name.startsWith("omx.mtk.")) { 166 // 1. MTK only works on 4.3 and above 167 // 2. MTK works on MIUI 6 (4.2.1) 168 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { 169 rank = RANK_NO_SENSE; 170 } else { 171 rank = RANK_TESTED; 172 } 173 } else { 174 Integer knownRank = getKnownCodecList().get(name); 175 if (knownRank != null) { 176 rank = knownRank; 177 } else { 178 try { 179 CodecCapabilities cap = codecInfo.getCapabilitiesForType(mimeType); 180 if (cap != null) { 181 rank = RANK_ACCEPTABLE; 182 } else { 183 rank = RANK_LAST_CHANCE; 184 } 185 } catch (Throwable e) { 186 rank = RANK_LAST_CHANCE; 187 } 188 } 189 } 190 191 BDCloudMediaCodecInfo candidate = new BDCloudMediaCodecInfo(); 192 candidate.mCodecInfo = codecInfo; 193 candidate.mRank = rank; 194 candidate.mMimeType = mimeType; 195 return candidate; 196 } 197 198 @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 199 public void dumpProfileLevels(String mimeType) { 200 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { 201 return; 202 } 203 204 try { 205 CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mimeType); 206 int maxProfile = 0; 207 int maxLevel = 0; 208 if (caps != null) { 209 if (caps.profileLevels != null) { 210 for (CodecProfileLevel profileLevel : caps.profileLevels) { 211 if (profileLevel == null) { 212 continue; 213 } 214 215 maxProfile = Math.max(maxProfile, profileLevel.profile); 216 maxLevel = Math.max(maxLevel, profileLevel.level); 217 } 218 } 219 } 220 221 Log.i(TAG, String.format(Locale.US, "%s", getProfileLevelName(maxProfile, maxLevel))); 222 } catch (Throwable e) { 223 Log.i(TAG, "profile-level: exception"); 224 } 225 } 226 227 public static String getProfileLevelName(int profile, int level) { 228 return String.format(Locale.US, " %s Profile Level %s (%d,%d)", getProfileName(profile), getLevelName(level), 229 profile, level); 230 } 231 232 public static String getProfileName(int profile) { 233 switch (profile) { 234 case CodecProfileLevel.AVCProfileBaseline: 235 return "Baseline"; 236 case CodecProfileLevel.AVCProfileMain: 237 return "Main"; 238 case CodecProfileLevel.AVCProfileExtended: 239 return "Extends"; 240 case CodecProfileLevel.AVCProfileHigh: 241 return "High"; 242 case CodecProfileLevel.AVCProfileHigh10: 243 return "High10"; 244 case CodecProfileLevel.AVCProfileHigh422: 245 return "High422"; 246 case CodecProfileLevel.AVCProfileHigh444: 247 return "High444"; 248 default: 249 return "Unknown"; 250 } 251 } 252 253 public static String getLevelName(int level) { 254 switch (level) { 255 case CodecProfileLevel.AVCLevel1: 256 return "1"; 257 case CodecProfileLevel.AVCLevel1b: 258 return "1b"; 259 case CodecProfileLevel.AVCLevel11: 260 return "11"; 261 case CodecProfileLevel.AVCLevel12: 262 return "12"; 263 case CodecProfileLevel.AVCLevel13: 264 return "13"; 265 case CodecProfileLevel.AVCLevel2: 266 return "2"; 267 case CodecProfileLevel.AVCLevel21: 268 return "21"; 269 case CodecProfileLevel.AVCLevel22: 270 return "22"; 271 case CodecProfileLevel.AVCLevel3: 272 return "3"; 273 case CodecProfileLevel.AVCLevel31: 274 return "31"; 275 case CodecProfileLevel.AVCLevel32: 276 return "32"; 277 case CodecProfileLevel.AVCLevel4: 278 return "4"; 279 case CodecProfileLevel.AVCLevel41: 280 return "41"; 281 case CodecProfileLevel.AVCLevel42: 282 return "42"; 283 case CodecProfileLevel.AVCLevel5: 284 return "5"; 285 case CodecProfileLevel.AVCLevel51: 286 return "51"; 287 case 65536: // CodecProfileLevel.AVCLevel52: 288 return "52"; 289 default: 290 return "0"; 291 } 292 } 293}