Android technology sharing | Android WebRTC opens H264 software codec tutorial

The encoding and decoding 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.

Based on

webRTC version:( https://chromium.googlesource.com/external/webrtc/+/branch-heads/4515)

Device: Mac

Virtual machine: Parallels Desktop + Ubuntu 18.4

start

1: Modify rtc_use_h264 return value

Path: webrtc/src/webrtc.gni. Open the file and modify the rtc_use_h264 attribute to rtc_use_h264 = true

  # rtc_use_h264 =
  # proprietary_codecs && !is_android && !is_ios && !(is_win && !is_clang)
  
  rtc_use_h264 = true

2: Modify ffmpeg related compilation parameters

Path: webrtc/src/third_party/ffmpeg/ffmpeg_generated.gni

Here, you need to turn on many compilation switches related to H264. Be sure to see clearly, otherwise this error will be reported during compilation ❌

The following is what I sorted out with reference to various information blogs on the Internet. I only compiled armv7 and arm64

: Line

198#

if ((is_mac) || (is_win) || (use_linux_config))

modify

if ((is_mac) || (is_win) || (use_linux_config) || (is_android))

252#

if ((is_mac && ffmpeg_branding == "Chrome") || (is_win && ffmpeg_branding == "Chrome") || (use_linux_config && ffmpeg_branding == "Chrome") || (use_linux_config && ffmpeg_branding == "ChromeOS"))

modify

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))

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"))

modify

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"))

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"))

397#

if ((is_mac && current_cpu == "arm64") || (is_win && current_cpu == "arm64") || (use_linux_config && current_cpu == "arm64"))

modify

if ((is_mac && current_cpu == "arm64") || (is_win && current_cpu == "arm64") || (use_linux_config && current_cpu == "arm64") || (is_android && current_cpu == "arm64"))

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"))

487#

if ((use_linux_config && current_cpu == "arm" && arm_use_neon) || (use_linux_config && current_cpu == "arm"))

modify

if ((use_linux_config && current_cpu == "arm" && arm_use_neon) || (use_linux_config && current_cpu == "arm") || (is_android && current_cpu == "arm"))

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 == "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") || (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))

545#

if (use_linux_config && current_cpu == "arm" && arm_use_neon)modify if (use_linux_config && current_cpu == "arm" && arm_use_neon || (is_android && current_cpu == "arm" && arm_use_neon))

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))

3: Add static compilation

Path 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 };

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 };

4: Modify macro definition

Path: webrtc/src/third_party/ffmpeg/chromium/config/Chromium/android//config.h

Search config_h264_coder and change its value from 0 to 1

#define CONFIG_H264_DECODER 1

5: Add Licenses

Path: webrtc/src/tools_webrtc/libs/generate_licenses.py

Find LIB_TO_LICENSES_DICT and add it in 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 to    'ffmpeg':['third_party/ffmpeg/LICENSE.md']#Add}

6: 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 webrtc

7: Create H264Encode.java and H264Decoder.java

Path: webrtc/src/sdk/android/src/java/org/webrtc/

If you want to compile into aar, add two java files in the above directory. If you want to modify the webrtc code for NDK development, the above files can be placed in your own sdk and ensure that 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();}

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();}

8: Modify java layer software codec class

Locate SoftwareVideoEncoderFactory.java

public VideoEncoder createEncoder(VideoCodecInfo codecInfo) {    String codecName = codecInfo.getName();    if (codecName.equalsIgnoreCase("H264")) {//Add return new H264Encoder(); / / add} / / add

Locate SoftwareVideoDecoderFactory.java

public VideoDecoder createDecoder(VideoCodecInfo codecInfo) {    String codecName = codecInfo.getName();    if (codecName.equalsIgnoreCase(VideoCodecMimeType.H264.toSdpCodecName())){//Add return new H264Decoder(); / / add} / / add

9: Add H264 compilation script

Imitate other codecs

Path: webrtc/src/sdk/android/BUILD.gn

51#

Add: ": h264#u 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",    ]  }

545#

Add: ": h264#u 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",    ]  }

895#

Add: ": h264#u 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"  }

10: Compile

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

ffmpeg conflict

In this way, the compiled static library contains ffmpeg, but it is an incomplete version of ffmpeg with few functions. If your project also needs to use ffmpeg, it is difficult to share those in webrtc. If you integrate yourself, you will report repeated definition conflicts.

There are few solutions on the Internet. Later, after a few days of search, I accidentally found that the compilation command has an option: if is_component_ffmpeg is set to false, I use the dynamic library. In this way, I can integrate ffmpeg and let webRTC use your integration, so there will be no conflict

Tags: Android ffmpeg webrtc h264

Posted on Wed, 03 Nov 2021 02:59:16 -0400 by classifieds100