More detailed! Android WebRTC Enable H264 soft codec

The codec of Android WebRTC software is based on openH264 and FFMpeg, but it is not enabled by default during compilation. If you want to enable it, you need to add and modify the code. I will list all the modification steps one by one below.

This article is based on

WebRTC version:

Equipment: Mac

Virtual machine: Parallels Desktop + Ubuntu 18.4

start

Change the return value of rTC_USe_h264

Path: webrtc/ SRC /webrtc.gni. Open the file and change rtc_use_h264 to rtc_USe_h264 = true

# rtc_use_h264 = # proprietary_codecs && ! is_android && ! is_ios && ! (is_win && ! is_clang) rtc_use_h264 = trueCopy the code

Two: modify ffMPEG related compilation parameters

Path: webrtc/SRC/third_party/ffmpeg/ffmpeg_generated gni

Here you need to turn on a number of H264 related compiler switches, make sure to watch, otherwise the compiler will report this error ❌

Armv7 + arm64 + armv7 + arm64 + armv7 + arm64 + armv7 + arm64

Line # :

198 #

if((is_mac) | | (is_win) | | (use_linux_config))if ((is_mac) || (is_win) || (use_linux_config) || (is_android))
Copy the code

252 #

if ((is_mac && ffmpeg_branding == "Chrome") || (is_win && ffmpeg_branding == "Chrome") || (use_linux_config && Ffmpeg_branding = = "Chrome") | | (use_linux_config && ffmpeg_branding = = "jump")) to modify the if ((is_mac && ffmpeg_branding == "Chrome") || (is_win && ffmpeg_branding == "Chrome") || (use_linux_config && ffmpeg_branding == "Chrome") || (use_linux_config && ffmpeg_branding == "ChromeOS") || (is_android))Copy the code

295 #

if ((is_mac && current_cpu == "x64") || (is_win && current_cpu == "x64") || (is_win && current_cpu == "x86") || (use_linux_config && current_cpu = = "x64") | | (use_linux_config && current_cpu = = "x86")) to modify the if ((is_mac && current_cpu == "x64") || (is_win && current_cpu == "x64") || (is_win && current_cpu == "x86") || (use_linux_config && current_cpu ==  "x64") || (use_linux_config && current_cpu == "x86") || (is_android && current_cpu=="x86") || (is_android && current_cpu=="x64"))Copy the code

376 #

if ((is_mac && current_cpu == "x64" && ffmpeg_branding == "Chrome") || (is_win && current_cpu == "x64" && ffmpeg_branding == "Chrome") || (is_win && current_cpu == "x86" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "x64" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "x64" && ffmpeg_branding == "ChromeOS") || (use_linux_config && current_cpu == "x86" && ffmpeg_branding == "Chrome") || (use_linux_config && Current_cpu == "x86" && ffmpeG_branding == "ChromeOS")) modify if ((is_mac && current_CPU == "x64" && ffmpeg_branding == "Chrome") || (is_win && current_cpu == "x64" && ffmpeg_branding == "Chrome") || (is_win && current_cpu == "x86" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "x64" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "x64" && ffmpeg_branding == "ChromeOS") || (use_linux_config && current_cpu == "x86"  && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "x86" && ffmpeg_branding == "ChromeOS") || (is_android && current_cpu == "x64"))Copy the code

397 #

if ((is_mac && current_cpu == "arm64") || (is_win && current_cpu == "arm64") || (use_linux_config && current_cpu == "Arm64")) to modify the if ((is_mac && current_cpu = = "arm64") | | (is_win && current_cpu = = "arm64") | | (use_linux_config && current_cpu == "arm64") || (is_android && current_cpu == "arm64"))Copy the code

423 #

if ((is_mac && current_cpu == "arm64" && ffmpeg_branding == "Chrome") || (is_win && current_cpu == "arm64" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm64" && ffmpeg_branding == "Chrome") || (use_linux_config &&current_CPU == "arm64" &&ffmpeg_branding == "ChromeOS") Modify if ((is_mac &&current_CPU == "arm64") && ffmpeg_branding == "Chrome") || (is_win && current_cpu == "arm64" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm64" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm64" && ffmpeg_branding == "ChromeOS") || (is_android && current_cpu == "arm64"))Copy the code

487 #

If ((use_linux_config && current_cpu = = "arm" && arm_use_neon) | | (use_linux_config && current_cpu = = "arm")) to modify the if ((use_linux_config && current_cpu == "arm" && arm_use_neon) || (use_linux_config && current_cpu == "arm") || (is_android  && current_cpu == "arm"))Copy the code

527 #

if ((use_linux_config && current_cpu == "arm" && arm_use_neon && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm" && arm_use_neon && ffmpeg_branding == "ChromeOS") || (use_linux_config && current_cpu == "arm" && Ffmpeg_branding = = "Chrome") | | (use_linux_config && current_cpu = = "arm" && ffmpeg_branding = = "jump")) to modify the if ((use_linux_config && current_cpu == "arm" && arm_use_neon && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm" && arm_use_neon && ffmpeg_branding == "ChromeOS") || (use_linux_config && current_cpu == "arm" && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm" && ffmpeg_branding == "ChromeOS")|| (is_android && current_cpu == "arm" && arm_use_neon))Copy the code

545 #

If (use_linux_config && current_CPU == "arm" && arm_use_neon) Changes if (use_linux_config && current_CPU == "arm" && arm_use_neon || (is_android && current_cpu == "arm" && arm_use_neon))Copy the code

564 #

if ((use_linux_config && current_cpu == "arm" && arm_use_neon && ffmpeg_branding == "Chrome") || (use_linux_config && Current_cpu == "arm" &&arm_use_neon &&ffmpeg_branding == "ChromeOS") modify if ((use_linux_config && current_CPU == "arm")  && arm_use_neon && ffmpeg_branding == "Chrome") || (use_linux_config && current_cpu == "arm" && arm_use_neon && ffmpeg_branding == "ChromeOS")||(is_android && current_cpu =="arm" && arm_use_neon))Copy the code

Three: add static compilation

Route 1: webrtc_source webrtc/SRC/third_party/ffmpeg/chromium/config/chromium/android / / libavcodec codec_list. C

Add & ff_h264_decoder

static const AVCodec * const codec_list[] = {
    &ff_flac_decoder,
    &ff_mp3_decoder,
    &ff_vorbis_decoder,
    &ff_pcm_alaw_decoder,
    &ff_pcm_f32le_decoder,
    &ff_pcm_mulaw_decoder,
    &ff_pcm_s16be_decoder,
    &ff_pcm_s16le_decoder,
    &ff_pcm_s24be_decoder,
    &ff_pcm_s24le_decoder,
    &ff_pcm_s32le_decoder,
    &ff_pcm_u8_decoder,
    &ff_libopus_decoder,
    &ff_h264_decoder,
    NULL };
Copy the code

Path 2: webrtc_source webrtc/SRC/third_party/ffmpeg/chromium/config/chromium/android / / libavcodec parser_list. C

Add & ff_h264_parser

static const AVCodecParser * const parser_list[] = {
    &ff_flac_parser,
    &ff_mpegaudio_parser,
    &ff_opus_parser,
    &ff_vorbis_parser,
    &ff_vp9_parser,
    &ff_h264_parser,
    NULL };
Copy the code

Four: modify macro definition

Path: webrtc/SRC/third_party/ffmpeg/chromium/config/chromium/android / / config. H

Search CONFIG_H264_DECODER to change its value from 0 to 1

#define CONFIG_H264_DECODER 1
Copy the code

5: Add Licenses

Path: webrtc/SRC/tools_webrtc/libs/generate_licenses py

Find LIB_TO_LICENSES_DICT to add to the node

LIB_TO_LICENSES_DICT = { 'abseil-cpp': ['third_party/abseil-cpp/LICENSE'], ... 'spl_sqrt_floor': ['common_audio/third_party/spl_sqrt_floor/LICENSE'], 'openh264: [' third_party/openh264 / SRC/LICENSE'], add 'ffmpeg' # : [' third_party/ffmpeg/LICENSE. Md] # add}Copy the code

Create h264_codec.cc

Path: webrtc/SRC/SDK/android/SRC/jni

Create a new file h264_codec.cc in the above path

#include <jni.h> #include "modules/video_coding/codecs/h264/include/h264.h" #include "sdk/android/generated_h264_jni/H264Decoder_jni.h" #include "sdk/android/generated_h264_jni/H264Encoder_jni.h" #include "sdk/android/src/jni/jni_helpers.h" namespace webrtc { namespace jni { static jlong JNI_H264Encoder_CreateEncoder(JNIEnv* jni) { return jlongFromPointer(H264Encoder::Create(cricket::VideoCodec(cricket::kH264CodecName)).release()); } static jboolean JNI_H264Encoder_IsSupported(JNIEnv* jni) { return ! SupportedH264Codecs().empty(); } static jlong JNI_H264Decoder_CreateDecoder(JNIEnv* jni) { return jlongFromPointer(H264Decoder::Create().release()); } static jboolean JNI_H264Decoder_IsSupported(JNIEnv* jni) { return ! SupportedH264Codecs().empty(); } } // namespace jni } // namespace webrtcCopy the code

Create h264encode. Java and h264decoder. Java

Path: webrtc/SRC/SDK/android/SRC/Java/org/webrtc /

If you are compiling to AAR, add two Java files to the above directory. If you want to modify your own WEbrTC code for NDK development, the above files can be put in your own SDK, make sure the directory is org/webrtc/.

H264Decoder.java

package org.webrtc;

public class H264Decoder extends WrappedNativeVideoDecoder {
  @Override
  public long createNativeVideoDecoder() {
    return nativeCreateDecoder();
  }


  static native boolean nativeIsSupported();
  static native long nativeCreateDecoder();
}
Copy the code

H264Encoder.java

package org.webrtc;

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

  static native long nativeCreateEncoder();


  @Override
  public boolean isHardwareEncoder() {
    return false;
  }

  static native boolean nativeIsSupported();
}
Copy the code

Eight: modify the Java layer software codec class

Find SoftwareVideoEncoderFactory. Java

public VideoEncoder createEncoder(VideoCodecInfo codecInfo) { String codecName = codecInfo.getName(); If (codecName. EqualsIgnoreCase (" H264 ")) {/ / new return new H264Encoder (); // add}// addCopy the code

Find SoftwareVideoDecoderFactory. Java

public VideoDecoder createDecoder(VideoCodecInfo codecInfo) { String codecName = codecInfo.getName(); If (codecName. EqualsIgnoreCase (VideoCodecMimeType. H264. ToSdpCodecName ())) {/ / new return new H264Decoder (); // add}// addCopy the code

Nine: add H264 compilation script

Write by imitating other codecs

Path: webrtc/SRC/SDK/android/BUILD designed.the gn

51 #

Add: “: h264_java”,

505 #

increase

rtc_android_library("h264_java") { visibility = [ "*" ] sources = [ "api/org/webrtc/H264Decoder.java", "api/org/webrtc/H264Encoder.java", ] deps = [ ":base_java", ":video_api_java", ":video_java", "//rtc_base:base_java", ]}Copy the code

545 #

Add: “: h264_java”,

860 #

Add:

rtc_library("h264_jni") {
    visibility = [ "*" ]
    allow_poison = [ "software_video_codecs" ]
    sources = [ "src/jni/h264_codec.cc" ]
    deps = [
      ":base_jni",
      ":generated_h264_jni",
      ":video_jni",
      "../../modules/video_coding:webrtc_h264",
    ]
  }
Copy the code

895 #

Add: “: h264_jni”,

1329 #

Add:

generate_jni("generated_h264_jni") {
    sources = [
      "api/org/webrtc/H264Decoder.java",
      "api/org/webrtc/H264Encoder.java",
    ]

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

Ten: compile

gn gen out/m93 --args='is_debug=false target_os="android" target_cpu="arm64" rtc_use_h264=true use_custom_libcxx=false'
Copy the code
ninja -C out/release/arm64-v8a
Copy the code

Ffmpeg conflict

The resulting static library contains FFMPEG, but is a crippled version of FFMPEG with very little functionality. It’s hard to share WEBRTC if you need FFMPEG in your own projects. Integrating your own will result in duplicate definition conflicts.

Is_component_ffmpeg is set to false to use a dynamic library, so that you can integrate FFMpeg yourself, and webRTC use your integrated one, so there is no conflict