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