Android平台WebRTC开启H264软编解码

由于版权问题WebRTC一直不支持H264,直到Cisco宣布旗下的H264 Codec开源为OpenH264,并且替所有OpenH264的使用者支付了H264的专利费,以此为契机,在IETF的WebRTC会议中,把H264和VP8都列入了WebRTC所必须要支持的视频编码器,接下来Google终于在WebRTC中增加了对H264的支持,对于Android平台, 编码器是用OpenH264, 解码器是用FFMPEG, 也可以用 MediaCodec. 这个对于广大需要H264的公司来说是一大福音. 在下载的WebRTC代码中做稍许配置, 就可以使用H264了,本文介绍针对M86分支增加H264软编的步骤。

开启H264编解码

打开开关

  • 修改third_party/ffmpeg/ffmpeg_generated.gni
    use_linux_config = is_linux || is_fuchsia
-> use_linux_config = is_linux || is_fuchsia || is_android
  • 修改third_party/ffmpeg/chromium/config/Chrome/android/arm64/config.h:
    #define CONFIG_H264_DECODER 0
-> #define CONFIG_H264_DECODER 1
  • 修改third_party/ffmpeg/chromium/config/Chrome/android/arm64/libavcodec/parser_list.c
    static const AVCodecParser * const parser_list[] = {
...
&ff_vp9_parser,
+ &ff_h264_parser,
NULL };
  • 修改third_party/ffmpeg/chromium/config/Chrome/android/arm64/libavcodec/codec_list.c
    static const AVCodec * const codec_list[] = {
...
&ff_libopus_decoder,
+ &ff_h264_decoder,
NULL };

增加H264编解码支持

  • sdk/android/api/org/webrtc中增加LibH264Decoder.javaLibH264Encoder.java,格式与原有Decoder、Encoder一致:
LibH264Decoder.java
package org.webrtc;

public class LibH264Decoder extends WrappedNativeVideoDecoder {
@Override
public long createNativeVideoDecoder() {
return nativeCreateDecoder();
}
static native long nativeCreateDecoder();
}
LibH264Encoder.java
package org.webrtc;

public class LibH264Encoder extends WrappedNativeVideoEncoder {
@Override
public long createNativeVideoEncoder() {
return nativeCreateEncoder();
}

static native long nativeCreateEncoder();

@Override
public boolean isHardwareEncoder() {
return false;
}
}
  • sdk/android/src/jni中添加h264_codec.cc,格式与原有vp8_codec.cc/vp9_codec.cc一致:
#include <jni.h>
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "sdk/android/generated_libH264_jni/LibH264Decoder_jni.h"
#include "sdk/android/generated_libH264_jni/LibH264Encoder_jni.h"
#include "sdk/android/src/jni/jni_helpers.h"

namespace webrtc {
namespace jni {

static jlong JNI_LibH264Encoder_CreateEncoder(JNIEnv* jni) {
return jlongFromPointer(H264Encoder::Create().release());
}

static jlong JNI_LibH264Decoder_CreateDecoder(JNIEnv* jni) {
return jlongFromPointer(H264Decoder::Create().release());
}

} // namespace jni
} // namespace webrtc
  • modules/video_coding/codecs/h264/h264.cc中增加上H264Encoder的构造函数:
std::unique_ptr<H264Encoder> H264Encoder::Create() {
#if defined(WEBRTC_USE_H264)
RTC_LOG(LS_INFO) << "Creating H264EncoderImpl.";
return std::make_unique<H264EncoderImpl>(cricket::VideoCodec("H264"));
#else
RTC_NOTREACHED();
return nullptr;
#endif
}
  • modules/video_coding/codecs/h264/include/h264.h头文件中声明函数:
class RTC_EXPORT H264Encoder : public VideoEncoder {
public:
+ static std::unique_ptr<H264Encoder> Create();
static std::unique_ptr<H264Encoder> Create(const cricket::VideoCodec& codec);
// If H.264 is supported (any implementation).
static bool IsSupported();

~H264Encoder() override {}
};
  • sdk/android/api/org/webrtc/中修改SoftwareVideoDecoderFactory.javaSoftwareVideoEncoderFactory.java增加对H264的支持:
SoftwareVideoDecoderFactory.java
  public VideoDecoder createDecoder(VideoCodecInfo codecType) {
+ if (codecType.getName().equalsIgnoreCase("H264")) {
+ return new LibH264Decoder();
+ }
...
return null;
}

static VideoCodecInfo[] supportedCodecs() {
List<VideoCodecInfo> codecs = new ArrayList<VideoCodecInfo>();

+ codecs.add(new VideoCodecInfo("H264", new HashMap<>()));
codecs.add(new VideoCodecInfo("VP8", new HashMap<>()));
...
return codecs.toArray(new VideoCodecInfo[codecs.size()]);
}
SoftwareVideoEncoderFactory.java
  public VideoEncoder createEncoder(VideoCodecInfo info) {
+ if(info.name.equalsIgnoreCase("H264")) {
+ return new LibH264Encoder();
}
...
return null;
}

static VideoCodecInfo[] supportedCodecs() {
List<VideoCodecInfo> codecs = new ArrayList<VideoCodecInfo>();

+ codecs.add(new VideoCodecInfo("H264", new HashMap<>()));
codecs.add(new VideoCodecInfo("VP8", new HashMap<>()));
...
return codecs.toArray(new VideoCodecInfo[codecs.size()]);
}

增加编译支持

sdk/android/BUILD.gn中关联上述新加逻辑:

BUILD.gn
+ rtc_android_library("libH264_java") {
+ visibility = [ "*" ]
+ sources = [
+ "api/org/webrtc/LibH264Decoder.java",
+ "api/org/webrtc/LibH264Encoder.java",
+ ]
+ deps = [
+ ":base_java",
+ ":video_api_java",
+ ":video_java",
+ "//rtc_base:base_java",
+ ]
+ }

rtc_android_library("libvpx_vp9_java") {
visibility = [ "*" ]
sources = [
"api/org/webrtc/LibvpxVp9Decoder.java",
"api/org/webrtc/LibvpxVp9Encoder.java",
]
deps = [
":base_java",
":video_api_java",
":video_java",
"//rtc_base:base_java",
]
}

...

+ rtc_library("libH264_jni") {
+ visibility = [ "*" ]
+ allow_poison = [ "software_video_codecs" ]
+ sources = [ "src/jni/h264_codec.cc" ]
+ deps = [
+ ":base_jni",
+ ":generated_libH264_jni",
+ ":video_jni",
+ "../../modules/video_coding:webrtc_h264",
+ ]
+ }

rtc_library("libvpx_vp9_jni") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
sources = [ "src/jni/vp9_codec.cc" ]
deps = [
":base_jni",
":generated_libvpx_vp9_jni",
":video_jni",
"../../modules/video_coding:webrtc_vp9",
]
}

rtc_library("swcodecs_jni") {
visibility = [ "*" ]
allow_poison = [ "software_video_codecs" ]
deps = [
+ ":libH264_jni",
":libvpx_vp8_jni",
":libvpx_vp9_jni",
]
}

...

+ generate_jni("generated_libH264_jni") {
+ sources = [
+ "api/org/webrtc/LibH264Decoder.java",
+ "api/org/webrtc/LibH264Encoder.java",
+ ]

+ namespace = "webrtc::jni"
+ jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h"
+ }

generate_jni("generated_libvpx_vp9_jni") {
sources = [
"api/org/webrtc/LibvpxVp9Decoder.java",
"api/org/webrtc/LibvpxVp9Encoder.java",
]

namespace = "webrtc::jni"
jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h"
}

编译命令

./tools_webrtc/android/build_aar.py --build-dir Build --arch arm64-v8a --extra-gn-args 'rtc_use_h264=true ffmpeg_branding="Chrome"'

end

WebRTC的音视频数据传输使用的是RTP协议,RTP报文分为报头和载荷两部分,不同类型的载荷有不同的格式,所以就需要单独实现把编码数据打包为RTP报文的逻辑以及从RTP报文解析已编码数据的逻辑。庆幸的是WebRTC以及帮我们处理好了H264的封包解包逻辑,我们只需要添加支持,并把逻辑打包进aar即可,而若要支持H265,则需要自己处理封包解包逻辑,好消息是OWT中包含了H265的支持,我们不用从0️⃣开始。

参考:

作者

8MilesRD

发布于

2022-09-28

更新于

2022-09-30

许可协议

评论