@mime:对h264,对应值是video/avc。 @supportedCodecPrefixes。查找四条件之三的名称前缀。找到的解码器name必须以该数组之一为前缀。 private static DecoderProperties findDecoder(String mime, String[] supportedCodecPrefixes) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { return null; // MediaCodec.setParameters is missing. } Logging.d(TAG, "Trying to find HW decoder for mime " + mime); for (int i = 0; i < MediaCodecList.getCodecCount(); ++i) { MediaCodecInfo info = null; try { info = MediaCodecList.getCodecInfoAt(i); } catch (IllegalArgumentException e) { Logging.e(TAG, "Cannot retrieve decoder codec info", e); } // 查找四条件之二:info的isEncoder必须是false。 if (info == null || info.isEncoder()) { continue; } String name = null; // 查找四条件之一:mime必须一致。 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.d(TAG, "Found candidate decoder " + name); // 查找四条件之三:name必须以supportedCodecPrefixes数组之一为前缀。 // 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; try { capabilities = info.getCapabilitiesForType(mime); } catch (IllegalArgumentException e) { Logging.e(TAG, "Cannot retrieve decoder capabilities", e); continue; } for (int colorFormat : capabilities.colorFormats) { Logging.v(TAG, " Color: 0x" + Integer.toHexString(colorFormat)); } // 查找四条件之四:支持的颜色格式和supportedColorList必须有交集。 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); } } } } Logging.d(TAG, "No HW decoder found for mime " + mime); return null; // No HW decoder. }
要理解此函数,像参数mime有什么值,以及接下的MediaCodecList.getCodecCount/getCodecInfoAt、MediaCodecInfo,强烈建议先去看“kOS(6):MediaCodec”中的“1.1 MediaCodec”。
findDecoder用于查找系统中能解码mime格式的HW解码器。Andorid用一个MediaCodecInfo结构表示一个编/解码器,该MediaCodecInfo除mime要满足一致外,还有其它三个条件。
- mime。该MediaCodecInfo.mime必须等于参数mime。
- isEncoder。必须是false,表示这是一个解码器。true表示该MediaCodecInfo是个编码器。
- name。name字符串必须以supportedCodecPrefixes(一个数组)中的某个字符串开始。每种mime有不一样的supportedCodecPrefixes,因而它作为参数传给findDecoder。
- colorFormats。支持的颜色格式和supportedColorList(一个数组)有交集。所有mime有着一样的supportedColorList。
要注解这个函数,一个很重要原因是为支持更多Android设备,你需要修改一处webrtc源码,具体是:supportedCodecPrefixes。对h264,对应的是supportedH264HwCodecPrefixes。
private static final String[] supportedH264HwCodecPrefixes = { "OMX.qcom.", "OMX.Intel.", "OMX.Exynos."};
以上是官方webrtc给出的值。但是,市面上一些Android设备不在当中,以下是个人认为至少要加上两种后的版本。
private static final String[] supportedH264HwCodecPrefixes = { "OMX.qcom.", "OMX.Intel.", "OMX.Exynos.", "OMX.rk.", "OMX.hisi."};
- OMX.rk.:rk3288/rk3399主板,像Firefly的RK系列。
- OMX.hisi.:华为手机、PAD。
类似原因,要支持市面更多android设备,需修改MediaCodecVideoEecoder.java中的MediaCodecProperties。
private static final MediaCodecProperties rkH264HwProperties = new MediaCodecProperties( "OMX.rk.", Build.VERSION_CODES.LOLLIPOP, BitrateAdjustmentType.FRAMERATE_ADJUSTMENT); private static final MediaCodecProperties hisiH264HwProperties = new MediaCodecProperties( "OMX.hisi.", Build.VERSION_CODES.LOLLIPOP, BitrateAdjustmentType.FRAMERATE_ADJUSTMENT); private static final MediaCodecProperties[] h264HwList = new MediaCodecProperties[] {qcomH264HwProperties, exynosH264HwProperties, rkH264HwProperties, hisiH264HwProperties};