系列文章目录
文章目录
前言
在上一章 Android MediaCodec 简明教程(一) 我们学习了如何使用 MediaCodecList 查询本机支持的 Codec 信息。在 FFmpeg 中你可以使用下面代码做类似的事情:
void print_all_codecs() {
AVCodec *codec = NULL;
while ((codec = av_codec_next(codec)) != NULL) {
printf("Codec Name: %s\n", codec->name);
}
}
本章将介绍 MediaCodecInfo.CodecCapabilities 类,它是 Android 音视频任务中非常有用的工具类。通过该类,我们可以查询 codec 的能力,包括支持的宽高、颜色空间、Profile 等信息。这些信息对于选择合适的 Codec 来解码或编码视频文件非常重要,也可以帮助我们发现某些特殊格式 Android 机器无法支持的情况,从而采用其他方案,如 FFmpeg 等。因此,掌握 MediaCodecInfo.CodecCapabilities 类的使用方法对于 Android 音视频开发非常有帮助。
一、MediaCodecInfo.CodecCapabilities 是什么?
MediaCodecInfo.CodecCapabilities 是Android中的一个类,它提供了关于特定编解码器的功能的信息。这包括编解码器支持的颜色格式,是否支持适应性的视频播放,以及编解码器的复杂性等等。
这个类主要用于开发者在使用MediaCodec API进行音视频编解码时,获取和设置编解码器的相关参数。例如,开发者可以通过这个类查询编解码器是否支持特定的视频分辨率或者帧率,然后根据查询结果设置合适的参数,以达到最佳的编解码效果。
二、MediaCodecInfo.CodecCapabilities 使用方法
2.1 获取 MediaCodecInfo.CodecCapabilities 对象
要使用 MediaCodecInfo.CodecCapabilities,首先需要获取 MediaCodecInfo 对象,然后调用其getCapabilitiesForType(String type)
方法来获取 CodecCapabilities 对象。
MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
for (MediaCodecInfo codecInfo : codecInfos) {
// 获取编解码器支持的类型(如:"video/avc","audio/mp4a-latm"等)
String[] types = codecInfo.getSupportedTypes();
for (String type : types) {
// 获取特定类型的编解码器能力信息
MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(type);
// ...
}
}
2.2 MediaCodecInfo.CodecCapabilities 接口说明
一些比较重要接口的说明
isFormatSupported(MediaFormat format)
,查询是否支持这种 FormatgetMimeType
,返回 MIME 类型。MIME类型是一种标识文件或数据格式的方式,常用于网络传输、电子邮件和文件存储等场景。在Android的媒体框架中,MIME类型用于标识不同的音频、视频和图像格式。例如,"video/avc"表示H.264视频,"audio/mp4a-latm"表示AAC音频,"image/jpeg"表示JPEG图像等。getDefaultFormat
,返回一个带有默认配置值的MediaFormat对象。MediaFormat是Android中用于描述音频/视频格式的类,它包含了一系列的键值对,用于指定媒体数据的各种属性,如编码格式、分辨率、比特率、帧率等。getDefaultFormat()方法返回的MediaFormat对象包含了编解码器的默认配置。例如,对于一个视频编解码器,这可能包括默认的分辨率、帧率、比特率等。这个方法提供了一种方便的方式来获取编解码器的默认设置,开发者可以在此基础上进行修改,以满足特定的需求。例如,你可能想要改变视频的分辨率或帧率,你可以首先获取默认的MediaFormat,然后修改相应的值,最后将修改后的MediaFormat传递给MediaCodec的configure()方法。getMaxSupportedInstances
,它返回编解码器支持的最大并发实例数。这个方法返回的是一个上限提示,应用程序不应期望能够成功操作超过返回值的实例数。但是,实际上能够并发操作的实例数可能会更少,因为这取决于使用时可用的资源。例如,如果getMaxSupportedInstances()返回3,那么你可以预期在同一时间最多可以有3个编解码器实例在运行。但是,如果系统资源有限(如内存不足),那么实际上可能无法同时运行3个实例。这个方法对于理解和管理编解码器资源非常有用,特别是在处理多路音视频流的情况下。getAudioCapabilities()
它返回音频编解码器的能力信息。如果这个编解码器是一个音频编解码器,那么这个方法将返回一个AudioCapabilities对象,这个对象包含了编解码器支持的音频格式、采样率、声道数等信息。如果这个编解码器不是一个音频编解码器(例如,它可能是一个视频编解码器),那么这个方法将返回null。这个方法对于确定编解码器是否能够处理特定的音频格式,以及如何配置编解码器非常有用。例如,你可以使用这个方法来检查编解码器是否支持特定的采样率或声道数,然后根据这些信息来设置MediaFormat。getVideoCapabilities()
返回视频编解码器的能力信息。如果这个编解码器是一个视频编解码器,那么这个方法将返回一个VideoCapabilities对象,这个对象包含了编解码器支持的视频格式、分辨率、帧率等信息。如果这个编解码器不是一个视频编解码器(例如,它可能是一个音频编解码器),那么这个方法将返回null。getEncoderCapabilities()
方法是MediaCodecInfo.CodecCapabilities类的一个公共方法,它返回编码器的能力信息。如果这个编解码器是一个编码器,那么这个方法将返回一个EncoderCapabilities对象,这个对象包含了编码器支持的比特率范围、复杂度范围、质量等级等信息。如果这个编解码器不是一个编码器(例如,它可能是一个解码器),那么这个方法将返回null。
还记得 MediaCodecList 中的 findDecoderForFormat
和 findEncoderForFormat
方法吗?这两个方法其实遍历了所有 CodecCapabilities ,调用 isFormatSupported
方法,找到第一个支持此格式的 Codec。
三、查看你的 MediaCodecInfo.CodecCapabilities
在 learnmediacodec 中提供了一个打印本机 codec 能力的功能,它将所有 codec 信息转换 json 文件保存在本地,方便进行查看。你可以在 codec_info 找到笔者测试机上的 codec 信息,例如 huawei mate 20 上 hisi 的 avc 解码器信息:
{
"name": "OMX.hisi.video.decoder.avc",
"canonicalName": "OMX.hisi.video.decoder.avc",
"isEncoder": false,
"isHardwareAccelerated": true,
"isSoftwareOnly": false,
"isVendor": true,
"isAlias": false,
"capabilities": [
{
"mimeType": "video\/avc",
"maxSupportedInstances": 16,
"defaultFormat": "{mime=video\/avc, feature-adaptive-playback=1}",
"colorFormats": [
2135033992,
21,
2130706433
],
"profileLevels": [
{
"profile": 1,
"level": 1
},
// ...
{
"profile": 524288,
"level": 16384
},
{
"profile": 8,
"level": 32768
},
{
"profile": 524288,
"level": 32768
}
],
"videoCapabilities": {
"supportedWidths": "[128, 4096]",
"supportedHeights": "[128, 2304]",
"supportedFrameRates": "[0, 960]",
"bitrateRange": "[1, 100000000]",
"widthAlignment": 2,
"heightAlignment": 2,
"performancePoints": [
{
"PerformancePoint": "PerformancePoint(4096x2160@56)"
},
{
"PerformancePoint": "PerformancePoint(3840x2160@60)"
},
{
"PerformancePoint": "PerformancePoint(1920x1088@240)"
}
]
},
"audioCapabilities": {
},
"encoderCapabilities": {
}
}
]
},
其中
widthAlignment
和heightAlignment
是宽高的对齐要求,视频的宽度必须是2的某个整数次幂(例如2、4、8、16、32等)的倍数。举个例子,假设getWidthAlignment()返回的值是16,那么视频的宽度必须是16的倍数,如16、32、48、64等。如果你尝试设置一个不是16的倍数的宽度,比如15或者17,那么可能会导致错误。这样的要求通常是由于硬件编解码器的限制或优化。例如,一些硬件可能在处理宽度为16的倍数的视频数据时,可以更有效地访问内存,从而提高编解码效率PerformancePoint
,性能点是设备制造商为基于设备硬件能力的硬件编解码器提供的性能保证。每个性能点定义了一个特定的分辨率和帧率,编解码器保证能够在这个分辨率和帧率下正常工作。
MediaCodecList 的 findDecoderForFormat
和 findEncoderForFormat
找第一个符合条件的 Codec,我在测试时发现它们总能匹配到产商提供的 Codec,而不会先匹配到 Android 原生的 Codec,这是为啥?
打印了所有 Codec 信息后你可以发现,产商提供的同类型 Codec 总是在 Android 原生 Codec 之前,例如 AVC。
总结
本文介绍了 MediaCodecInfo.CodecCapabilities 基本使用,对其几个重要接口进行了详细的说明,并且提供了打印 Android 机器上所有 Codec CodecCapabilities 的参考代码,最后对 CodecCapabilities 中属性做了说明。相关代码可以在 learnmediacodec 中找到。
文章评论