0. 前言
MediaCodec是Android多媒体框架提供的编解码组件,它为上层应用提供了访问底层编码器的能力,并且不同于ffmpeg编解码的软件实现,MediaCodec提供了硬件加速的能力,在速度上会更具优势。
MediaCodec的实现与Android的系统版本,具体的硬件平台等都有关联,因此不同的手机,所支持的能力也都不一样,所以在使用前,需要查询到所支持的Codec信息。
在正式学习MediaCodec之前,我们先了解一下如何使用MediaCodecList和MediaCodecInfo来获取Android编解码器的信息。
1. MediaCodecList
MediaCodecList用于列举所有应用层可以访问到的编解码器信息,其具体的信息存放在MediaCodecInfo结构体内。
我们可以通过MeidaCodecList的构造函数来获得当前机器所有可以访问的编解码器,值得注意的是,MediaCodecList的构造函数需要制定一个kind的值,分别是常量REGULAR_CODECS和ALL_CODECS。一般来说,我们使用REGULAR_CODECS标志则可。
ALL_CODECS包含所有可以被设备访问到的编解码器(包括非常规使用的),如厂商专属编解码器,测试或实验性编解码器,过时的编解码器,特殊用途编解码器(如专用VR、AR应用等)。
REGULAR_CODECS用于获取设备上常规编解码器列表的标志,常常用于过滤和提取那些通常被应用程序广泛使用并被正式支持的编解码器。这样做可以帮助开发者确保其应用程序兼容性更好,因为这些编解码器是系统常规推荐和优化的。
public static final int REGULAR_CODECS = 0;
public static final int ALL_CODECS = 1;
// kind可以是上述的两个枚举值之一。
public MediaCodecList(int kind);
2. MediaCodecInfo
MediaCodecInfo记录了一个编解码器所支持的全部能力,以及参数限制。具体能力可以由其组合的成员MediaCodecInfo.CodecCapabilities, MediaCodecInfo.VideoCapabilities,MediaCodecInfo.AudioCapabilities, MediaCodecInfo.EncoderCapabilities中获取,主要结构和能力可参见下面脑图:
3. 🌰例子
protected void showCodecList() {
MediaCodecList codecList = new MediaCodecList(REGULAR_CODECS);
MediaCodecInfo[] infos = codecList.getCodecInfos();
for(int i = 0; i < infos.length; ++i) {
String codecName = infos[i].getName();
boolean isHw = false;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
isHw = infos[i].isHardwareAccelerated();
}
// 编码器名,是否支持硬件加速
Log.d(TAG, i + " CodecName : " + codecName + ", isHw : " + isHw);
// 所支持的media types, 和MIME相对应
String[] supportTypes = infos[i].getSupportedTypes();
for(String type : supportTypes) {
Log.d(TAG, " - type : " + type);
MediaCodecInfo.CodecCapabilities capabilities = infos[i].getCapabilitiesForType(type);
// 对应视频时的能力限制
MediaCodecInfo.VideoCapabilities videoCapabilities = capabilities.getVideoCapabilities();
if(videoCapabilities != null) {
Log.d(TAG, " ---- videoCapabilities : ");
Range<Integer> bitrateRange = videoCapabilities.getBitrateRange();
Log.d(TAG, " ------ bitrate : [" + bitrateRange.getLower() + ", " + bitrateRange.getUpper() + "]");
Range<Integer> fpsRange = videoCapabilities.getSupportedFrameRates();
Log.d(TAG, " ------ fps : [" + fpsRange.getLower() + ", " + fpsRange.getUpper() + "]");
Range<Integer> widthRange = videoCapabilities.getSupportedWidths();
int widthAlignment = videoCapabilities.getWidthAlignment();
Log.d(TAG, " ------ widthRagne : [" + widthRange.getLower() + ", " + widthRange.getUpper() + "], widthAlignment : " + widthAlignment);
Range<Integer> heightRange = videoCapabilities.getSupportedHeights();
int heightAlignment = videoCapabilities.getHeightAlignment();
Log.d(TAG, " ------ heightRange : [" + heightRange.getLower() + ", " + heightRange.getUpper() + "], heightAlignment : " + heightAlignment);
}
// 对应音频时的能力限制
MediaCodecInfo.AudioCapabilities audioCapabilities = capabilities.getAudioCapabilities();
if(audioCapabilities != null) {
Log.d(TAG, " ---- audioCapabilities : ");
Range<Integer> bitrateRange = audioCapabilities.getBitrateRange();
Log.d(TAG, " ------ bitrate : [" + bitrateRange.getLower() + ", " + bitrateRange.getUpper() + "]");
int[] sampleRates = audioCapabilities.getSupportedSampleRates();
Log.d(TAG, " ------ sampleRate : " + Arrays.toString(sampleRates));
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
Range<Integer>[] channelCountRange = audioCapabilities.getInputChannelCountRanges();
String str = "";
if(channelCountRange.length > 0) {
for(Range<Integer> range : channelCountRange) {
str += "[" + range.getLower() + "," + range.getUpper() + "], ";
}
Log.d(TAG, " ------ channelCountRange : " + str);
}
}
}
}
}
}