content: package tv.danmaku.ijk.media.player;
  
  import android.annotation.TargetApi;
  import android.media.MediaCodecInfo;
  import android.media.MediaCodecInfo.CodecCapabilities;
  import android.media.MediaCodecInfo.CodecProfileLevel;
  import android.os.Build;
  import android.text.TextUtils;
  import android.util.Log;
  
  import java.util.Locale;
  import java.util.Map;
  import java.util.TreeMap;
  
  public class IjkMediaCodecInfo {
      private final static String TAG = "IjkMediaCodecInfo";
  
      public static final int RANK_MAX = 1000;
      public static final int RANK_TESTED = 800;
      public static final int RANK_ACCEPTABLE = 700;
      public static final int RANK_LAST_CHANCE = 600;
      public static final int RANK_SECURE = 300;
      public static final int RANK_SOFTWARE = 200;
      public static final int RANK_NON_STANDARD = 100;
      public static final int RANK_NO_SENSE = 0;
  
      public MediaCodecInfo mCodecInfo;
      public int mRank = 0;
      public String mMimeType;
  
      private static Map<String, Integer> sKnownCodecList;
  
      private static synchronized Map<String, Integer> getKnownCodecList() {
          if (sKnownCodecList != null)
              return sKnownCodecList;
  
          sKnownCodecList = new TreeMap<String, Integer>(
                  String.CASE_INSENSITIVE_ORDER);
  
          // ----- Nvidia -----
          // Tegra3
          // Nexus 7 (2012)
          // Tegra K1
          // Nexus 9
          sKnownCodecList.put("OMX.Nvidia.h264.decode", RANK_TESTED);
          sKnownCodecList.put("OMX.Nvidia.h264.decode.secure", RANK_SECURE);
  
          // ----- Intel -----
          // Atom Z3735
          // Teclast X98 Air
          sKnownCodecList.put("OMX.Intel.hw_vd.h264", RANK_TESTED + 1);
          // Atom Z2560
          // Dell Venue 7 3730
          sKnownCodecList.put("OMX.Intel.VideoDecoder.AVC", RANK_TESTED);
  
          // ----- Qualcomm -----
          // MSM8260
          // Xiaomi MI 1S
          sKnownCodecList.put("OMX.qcom.video.decoder.avc", RANK_TESTED);
          sKnownCodecList.put("OMX.ittiam.video.decoder.avc", RANK_NO_SENSE);
  
          // ----- Samsung -----
          // Exynos 3110
          // Nexus S
          sKnownCodecList.put("OMX.SEC.avc.dec", RANK_TESTED);
          sKnownCodecList.put("OMX.SEC.AVC.Decoder", RANK_TESTED - 1);
          // OMX.SEC.avcdec doesn't reorder output pictures on GT-9100
          sKnownCodecList.put("OMX.SEC.avcdec", RANK_TESTED - 2);
          sKnownCodecList.put("OMX.SEC.avc.sw.dec", RANK_SOFTWARE);
          // Exynos 5 ?
          sKnownCodecList.put("OMX.Exynos.avc.dec", RANK_TESTED);
          sKnownCodecList.put("OMX.Exynos.AVC.Decoder", RANK_TESTED - 1);
  
          // ------ Huawei hisilicon ------
          // Kirin 910, Mali 450 MP
          // Huawei HONOR 3C (H30-L01)
          sKnownCodecList.put("OMX.k3.video.decoder.avc", RANK_TESTED);
          // Kirin 920, Mali T624
          // Huawei HONOR 6
          sKnownCodecList.put("OMX.IMG.MSVDX.Decoder.AVC", RANK_TESTED);
  
          // ----- TI -----
          // TI OMAP4460
          // Galaxy Nexus
          sKnownCodecList.put("OMX.TI.DUCATI1.VIDEO.DECODER", RANK_TESTED);
  
          // ------ RockChip ------
          // Youku TVBox
          sKnownCodecList.put("OMX.rk.video_decoder.avc", RANK_TESTED);
  
          // ------ AMLogic -----
          // MiBox1, 1s, 2
          sKnownCodecList.put("OMX.amlogic.avc.decoder.awesome", RANK_TESTED);
  
          // ------ Marvell ------
          // Lenovo A788t
          sKnownCodecList.put("OMX.MARVELL.VIDEO.HW.CODA7542DECODER", RANK_TESTED);
          sKnownCodecList.put("OMX.MARVELL.VIDEO.H264DECODER", RANK_SOFTWARE);
  
          // ----- TODO: need test -----
          sKnownCodecList.remove("OMX.Action.Video.Decoder");
          sKnownCodecList.remove("OMX.allwinner.video.decoder.avc");
          sKnownCodecList.remove("OMX.BRCM.vc4.decoder.avc");
          sKnownCodecList.remove("OMX.brcm.video.h264.hw.decoder");
          sKnownCodecList.remove("OMX.brcm.video.h264.decoder");
          sKnownCodecList.remove("OMX.cosmo.video.decoder.avc");
          sKnownCodecList.remove("OMX.duos.h264.decoder");
          sKnownCodecList.remove("OMX.hantro.81x0.video.decoder");
          sKnownCodecList.remove("OMX.hantro.G1.video.decoder");
          sKnownCodecList.remove("OMX.hisi.video.decoder");
          sKnownCodecList.remove("OMX.LG.decoder.video.avc");
          sKnownCodecList.remove("OMX.MS.AVC.Decoder");
          sKnownCodecList.remove("OMX.RENESAS.VIDEO.DECODER.H264");
          sKnownCodecList.remove("OMX.RTK.video.decoder");
          sKnownCodecList.remove("OMX.sprd.h264.decoder");
          sKnownCodecList.remove("OMX.ST.VFM.H264Dec");
          sKnownCodecList.remove("OMX.vpu.video_decoder.avc");
          sKnownCodecList.remove("OMX.WMT.decoder.avc");
  
          // Really ?
          sKnownCodecList.remove("OMX.bluestacks.hw.decoder");
  
          // ---------------
          // Useless codec
          // ----- google -----
          sKnownCodecList.put("OMX.google.h264.decoder", RANK_SOFTWARE);
          sKnownCodecList.put("OMX.google.h264.lc.decoder", RANK_SOFTWARE);
          // ----- huawei k920 -----
          sKnownCodecList.put("OMX.k3.ffmpeg.decoder", RANK_SOFTWARE);
          sKnownCodecList.put("OMX.ffmpeg.video.decoder", RANK_SOFTWARE);
          // ----- unknown -----
          sKnownCodecList.put("OMX.sprd.soft.h264.decoder", RANK_SOFTWARE);
  
          return sKnownCodecList;
      }
  
      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
      public static IjkMediaCodecInfo setupCandidate(MediaCodecInfo codecInfo,
              String mimeType) {
          if (codecInfo == null
                  || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
              return null;
  
          String name = codecInfo.getName();
          if (TextUtils.isEmpty(name))
              return null;
  
          name = name.toLowerCase(Locale.US);
          int rank = RANK_NO_SENSE;
          if (!name.startsWith("omx.")) {
              rank = RANK_NON_STANDARD;
          } else if (name.startsWith("omx.pv")) {
              rank = RANK_SOFTWARE;
          } else if (name.startsWith("omx.google.")) {
              rank = RANK_SOFTWARE;
          } else if (name.startsWith("omx.ffmpeg.")) {
              rank = RANK_SOFTWARE;
          } else if (name.startsWith("omx.k3.ffmpeg.")) {
              rank = RANK_SOFTWARE;
          } else if (name.startsWith("omx.avcodec.")) {
              rank = RANK_SOFTWARE;
          } else if (name.startsWith("omx.ittiam.")) {
              // unknown codec in qualcomm SoC
              rank = RANK_NO_SENSE;
          } else if (name.startsWith("omx.mtk.")) {
              // 1. MTK only works on 4.3 and above
              // 2. MTK works on MIUI 6 (4.2.1)
              if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)
                  rank = RANK_NO_SENSE;
              else
                  rank = RANK_TESTED;
          } else {
              Integer knownRank = getKnownCodecList().get(name);
              if (knownRank != null) {
                  rank = knownRank;
              } else {
                  try {
                      CodecCapabilities cap = codecInfo
                              .getCapabilitiesForType(mimeType);
                      if (cap != null)
                          rank = RANK_ACCEPTABLE;
                      else
                          rank = RANK_LAST_CHANCE;
                  } catch (Throwable e) {
                      rank = RANK_LAST_CHANCE;
                  }
              }
          }
  
          IjkMediaCodecInfo candidate = new IjkMediaCodecInfo();
          candidate.mCodecInfo = codecInfo;
          candidate.mRank = rank;
          candidate.mMimeType = mimeType;
          return candidate;
      }
  
      @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
      public void dumpProfileLevels(String mimeType) {
          if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
              return;
  
          try {
              CodecCapabilities caps = mCodecInfo
                      .getCapabilitiesForType(mimeType);
              int maxProfile = 0;
              int maxLevel = 0;
              if (caps != null) {
                  if (caps.profileLevels != null) {
                      for (CodecProfileLevel profileLevel : caps.profileLevels) {
                          if (profileLevel == null)
                              continue;
  
                          maxProfile = Math.max(maxProfile, profileLevel.profile);
                          maxLevel = Math.max(maxLevel, profileLevel.level);
                      }
                  }
              }
  
              Log.i(TAG,
                      String.format(Locale.US, "%s",
                              getProfileLevelName(maxProfile, maxLevel)));
          } catch (Throwable e) {
              Log.i(TAG, "profile-level: exception");
          }
      }
  
      public static String getProfileLevelName(int profile, int level) {
          return String.format(Locale.US, " %s Profile Level %s (%d,%d)",
                  getProfileName(profile), getLevelName(level), profile, level);
      }
  
      public static String getProfileName(int profile) {
          switch (profile) {
          case CodecProfileLevel.AVCProfileBaseline:
              return "Baseline";
          case CodecProfileLevel.AVCProfileMain:
              return "Main";
          case CodecProfileLevel.AVCProfileExtended:
              return "Extends";
          case CodecProfileLevel.AVCProfileHigh:
              return "High";
          case CodecProfileLevel.AVCProfileHigh10:
              return "High10";
          case CodecProfileLevel.AVCProfileHigh422:
              return "High422";
          case CodecProfileLevel.AVCProfileHigh444:
              return "High444";
          default:
              return "Unknown";
          }
      }
  
      public static String getLevelName(int level) {
          switch (level) {
          case CodecProfileLevel.AVCLevel1:
              return "1";
          case CodecProfileLevel.AVCLevel1b:
              return "1b";
          case CodecProfileLevel.AVCLevel11:
              return "11";
          case CodecProfileLevel.AVCLevel12:
              return "12";
          case CodecProfileLevel.AVCLevel13:
              return "13";
          case CodecProfileLevel.AVCLevel2:
              return "2";
          case CodecProfileLevel.AVCLevel21:
              return "21";
          case CodecProfileLevel.AVCLevel22:
              return "22";
          case CodecProfileLevel.AVCLevel3:
              return "3";
          case CodecProfileLevel.AVCLevel31:
              return "31";
          case CodecProfileLevel.AVCLevel32:
              return "32";
          case CodecProfileLevel.AVCLevel4:
              return "4";
          case CodecProfileLevel.AVCLevel41:
              return "41";
          case CodecProfileLevel.AVCLevel42:
              return "42";
          case CodecProfileLevel.AVCLevel5:
              return "5";
          case CodecProfileLevel.AVCLevel51:
              return "51";
          case 65536: // CodecProfileLevel.AVCLevel52:
              return "52";
          default:
              return "0";
          }
      }
  }
  