Android上的WebRTC:如何在多个设备上启用硬件编码

对于Badoo中的视频通话,我们使用WebRTC标准和H.264编解码器。如果您相信文档,那么此编解码器应该可以在Android 5.0以后的任何Android设备上正常工作。但实际上,事实并非如此。在本文中,我将讨论在WebRTC中为H.264编解码器实现硬件编码的功能,以及如何使其在更多设备上运行。



为什么选择H.264?


通过WebRTC连接时,参与会话的所有设备都会传输各种通信参数,包括视频和音频编解码器。如果设备支持多个编解码器(例如VP8和H.264),则将首先列出平台的优先级编解码器。在WebRTC 对帐阶段使用此数据,此后仅保留所有设备支持的编解码器。可以在此文档中看到带有解密的此类数据的示例

在进行视频通话时,如果其中一个设备不支持H.264编解码器,则两个设备都可以切换到例如VP8编解码器,这不取决于设备上的硬件实现。但是我们的应用程序可用于各种小工具,包括前几代的智能手机。因此,对于视频通信,我们希望尽可能使用硬件编码:它减少了处理器的负担,并且不会消耗过多的电池,这对于过时的小工具至关重要。与相同的VP8不同,H.264硬件编码支持在大量设备上实现

Android上的H.264支持


如果您相信对多媒体格式的支持描述,则从所有Android设备上解码H.264 Baseline Profile应该适用,并且从Android 3.0开始进行编码。在Badoo中,我们支持从Android 5.0开始的设备,因此不会有任何问题。但这并不是那么简单:即使在带有第五版的小工具中,我们也发现了很多功能。

用什么可以连接?

如您所知,在Android上开发新设备时,任何制造商都需要通过兼容性测试套件。它在连接到该设备的PC上运行,并且必须将其结果发送给Google以确认该设备符合指定版本的Android操作系统的要求。只有在此之后,该小工具才能投放市场。

我们对这个测试套件中的多媒体测试,尤其是视频编码和解码测试感兴趣。我决定专注于测试EncodeDecodeTestMediaCodecTestDecoderTestEncoderTest,因为它们存在于4.3以后的所有版本的Android中。这些测试中的代码行数图如下所示:



在版本4.3之前,大多数测试根本不存在,而在版本5和版本7上却大幅增加。因此,可以说,在版本Android 4.3之前,Google并未检查设备是否符合其编码和解码视频的规范,而是版本5.0大大改进了此检查。

看来这表明从5.0版开始对所有内容进行编码应该是有序的。但是,考虑到我以前在Android上解码流视频的经验,我确定事实并非如此。在Google 网上论坛体检Webrtc中查看有关编码主题数量就足够了 WebRTC源文件位于公共领域,可帮助我们搜索陷阱。让我们更详细地考虑它们。



WebRTC中的H.264支持


让我们从HardwareVideoEncoderFactory开始

有一个方法的名称为isHardwareSupportedInCurrentSdkH264:

private boolean isHardwareSupportedInCurrentSdkH264(MediaCodecInfo info) {
  // First, H264 hardware might perform poorly on this model.
  if (H264_HW_EXCEPTION_MODELS.contains(Build.MODEL)) {
    return false;
  }
  String name = info.getName();
  // QCOM H264 encoder is supported in KITKAT or later.
  return (name.startsWith(QCOM_PREFIX) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
      // Exynos H264 encoder is supported in LOLLIPOP or later.
      || (name.startsWith(EXYNOS_PREFIX)
             && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
}

如我们所见,Android仅在Qualcomm和Exynos芯片组上实现了对硬件编码的支持。为什么标准WebRTC实现中不支持其他芯片组?这很可能是由于硬件编解码器制造商的特性所致。而且,由于并非总是能够找到特定的设备,因此通常只能在生产时识别这些功能。

设备上的所有编解码器描述都存储在media_codecs.xml文件中。例如,这里是Pixel XLHUAWEI P8 lite的文件。使用MediaCodecList对象的getCodecInfos()方法获取编解码器列表时,将解析此文件-并返回存储在其中的编解码器。 CTS测试涵盖了此操作以及制造商对该文件的正确填充。MediaCodecListTest,也从Android 4.3中的160行代码增加到Android 10中的740行。

在Badoo中,我们更改了isHardwareSupportedInCurrentSdkH264方法代码,拒绝“白色”编解码器列表,并将其替换为WebRTC 列出的程序编解码器前缀的“黑色”列表

static final String[] SOFTWARE_IMPLEMENTATION_PREFIXES = {"OMX.google.", "OMX.SEC."};

但是,您不能只获得并实现对所有编解码器的支持,而不必关注制造商的功能。describe-webrtc组中专门讨论Android上的硬件编码主题的名称中,我们可以了解到,在这种情况下,我们肯定会遇到错误。基本上,它们出现在编解码器配置阶段。

编解码器配置选项


初始化编解码器以进行编码如下:

MediaCodec mediaCodec = createByCodecName(codecName);
MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
format.setInteger(MediaFormat.KEY_BIT_RATE, targetBitrateBps);
format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateConstant);
format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
format.setInteger(MediaFormat.KEY_FRAME_RATE, targetFps);
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, keyFrameIntervalSec);
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);

在其中一些参数中容易出错,这会在配置编解码器时引发异常并中断应用程序。另外,在使用编解码器时,由于编解码器本身做错了,您可能需要根据各种因素调整其比特率。为此,在WebRTC中,BaseBitrateAdjuster类是负责的,它具有两个后代:


因此,对于每个编解码器,您必须选择自己的比特率调整机制。让我们更详细地考虑为硬件编解码器设置初始化参数的功能。

流分辨率


收到编解码器的MediaCodecInfo对象后,可以通过在CodecCapabilities类中获取其功能来更详细地检查编解码器通过它们,您可以了解编解码器是否支持所选的分辨率和帧速率。如果支持这些参数,则可以安全地设置它们。

但是,有时此规则不起作用。我们面临这样一个事实,即编解码器的前缀为“ OMX.MARVELL”。编码不正确,如果流的分辨率不同于4:3,则屏幕边缘会显示绿色条纹。同时,编解码器本身声称支持选定的分辨率和帧速率。

比特率模式


所有视频编解码器的标准模式是恒定比特率。但是,一旦我们不得不使用可变比特率:

format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateVariable);

这在带有展讯芯片组(现在为Unisoc)的联想A1000设备上发生,前缀为“ OMX.sprd”。在Internet上进行的搜索使我们在Firefox OS上发表长达6年的帖子,其中描述了此问题以及如何解决。

色彩格式


在字节缓冲区模式下使用编解码器时,必须选择正确的格式。通常使用以下形式的函数来完成此操作:

@Nullable
static Integer selectColorFormat(int[] supportedColorFormats, CodecCapabilities capabilities) {
  for (int supportedColorFormat : supportedColorFormats) {
    for (int codecColorFormat : capabilities.colorFormats) {
      if (codecColorFormat == supportedColorFormat) {
        return codecColorFormat;
      }
    }
  }
  return null;
}

粗略地说,总是会选择支持的第一种颜色格式。

但是,对于以前缀“ OMX.IMG.TOPAZ。”,“ OMX.hisi”开头的HUAWEI编解码器。和“ OMX.k3”。此方法不起作用,经过长时间的搜索,我们找到了解决方案:无论这些编解码器返回哪种格式,都需要使用COLOR_FormatYUV420SemiPlanar格式线程帮助我们在一个中文论坛中弄清楚了这一点

比特率调整


标准的WebRTC代码包含以下内容

private BitrateAdjuster createBitrateAdjuster(VideoCodecMimeType type, String codecName) {
  if (codecName.startsWith(EXYNOS_PREFIX)) {
    if (type == VideoCodecMimeType.VP8) {
        // Exynos VP8 encoders need dynamic bitrate adjustment.
        return new DynamicBitrateAdjuster();
      } else {
        // Exynos VP9 and H264 encoders need framerate-based bitrate adjustment.
        return new FramerateBitrateAdjuster();
    }
  }
  // Other codecs don't need bitrate adjustment.
  return new BaseBitrateAdjuster();
}

从该代码中可以看到,对于Exynos以外的所有芯片组,比特率调整均处于关闭状态。但这仅适用于Qualcomm,因为标准代码仅支持Exynos和Qualcomm。通过尝试此设置的各种值以及搜索Internet,我们发现前缀为``OMX.MTK''的编解码器。它也需要打开。对于以前缀“ OMX.IMG.TOPAZ。”,“ OMX.hisi”开头的HUAWEI编解码器,也必须执行此操作。或“ OMX.k3”。这是由于以下事实:假设在配置编解码器时所有帧的频率设置都相同,则这些编解码器不会使用帧的时间戳来调整比特率。

最后,我将给出我们收到的针对Android 5.0和5.1上的设备的编解码器列表。他们对我们很感兴趣,主要是因为在更新版本的Android上,这种情况正在改善,并且非标准编解码器也越来越小。

可以在下图中看到。对数刻度更好地显示了罕见的情况。


如我们所见,大多数设备都具有展讯,联发科,华为和MARVELL芯片组-因此,我们的更改有助于在这些小工具上启用硬件编码。

结果


尽管我们认为某些设备在使用H.264时会遇到问题,但Android再次使我们感到惊讶。从Badoo用户统计数据可以看出,2014-2016年用户手中仍有相当多的设备,他们不希望或无法更新。尽管发布新设备的Android更新的情况已经比几年前好很多,但上一代小工具的比例却在缓慢下降,并且必须保持相当长的一段时间。

现在,由于Google在Stadia项目中使用了WebRTC,因此正在积极开发WebRTC(以下是视频(有关此主题的详细信息),它将变得越来越好,并且很有可能将成为实现视频通信的标准。我希望本文能帮助您了解在WebRTC中使用H.264的功能,并在您的项目中使用它。

All Articles