private static DecoderProperties findDecoder(String mime, String[] supportedCodecPrefixes) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
      return null; // MediaCodec.setParameters is missing.
    }
    for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) {
      MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
      if (info.isEncoder()) {
        continue;
      }
      String name = null;
      for (String mimeType : info.getSupportedTypes()) {
        if (mimeType.equals(mime)) {
          name = info.getName();
          break;
        }
      }
      if (name == null) {
        continue; // No HW support in this codec; try the next one.
      }
      Logging.v(TAG, "Found candidate decoder " + name);

      // Check if this is supported decoder.
      boolean supportedCodec = false;
      for (String codecPrefix : supportedCodecPrefixes) {
        if (name.startsWith(codecPrefix)) {
          supportedCodec = true;
          break;
        }
      }
      if (!supportedCodec) {
        continue;
      }

      // Check if codec supports either yuv420 or nv12.
      CodecCapabilities capabilities = info.getCapabilitiesForType(mime);
      for (int colorFormat : capabilities.colorFormats) {
        Logging.v(TAG, "   Color: 0x" + Integer.toHexString(colorFormat));
      }
      for (int supportedColorFormat : supportedColorList) {
        for (int codecColorFormat : capabilities.colorFormats) {
          if (codecColorFormat == supportedColorFormat) {
            // Found supported HW decoder.
            Logging.d(
                TAG,
                "Found target decoder "
                    + name
                    + ". Color: 0x"
                    + Integer.toHexString(codecColorFormat));
            return new DecoderProperties(name, codecColorFormat);
          }
        }
      }
    }
    return null; // No HW decoder.
  }
  /**
   * Creates new instance of <tt>CodecInfo</tt> that will encapsulate given <tt>codecInfo</tt>.
   *
   * @param codecInfo the codec info object to encapsulate.
   * @param mediaType media type of the codec
   */
  public CodecInfo(MediaCodecInfo codecInfo, String mediaType) {
    this.codecInfo = codecInfo;
    this.mediaType = mediaType;
    this.caps = codecInfo.getCapabilitiesForType(mediaType);

    this.colors = new ArrayList<CodecColorFormat>();
    int[] colorFormats = caps.colorFormats;
    for (int colorFormat : colorFormats) {
      colors.add(CodecColorFormat.fromInt(colorFormat));
    }
  }
예제 #3
0
  @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;
  }
예제 #4
0
  @SuppressWarnings("RedundantThrows")
  public static String dumpDecoders() throws Exception {
    String str = "";
    for (MediaCodecInfo codecInfo : getMediaCodecList()) {
      // Skip encoders
      if (codecInfo.isEncoder()) {
        continue;
      }

      str += "Decoder: " + codecInfo.getName() + "\n";
      for (String type : codecInfo.getSupportedTypes()) {
        str += "\t" + type + "\n";
        CodecCapabilities caps = codecInfo.getCapabilitiesForType(type);

        for (CodecProfileLevel profile : caps.profileLevels) {
          str += "\t\t" + profile.profile + " " + profile.level + "\n";
        }
      }
    }
    return str;
  }
예제 #5
0
  // We declare this method as explicitly throwing Exception
  // since some bad decoders can throw IllegalArgumentExceptions unexpectedly
  // and we want to be sure all callers are handling this possibility
  @SuppressWarnings("RedundantThrows")
  private static MediaCodecInfo findKnownSafeDecoder(String mimeType, int requiredProfile)
      throws Exception {
    for (MediaCodecInfo codecInfo : getMediaCodecList()) {
      // Skip encoders
      if (codecInfo.isEncoder()) {
        continue;
      }

      // Check for explicitly blacklisted decoders
      if (isDecoderInList(blacklistedDecoderPrefixes, codecInfo.getName())) {
        LimeLog.info("Skipping blacklisted decoder: " + codecInfo.getName());
        continue;
      }

      // Find a decoder that supports the requested video format
      for (String mime : codecInfo.getSupportedTypes()) {
        if (mime.equalsIgnoreCase(mimeType)) {
          LimeLog.info("Examining decoder capabilities of " + codecInfo.getName());

          CodecCapabilities caps = codecInfo.getCapabilitiesForType(mime);

          if (requiredProfile != -1) {
            for (CodecProfileLevel profile : caps.profileLevels) {
              if (profile.profile == requiredProfile) {
                LimeLog.info("Decoder " + codecInfo.getName() + " supports required profile");
                return codecInfo;
              }
            }

            LimeLog.info("Decoder " + codecInfo.getName() + " does NOT support required profile");
          } else {
            return codecInfo;
          }
        }
      }
    }

    return null;
  }
예제 #6
0
  private boolean supports(String mimeType, int profile, int level, boolean testLevel) {
    int numCodecs = MediaCodecList.getCodecCount();
    for (int i = 0; i < numCodecs; i++) {
      MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
      if (codecInfo.isEncoder()) {
        continue;
      }

      if (!supportsMimeType(codecInfo, mimeType)) {
        continue;
      }

      CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
      for (CodecProfileLevel profileLevel : capabilities.profileLevels) {
        if (profileLevel.profile == profile && (!testLevel || profileLevel.level >= level)) {
          return true;
        }
      }
    }

    return false;
  }
예제 #7
0
  @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");
    }
  }