相信大家伙在看其他开启ffmpeg或者开启webrtcH264软解的相关文档当中,基本都会看到这句话:
打开third_party/ffmpeg/ffmpeg_generated.gni文件,把包含H264的开关打开
基本上所有文章说了这句话之后就没然后了,开关打开怎么开也没有说明,甚至没有例子,对初学者非常不友好。
在上一篇文章android webrtc学习二当中已经修改了硬编解码的白名单;而对于软编解码,android webrtc编码采用openh264,解码则使用ffmpeg,这两块的代码都在webrtc源码src/third_party当中;开启步骤如下:
1、使rtc_use_h264最终返回值为true
打开src/webrtc.gni文件,搜索rtc_use_h264,可以看到原本是这么写的
rtc_use_h264 = proprietary_codecs && !is_android && !is_ios && !(is_win && !is_clang)
想要让rtc_use_h264最终返回true,就将!is_android去掉或者直接将rtc_use_h264值改为true;当只去掉!is_android判断后,那么这时候返回的值就取决于proprietary_codecs,而这个值通过全局搜索可以发现在 src/build/config/features.gni 文件当中定义了
proprietary_codecs = is_chrome_branded || is_chromecast
该值默认返回false,那么我们可以直接改为true,但考虑到该文件藏得有点深,并且也不太想改动这两个平台的判断,那么最终对该值的改动则在编译过程中添加 args="proprietary_codecs=true"进行设置即可。
2、修改src/third_party/ffmpeg/ffmpeg_generated.gni文件
找到并打开src/third_party/ffmpeg/ffmpeg_generated.gni,把包含H264的开关打开,大多的文章坑就在这里,以下则是我不断尝试最终实现效果的改法,搜索H264。
- 修改1
if ((is_mac) || (is_win) || (use_linux_config)) {
ffmpeg_c_sources += [
“libavcodec/autorename_libavcodec_hpeldsp.c”,
“libavcodec/autorename_libavcodec_videodsp.c”,
“libavcodec/autorename_libavcodec_vp3dsp.c”,
“libavcodec/autorename_libavcodec_vp8dsp.c”,
“libavcodec/h264pred.c”,
“libavcodec/vp3.c”,
“libavcodec/vp3_parser.c”,
“libavcodec/vp56rac.c”,
“libavcodec/vp8.c”,
“libavcodec/vp8_parser.c”,
]
}
在判断条件当中添加|| (is_android)判断,如下:
if ((is_mac) || (is_win) || (use_linux_config) || (is_android)) {
ffmpeg_c_sources += [
“libavcodec/autorename_libavcodec_hpeldsp.c”,
“libavcodec/autorename_libavcodec_videodsp.c”,
“libavcodec/autorename_libavcodec_vp3dsp.c”,
“libavcodec/autorename_libavcodec_vp8dsp.c”,
“libavcodec/h264pred.c”,
“libavcodec/vp3.c”,
“libavcodec/vp3_parser.c”,
“libavcodec/vp56rac.c”,
“libavcodec/vp8.c”,
“libavcodec/vp8_parser.c”,
]
}
- 修改2
if ((is_mac && ffmpeg_branding == “Chrome”) || (is_win && ffmpeg_branding == “Chrome”) || (use_linux_config && ffmpeg_branding == “Chrome”) || (use_linux_config && ffmpeg_branding == “ChromeOS”)) {
ffmpeg_c_sources += [
“libavcodec/cabac.c”,
“libavcodec/h2645_parse.c”,
“libavcodec/h264_cabac.c”,
“libavcodec/h264_cavlc.c”,
“libavcodec/h264_direct.c”,
“libavcodec/h264_loopfilter.c”,
“libavcodec/h264_mb.c”,
“libavcodec/h264_parse.c”,
“libavcodec/h264_parser.c”,
“libavcodec/h264_picture.c”,
“libavcodec/h264_ps.c”,
“libavcodec/h264_refs.c”,
“libavcodec/h264_sei.c”,
“libavcodec/h264_slice.c”,
“libavcodec/h264chroma.c”,
“libavcodec/h264data.c”,
“libavcodec/h264dec.c”,
“libavcodec/h264dsp.c”,
“libavcodec/h264idct.c”,
“libavcodec/h264qpel.c”,
“libavcodec/startcode.c”,
]
}
同理,在if条件里添加|| (is_android)判断
- 修改3
if ((is_mac) || (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”)) {
ffmpeg_c_sources += [
“libavcodec/x86/autorename_libavcodec_x86_videodsp_init.c”,
“libavcodec/x86/h264_intrapred_init.c”,
“libavcodec/x86/hpeldsp_init.c”,
“libavcodec/x86/hpeldsp_vp3_init.c”,
“libavcodec/x86/vp3dsp_init.c”,
“libavcodec/x86/vp8dsp_init.c”,
]
ffmpeg_asm_sources += [
“libavcodec/x86/autorename_libavcodec_x86_videodsp.asm”,
“libavcodec/x86/fpel.asm”,
“libavcodec/x86/h264_intrapred.asm”,
“libavcodec/x86/h264_intrapred_10bit.asm”,
“libavcodec/x86/hpeldsp.asm”,
“libavcodec/x86/hpeldsp_vp3.asm”,
“libavcodec/x86/vp3dsp.asm”,
“libavcodec/x86/vp8dsp.asm”,
“libavcodec/x86/vp8dsp_loopfilter.asm”,
]
}
在if条件里添加:|| (is_android && current_cpu==“x64”)
- 修改4
if ((use_linux_config && current_cpu == “arm” && arm_use_neon) || (use_linux_config && current_cpu == “arm”)) {
ffmpeg_c_sources += [
“libavcodec/arm/h264pred_init_arm.c”,
“libavcodec/arm/hpeldsp_init_arm.c”,
“libavcodec/arm/hpeldsp_init_armv6.c”,
“libavcodec/arm/videodsp_init_arm.c”,
“libavcodec/arm/videodsp_init_armv5te.c”,
“libavcodec/arm/vp3dsp_init_arm.c”,
“libavcodec/arm/vp8dsp_init_arm.c”,
“libavcodec/arm/vp8dsp_init_armv6.c”,
]
ffmpeg_gas_sources += [
“libavcodec/arm/hpeldsp_arm.S”,
“libavcodec/arm/hpeldsp_armv6.S”,
“libavcodec/arm/videodsp_armv5te.S”,
“libavcodec/arm/vp8_armv6.S”,
“libavcodec/arm/vp8dsp_armv6.S”,
]
}
在if条件里添加:|| (is_android && current_cpu == “arm”)
- 修改5
if ((use_linux_config && current_cpu == “mips64el”) || (use_linux_config && current_cpu == “mipsel”)) {
ffmpeg_c_sources += [
“libavcodec/mips/autorename_libavcodec_mips_videodsp_init.c”,
“libavcodec/mips/h264pred_init_mips.c”,
“libavcodec/mips/hpeldsp_init_mips.c”,
“libavcodec/mips/vp3dsp_init_mips.c”,
“libavcodec/mips/vp8dsp_init_mips.c”,
]
}
在if条件里添加:|| (is_android && current_cpu == “mips64el”)
- 修改6
if ((is_android && current_cpu == “arm64”) || (is_win && current_cpu == “arm64”) || (use_linux_config && current_cpu == “arm64”)) {
ffmpeg_c_sources += [
“libavcodec/aarch64/fft_init_aarch64.c”,
“libavcodec/aarch64/mpegaudiodsp_init.c”,
“libavcodec/aarch64/vorbisdsp_init.c”,
“libavutil/aarch64/cpu.c”,
“libavutil/aarch64/float_dsp_init.c”,
]
ffmpeg_gas_sources += [
“libavcodec/aarch64/autorename_libavcodec_aarch64_fft_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_mdct_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_vorbisdsp_neon.S”,
“libavcodec/aarch64/mpegaudiodsp_neon.S”,
“libavutil/aarch64/autorename_libavutil_aarch64_float_dsp_neon.S”,
]
}
在if条件里添加:|| (is_android && current_cpu == “arm64”)
- 修改7
if ((is_win && current_cpu == “arm64”) || (use_linux_config && current_cpu == “arm64”)) {
ffmpeg_c_sources += [
“libavcodec/aarch64/h264pred_init.c”,
“libavcodec/aarch64/hpeldsp_init_aarch64.c”,
“libavcodec/aarch64/videodsp_init.c”,
“libavcodec/aarch64/vp8dsp_init_aarch64.c”,
]
ffmpeg_gas_sources += [
“libavcodec/aarch64/autorename_libavcodec_aarch64_h264pred_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_hpeldsp_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_vp8dsp_neon.S”,
“libavcodec/aarch64/videodsp.S”,
]
}
在if条件里添加:|| (is_android && current_cpu == “arm64”)
- 修改8
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”)) {
ffmpeg_c_sources += [
“libavcodec/arm/h264chroma_init_arm.c”,
“libavcodec/arm/h264dsp_init_arm.c”,
“libavcodec/arm/h264qpel_init_arm.c”,
]
ffmpeg_gas_sources += [
“libavcodec/arm/startcode_armv6.S”,
]
}
在if条件里添加:|| (is_android && current_cpu == “arm” && arm_use_neon)
- 修改9
if ((is_mac && 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”)) {
ffmpeg_c_sources += [
“libavcodec/x86/h264_qpel.c”,
“libavcodec/x86/h264chroma_init.c”,
“libavcodec/x86/h264dsp_init.c”,
]
ffmpeg_asm_sources += [
“libavcodec/x86/h264_chromamc.asm”,
“libavcodec/x86/h264_chromamc_10bit.asm”,
“libavcodec/x86/h264_deblock.asm”,
“libavcodec/x86/h264_deblock_10bit.asm”,
“libavcodec/x86/h264_idct.asm”,
“libavcodec/x86/h264_idct_10bit.asm”,
“libavcodec/x86/h264_qpel_10bit.asm”,
“libavcodec/x86/h264_qpel_8bit.asm”,
“libavcodec/x86/h264_weight.asm”,
“libavcodec/x86/h264_weight_10bit.asm”,
“libavcodec/x86/qpel.asm”,
]
}
在if条件里添加:|| (is_android && current_cpu == “x64”) || (is_android && current_cpu == “x86”)
- 修改10
if ((use_linux_config && current_cpu == “mips64el” && ffmpeg_branding == “Chrome”) || (use_linux_config && current_cpu == “mips64el” && ffmpeg_branding == “ChromeOS”) || (use_linux_config && current_cpu == “mipsel” && ffmpeg_branding == “Chrome”) || (use_linux_config && current_cpu == “mipsel” && ffmpeg_branding == “ChromeOS”)) {
ffmpeg_c_sources += [
“libavcodec/mips/h264chroma_init_mips.c”,
“libavcodec/mips/h264dsp_init_mips.c”,
“libavcodec/mips/h264qpel_init_mips.c”,
]
}
在if条件里添加:|| (is_android && current_cpu == “mips64el”) || (is_android && current_cpu == “mipsel”)
- 修改11
if ((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”)) {
ffmpeg_c_sources += [
“libavcodec/aarch64/h264chroma_init_aarch64.c”,
“libavcodec/aarch64/h264dsp_init_aarch64.c”,
“libavcodec/aarch64/h264qpel_init_aarch64.c”,
]
ffmpeg_gas_sources += [
“libavcodec/aarch64/autorename_libavcodec_aarch64_h264cmc_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_h264dsp_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_h264idct_neon.S”,
“libavcodec/aarch64/autorename_libavcodec_aarch64_h264qpel_neon.S”,
]
}
在if条件里添加: || (is_android && current_cpu == “arm64”)
-修改12
if (use_linux_config && current_cpu == “arm” && arm_use_neon) {
ffmpeg_c_sources += [
“libavcodec/arm/hpeldsp_init_neon.c”,
“libavcodec/arm/vp8dsp_init_neon.c”,
]
ffmpeg_gas_sources += [
“libavcodec/arm/h264pred_neon.S”,
“libavcodec/arm/hpeldsp_neon.S”,
“libavcodec/arm/vp3dsp_neon.S”,
“libavcodec/arm/vp8dsp_neon.S”,
]
}
在if条件里添加:|| (is_android && current_cpu == “arm” && arm_use_neon)
- 修改13
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”)) {
ffmpeg_gas_sources += [
“libavcodec/arm/h264cmc_neon.S”,
“libavcodec/arm/h264dsp_neon.S”,
“libavcodec/arm/h264idct_neon.S”,
“libavcodec/arm/h264qpel_neon.S”,
]
}
在if条件里添加:|| (is_android && current_cpu == “arm” && arm_use_neon)
3、添加静态编译
找到src/third_party/ffmpeg/chromium/config/Chromium/android/{ABI}/libavcodec/codec_list.c和
src/third_party/ffmpeg/chromium/config/Chromium/android/{ABI}/libavcodec/parser_list.c;分别添加&ff_h264_decoder,和&ff_h264_parser,,如下:
4、修改宏定义
打开文件src/third_party/ffmpeg/chromium/config/Chromium/android/{ABI}/config.h,搜索CONFIG_H264_DECODER,将该值改成1
5、添加licenses
打开src/tools_webrtc/libs/generate_licences,找到LIB_TO_LICENSES_DICT节点,添加
‘openh264’:[‘third_party/openh264/src/LICENSE’],
‘ffmpeg’:[‘third_party/ffmpeg/LICENSE.md’],
6、实现jni和java层
以上四大步骤操作完毕之后,已经将h264编解码器集成到webrtc当中了,接下来模仿vp8或者vp9实现jni和java层
进入src/sdk/android/jni文件夹,创建h264_codec.cc文件
#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();
}
}
}
进入src/sdk/android/api/org/webrtc文件夹,模仿LibvpxVp9Decoder.java和LibvpxVp9Encoder.java编写H264Decoder.java和H264Encoder.java类
7、添加H264编译脚本
打开src/sdk/android/BUILD.gn文件,搜索vp9,模仿vp9写出h264的编译脚本,如下
8、编译
- 编译jar和so包
gn gen out/release/arm64-v8a --args=‘target_os=“android” target_cpu=“arm64” proprietary_codecs=true use_openh264=true’
ninja -C out/release/arm64-v8a
- 编译aar包,将rtc_use_h264直接改为true
在src目录下执行
./tools_webrtc/android/build_aar.py --build-dir out --arch “armeabi-v7a”