63

Android上的WebRTC——多设备如何启用硬件编码?(二) | WebRTC中文网-最权威的RTC实时...

 4 years ago
source link: https://webrtc.org.cn/20200624-android2/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Android上的WebRTC——多设备如何启用硬件编码?(二)

可以看到,Android仅对Qualcomm和Exynos芯片组启用了硬件编码支持。那么为什么标准的WebRTC实现不支持其他芯片组呢?最有可能是因为不同制造商的硬件编解码器实现方式不尽相同,因为并非总能找到具体设备,所以这种不同通常到了生产阶段才能发现。

所有编解码器描述都存储在media_codecs.xml文件中,例如Pixel XLHUAWEI P8 lite。当我们使用MediaCodecList对象中的getCodecInfos()方法接收编解码器列表时,该文件经过解析后,会返回已存储的编解码器。MediaCodecListTest在CTS中介绍了此过程以及制造商填写此文件的准确性,其SLOC计数已从Android 4.3中的160增加到Android 10中的740。

在Badoo中,我们更改了isHardwareSupportedInCurrentSdkH264方法代码,并将编解码器的允许列表替换为WebRTC中列出的软件编解码器前缀的黑名单

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

但我们确实需要考虑制造特性,才有可能实现对所有编解码器的支持。从专用于Android上硬件编码的describe-webrtc主题名称中,我们可以明显看出此过程中肯定会出错,大多数情况下都是编解码器配置阶段出问题。

编解码器配置参数

用于编码的编解码器初始化是这样的:

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);
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类中获取该功能的信息,来更详细地了解编解码器。通过这种方式,我们可以确定该编解码器是否支持选定的分辨率和帧速率。如果它确实支持这些参数,我们就可以安全地进行设置。

但在某些情况下,此规则并不适用。我们发现,当流分辨率不是4:3时,带有“ OMX.MARVELL”前缀的编解码器在某些情况下会出现编码错误,导致屏幕边缘出现绿条,而该编解码器本身声称支持选定的分辨率和帧速率。

比特率模式

所有视频编解码器的标准模式是恒定比特率。但是有时我们必须使用可变比特率:

format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateVariable);
format.setInteger(MediaFormat.KEY_BITRATE_MODE, VIDEO_ControlRateVariable);

需要使用可变比特率的情况是搭载展讯(现在称为Unisoc)芯片组的联想A1000设备上,该芯片组以“ OMX.sprd”开头。通过网络搜索,我们找到了一份六年前发布的研究Firefox OS的文章,该作者在文章中阐述了问题和解决方案。

色彩模式

在字节缓冲模式下使用编解码器时,我们需要选择适当的格式。通常是在以下功能的帮助下执行的:

@Nullable
static Integer selectColorFormat(int[] supportedColorFormats, CodecCapabilities capabilities) {
for (int supportedColorFormat : supportedColorFormats) {
for (int codecColorFormat : capabilities.colorFormats) {
if (codecColorFormat == supportedColorFormat) {
return codecColorFormat;
return null;
@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”或“OMX.k3.”开头的HUAWEI编解码器。经过一段时间的搜索,某中文论坛上的一篇帖子帮我们解决了这个问题——无论这些编解码器返回的格式如何,使用COLOR_FormatYUV420SemiPlanar格式就可以了。

文章地址:https://badootech.badoo.com/webrtc-on-android-how-to-enable-hardware-encoding-on-multiple-devices-5bd819c0ce5

原文作者:Ivan Dyatlov


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK