骁龙和高通品牌的产品是高通技术, Inc. 和/或其子公司的产品
如果您正在开发Android富媒体应用,就需要熟悉 Android API 中的MediaCodec 类。通过MediaCodec 可以访问低级媒体编码器/解码器 (CODEC) 组件,处理音频、视频和压缩数据,从而可以整合低延迟解码等功能来增强应用程序的功能。因此,如果在骁龙® 平台支持的设备上运行时,您可以借助我们的 MediaCodec 厂商扩展解锁更多功能。
下面我们仔细看看 MediaCodec 的工作原理及其使用方法。
MediaCodec 的工作原理
开发人员使用 MediaCodec 的方法如下:
- 应用(客户端)配置 MediaCodec
- MediaCodec 为您的应用提供空的输入缓冲区
- 应用使用数据填充缓冲区并将其发送给编解码器进行处理
- 编解码器转换接收到的缓冲区数据
- 转换后的数据通过输出缓冲区提供给您的应用
- 在应用生命周期结束时,应用将停止并释放 MediaCodec
工作流程如下图所示:
骁龙平台的功能
除了 Android API 提供的内置编解码器和功能之外,我们的 MediaCodec 扩展(可在 android-on-snapdragon 存储库中找到)还包括编解码器和其他功能,可解锁骁龙设备多种硬件加速功能:
感兴趣区域 (ROI) – 动态提高视频某些区域的图像质量。
长期参考帧 (LTR) – 对参考帧进行编码,用于未来帧的运动补偿预测。
编码器统计数据 – 提供描述场景复杂性的每帧统计数据。应用可以使用此信息动态控制编码参数(例如比特率)并调整预编码过滤,以实现更好的压缩效果,而不会造成高压缩伪影。
下图显示了Android 整体开发栈以及扩展的集成方式:
MediaCodec 扩展位于开发栈底部附近,靠近硬件
支持库(例如 Media3 或 CameraX)也可以使用扩展,在此情况下,这些扩展的某些功能可能已经启用。下图显示了支持库在开发栈中的位置:
支持库位于应用和Android SDK之间,可以访问厂商扩展提供的功能
设置 MediaCodec 厂商扩展的四个步骤
在运行时设置 MediaCodec 厂商扩展涉及以下步骤:
- 枚举设备支持的扩展
- 查询支持的扩展可以使用的值(例如值的范围)
- 将配置应用于扩展
下面我们详细地讨论每一个步骤。
1、枚举设备支持的扩展
在使用扩展之前,必须首先检查设备是否支持该扩展。实例化 MediaCodec 后,调用其 getSupportedVendorParameters() 方法,返回支持的扩展名称集合。如果你想使用的扩展名在集合中,则表示设备支持该扩展。
以下示例代码演示了如何检查是否可以在设备上使用高效视频编码 (HEVC) 编解码器:
MediaCodec codec = MediaCodec.createEncoderByType("video/hevc");
List supportedExtensions = codec.getSupportedVendorParameters();
if (supportedExtensions.indexOf(qti.video.KEY_INIT_QP_I_FRAME_ENABLE) != -1)
{
//Device supports extension
}
注意:有关 KEY_INIT_QP_I_FRAME_ENABLE 的定义,请参见。
2、查询支持的扩展可以使用的值
一旦确定设备支持您要使用的扩展,就需要确定它支持的参数(可能因设备而异)。
首先使用我们的 QMediaCodecCapabilities 类的 CreateForCodec() 方法请求扩展的功能,此时会返回支持的参数名称集合。如果您要使用的参数名称在列表中,则设备支持该参数。然后,调用 getParameterDescriptor() 来确定参数支持的值。
以下示例代码显示了如何检查 HEVC 编解码器是否支持 LTR:
MediaCodec codec = MediaCodec.createByCodecName("c2.qti.hevc.encoder");
// codec.getSupportedVendorParameters() should contain KEY_LTR_MAX_FRAMES, KEY_LTR_MARK_FRAME, KEY_LTR_USE_FRAME and KEY_LTR_RESPONSE
/*
* vendorParams should contain KEY_LTR_MAX_FRAMES, KEY_LTR_MARK_FRAME, KEY_LTR_USE_FRAME and KEY_LTR_RESPONSE
*/
if (supportedExtensions.indexOf(KEY_LTR_MAX_FRAMES) != -1
&& supportedExtensions.indexOf(KEY_LTR_MARK_FRAME) != -1
&& supportedExtensions.indexOf(KEY_LTR_USE_FRAME) != -1
&& supportedExtensions.indexOf(KEY_LTR_RESPONSE) != -1)
{
// LTR feature is supported }
QMediaCodecCapabilities qCodecCaps = QMediaCodecCapabilities.CreateForCodec("c2.qti.hevc.encoder", "video/hevc");
switch (descriptor.getType()) {
case MediaFormat.TYPE_INTEGER:
SupportedValues erLtrMaxFramesValues = qCodecCaps.getParameterRangeInteger(KEY_LTR_MAX_FRAMES);
if (intValues.getType() == SupportedValues.TYPE_RANGE) {
ValueRange intRange = intvalues.getRange();
// min: intRange.getMin()
// max: intRange.getMax()
// step: intRange.getstep()
) else {
// not a range
default:
//not integer value type
}
// qCodecCaps.getParameterDescriptor(KEY_ER_LTR_MARK_FRAME).getType() -> MediaFormat.TYPE_INTEGER
SupportedValues erLtrMarkFramesValues = qCodecCaps.getParameterRangeInteger(KEY_ER_LTR_MARK_FRAME);
// erLtrMarkFramesValues.getType() -> SupportedValues.TYPE_RANGE
// qCodecCaps.getParameterDescriptor(KEY_ER_LTR_USE_FRAME).getType() -> MediaFormat.TYPE_INTEGER
SupportedValues erLtrmaxFramesValues = qCodecCaps.getParameterRangeInteger(KEY_ER_LTR_USE_FRAME);
// erLtrmaxFramesValues.getType() -> SupportedValues.TYPE_RANGE
// qCodecCaps.getParameterDescriptor(KEY_ER_LTR_RESPONSE).getType() -> MediaFormat.TYPE_INTEGER
SupportedValues erLtrResponseValues = qCodecCaps.getParameterRangeInteger(KEY_ER_LTR_RESPONSE);
// erLtrResponseValues.getType() -> SupportedValues.TYPE_RANGE
3、将配置应用于厂商扩展
此时,您已获得配置支持的扩展所需的所有信息,现在可以配置在应用的整个生命周期中保持不变的静态扩展属性,以及可以随时更改的动态扩展属性。
首先检查您要使用的参数名称是否在支持的扩展列表中。对于静态扩展属性,请使用 MediaFormat 的 set 方法(例如 setInteger())来配置各种参数的名称/值对。然后将 MediaFormat 实例传递给MediaCodec 的 configure() 方法。
以下示例代码展示了如何设置分辨率为 1280x720 的 HEVC 的最大帧数:
MediaCodec codec = MediaCodec.createEncoderByType ("video/hevc");
MediaFormat format = MediaFormat.createVideoFormat("video/hevc", 1280, 720);
// check if the extension is supported first, before using it
if (supportedExtensions.indexOf{qti.video.KEY_LTR_MAX_COUNT_FRAME) == -1) {
// return error, extension KEY_LTR_MAX_COUNT_FRAME is not supported by the Android Device
}
else {
format.setInteger(qti.video.KEY_LTR_MAX_COUNT_FRAMES, 4);
codec.configure(format);
}
设置动态扩展属性的值与此类似,只不过键/值对存储在 Bundle 中并通过其 setParameters() 方法传递给 MediaCodec 实例。以下示例代码显示了如何为帧设置 QP 编号:
codec.start();
if (supportedExtensions.indexOf(qti.video.KEY_FRAME_QP) ! = -1) {
Bundle frameQP = new Bundle();
frameQP.setinteger(qti.video.KEY_FRAME_QP, 24);
codec.setParameters(frameQP);
codec.queueinputBuffer(...);
}
结论
Android 的 MediaCodec 类与我们的厂商扩展相结合,可以为富媒体应用解锁多种强大的功能。您可以使用它来基于底层硬件的支持,发现、配置和调整应用的功能。当在最新骁龙设备上运行时,可以将 ROI、LTR 和编码器统计数据以及多个内置 Android 编解码器功能合并到您的应用中。
了解更多信息,请查看我们的 Android on Snapdragon 开发者门户。
骁龙品牌产品是高通技术, Inc. 和/或其子公司的产品。