作为 Google 的 p2p 音视频方案,WebRTC 在很长时间里都会优先选择同样是 Google 自家的 VP8/VP9 作为编解码方案。但是不可否认,H.264 才是现在业界里更加主流的方案。所以在最近的几个版本中,WebRTC 也开始逐渐将 H.264 添加到默认的编解码方案中来了。

Android 上 WebRTC 只针对少量的设备提供了硬编解的支持,而软解则是完全不支持。幸运的是,WebRTC 使用 openH264 来实现软编码,FFmpeg 实现软解码,而这两部分代码都包含在了 src/third_party 中,我们只需要修改部分代码及编译的脚本就可以把这部分能力集成进来了。

针对 Android 平台,我们要完整的支持 H.264 的编解码,需要完成这些目标:

  1. 完善硬编解列表
  2. FFmpeg 开启 H.264 软解
  3. WebRTC 开启 H.264 软编解

本文基于 M70 版本

完善硬编解列表

不同于早期的版本,M70 移除了默认的编解码,必须在创建 PeerConnectionFactory 的时候显式的传入 VideoDecoderFactoryVideoEncoderFactory,通常来说,可以按照官方的 PSA 配置默认的工厂类。

配置硬编(解)码的代码在 sdk/android/api/org/webrtc/HardwareVideoEncoderFactory.javasdk/android/api/org/webrtc/HardwareVideoDecoderFactory.java 中。两个类对于编(解)码实例创建的逻辑是相似的,都需要先根据 MediaCodecInfoVideoCodecType 判断当前设备是否支持。仅以 HardwareVideoEncoderFactory 为例:

op1=>operation: HardwareVideoEncoderFactory::createEncoder
op2=>operation: HardwareVideoEncoderFactory::findCodecForType
op3=>operation: HardwareVideoEncoderFactory::isSupportedCodec
op4=>operation: HardwareVideoEncoderFactory::isHardwareSupportedInCurrentSdk
op5=>operation: HardwareVideoEncoderFactory::isHardwareSupportedInCurrentSdkH264
op1->op2->op3->op4->op5

默认只支持 OMX.qcom.OMX.Exynos.,可以根据业务需求把 OMX.hisi.OMX.MTK. 添加进来,当然也可以根据黑名单排除一些设备。

FFmpeg 开启 H.264 软解

为 FFmpeg 开启 H.264 的编译选项,需要修改 third_party/ffmpeg 下的脚本。

  1. third_party/ffmpeg/ffmpeg_generated.gni 将 h264 相关的源码添加到 ffmpeg_c_sources 中
  2. 修改 third_party/ffmpeg/chromium/config/Chromium/{ABI}/config.h#define CONFIG_H264_DECODER 的宏定义
  3. 由于 FFmpeg 废弃了 av_register_all,所以需要静态的注册 H.264。third_party/ffmpeg/chromium/config/Chromium/android/{ABI}/libavcodec/parser_list.cthird_party/ffmpeg/chromium/config/Chromium/android/{ABI}/libavcodec/codec_list.c 分别添加 h264 的 parser 和 decoder

WebRTC 开启 H.264 软编解

尽管我们已经将 H.264 的软解添加到 FFmpeg 中了,但是 WebRTC 还是没有调用到这些代码。这里我们可以参考源码中对于 VP9 的处理,依样画葫芦。

  1. 参照 sdk/android/src/java/org/webrtc/VP9Decoder.javasdk/android/src/java/org/webrtc/VP9Encoder.java 实现 H.264 的 Java 层 Wrapper
  2. 参照 sdk/android/jni/vp9codec.cc 实现 H.264 的 native 代码
  3. sdk/android/BUILD.gn 中分别添加 generate_jni rtc_static_library 任务,并添加对应的 java 和 cpp 文件
  4. sdk/android/api/org/webrtc/SoftwareVideoDecoderFacoty.javasdk/android/api/org/webrtc/SoftwareVideoEncoderFacoty.java 中分别注册 H.264 并添加创建 codec 的代码

注:WebRTC Android JNI 接口的 C 层函数定义,都是通过 Python 脚本 base/android/jni_generator/jni_generator.py 生成的,生成的代码在 out/{destination}/gen/sdk/android/generated_xxx_jni/jni 目录下。我们需要通过第3步生成 H.264 的 JNI 函数,并在第四步中引用生成的头文件。

另注:我们在将 H.264 的软编(解)码添加到工厂类里时,需要传入一个 Map 作为参数。sdk/android/src/java/org/webrtc/H264Utils.java 提供了这些生成参数的方法。这里的参数会影响协商时生成的 SDP,要根据业务实现。

收个尾

编译时,我们需要将 rtc_use_h264 设置为 true。可以在 webrtc.gni 中修改,也可以通过 gn gen 在生成 gn 项目的时候通过 --args 设置。