使用 MediaCodec 和厂商扩展构建富媒体 Android 应用
发表于 2023-07-25 11:56:45

骁龙和高通品牌的产品是高通技术, Inc. 和/或其子公司的产品

如果您正在开发Android富媒体应用,就需要熟悉 Android API 中的MediaCodec 类。通过MediaCodec 可以访问低级媒体编码器/解码器 (CODEC) 组件,处理音频、视频和压缩数据,从而可以整合低延迟解码等功能来增强应用程序的功能。因此,如果在骁龙® 平台支持的设备上运行时,您可以借助我们的 MediaCodec 厂商扩展解锁更多功能。

下面我们仔细看看 MediaCodec 的工作原理及其使用方法。

MediaCodec 的工作原理

开发人员使用 MediaCodec 的方法如下:

  • 应用(客户端)配置 MediaCodec
  • MediaCodec 为您的应用提供空的输入缓冲区
  • 应用使用数据填充缓冲区并将其发送给编解码器进行处理
  • 编解码器转换接收到的缓冲区数据
  • 转换后的数据通过输出缓冲区提供给您的应用
  • 在应用生命周期结束时,应用将停止并释放 MediaCodec

工作流程如下图所示:

 骁龙平台的功能

除了 Android API 提供的内置编解码器和功能之外,我们的 MediaCodec 扩展(可在 android-on-snapdragon 存储库中找到)还包括编解码器和其他功能,可解锁骁龙设备多种硬件加速功能:

感兴趣区域 (ROI) – 动态提高视频某些区域的图像质量。

长期参考帧 (LTR) – 对参考帧进行编码,用于未来帧的运动补偿预测。

编码器统计数据 – 提供描述场景复杂性的每帧统计数据。应用可以使用此信息动态控制编码参数(例如比特率)并调整预编码过滤,以实现更好的压缩效果,而不会造成高压缩伪影。

下图显示了Android 整体开发栈以及扩展的集成方式:

 MediaCodec 扩展位于开发栈底部附近,靠近硬件

支持库(例如 Media3CameraX)也可以使用扩展,在此情况下,这些扩展的某些功能可能已经启用。下图显示了支持库在开发栈中的位置:

支持库位于应用和Android SDK之间,可以访问厂商扩展提供的功能

设置 MediaCodec 厂商扩展的四个步骤

在运行时设置 MediaCodec 厂商扩展涉及以下步骤:

  1. 枚举设备支持的扩展
  2. 查询支持的扩展可以使用的值(例如值的范围)
  3. 将配置应用于扩展

下面我们详细地讨论每一个步骤。

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. 和/或其子公司的产品。

 

CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
微博关注
【免责声明:CSDN本栏目发布信息,目的在于传播更多信息,丰富网络文化,稿件仅代表作者个人观点,与CSDN无关。其原创性以及文中陈述文字和文字内容未经本网证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本网不做任何保证或者承诺,请读者仅作参考,并请自行核实相关内容。您若对该稿件有任何怀疑或质疑,请立即与CSDN联系,我们将迅速给您回应并做处理。】