@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};