Android摄像头采集到的数据格式是NV21(YUV的一种),称为原始数据,这种格式的数据量比较大,不利于传输,需要对数据进行压缩,这里需要通过H264编码达到压缩目的。x264是把原始数据转化为H264的工具,x264是工具,h264是协议。
FAAC和X264功能类似,X264是做视频编码的,FAAC是做音频编码的。
H264的流需要一个载体把流中一段段传输到服务器,这个载体就是RTMPDump。RTMPDump是个工具,实现了rtmp协议,通过RTMPDump把数据流中的每一帧转换成一个packet传输到服务器。
集成RTMPDump:
RTMPDump下载地址
- 下载完直接copy到项目中(在cpp 目录下创建librtmp 目录,全都丢进去)
- 根据其中Mmakefile可看出哪些文件有用,把删除没用的删掉。
Mmakefile:
...
OBJS=rtmp.o log.o amf.o hashswf.o parseurl.o
...
librtmp.a: $(OBJS)
$(AR) rs $@ $?
...
可以看出需要的是rtmp.o log.o amf.o hashswf.o parseurl.o对应的.c文件,把其他文件都删掉,然后会发现这些.c中有些会报错,因为我们多删除了已引入的.h文件,然后看需要哪些.h再重新copy进来。( 对于这个库最后发现其实没删多少,下面的贴图没做删除,这里只是删除无用代码的方式)。
- Cmakelist中引入:
这里采用Cmakelist嵌套的方式导入,在librtmp目录下创建Cmakelist.txt:
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") #CMAKE_C_FLAGS:用C的方式去编译, -D传入参数
add_library(
rtmp #生成库的名称
STATIC #静态库
amf.c #下面是需要的.c文件,可以在Makefile中看到
hashswf.c
log.c
parseurl.c
rtmp.c
)
然后在工程的Cmakelist文件中添加这个Cmakelist:
...
add_subdirectory(librtmp)#这个路径是相对该CMakeLists.text的dir,不同版本AS中初始CMakeLists路径不同,这里有可能不同,比如会是add_subdirectory(src/main/cpp/librtmp)
add_library( ...)
find_library( ...)
target_link_libraries(
...
rtmp)
目录结构贴一下,参考下add_subdirectory()的参数路径(打码的不用看),这里没有删除RTMPdump中没用的代码:
- 当感觉一切OK的时候,编译一下---->“找不到openssl”
openssl是用来加密的,现在不需要加密,看他的上下逻辑发现如果有定义NO_CRYPTO这个宏宏,就不会走#include这一句,那直接在cmakelist中传入这个宏,编译时加个参数:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO") #CMAKE_C_FLAGS:用C的方式去编译, -D传入参数。
这个不报错的方式有很多,比如删掉,注释掉什么什么的,这里为了以后万一要用ssl,还是用传入参数的方式好。
- 编译成功,成功引入Rtmpdump。
集成x264:
这个库比较大,就不采用copy到as中编译了。
这里先在linux环境交叉编译出x264的库。然后再导入AS中使用。
x264下载地址
- 解压并进入目录,调用./configure就可以编译,但是需要传一些参数,输入./configure --help可以看到参数说明。
- 直接用./configure --参数 --参数 --参数, 肯定是扯了点,这里写一个脚本去执行:
在x264目录下 vim build.sh,这里把编译armeabi-v7a和arm64-v8a的脚本贴一下(这个shell语法我用的不熟练,其实可以把这些写到一个脚本里)
arm64-v8a:
#!/bin/bash
PREFIX=./android/arm64-v8a
TOOLCHAIN=$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
FLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
# --disable-cli : 关闭命令行
# 其他和ffmpeg一样
./configure \
--prefix=$PREFIX \
--disable-cli \
--enable-static \
--enable-pic \
--host=aarch64-linux \
--cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
--sysroot=$NDK_ROOT/platforms/android-21/arch-arm64 \
--extra-cflags="$FLAGS"
make clean
make install
armeabi-v7a:
#!/bin/bash
PREFIX=./android/armeabi-v7a
TOOLCHAIN=$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
FLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=17 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
# --disable-cli : 关闭命令行
# 其他和ffmpeg一样
./configure \
--prefix=$PREFIX \
--disable-cli \
--enable-static \
--enable-pic \
--host=arm-linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--sysroot=$NDK_ROOT/platforms/android-17/arch-arm \
--extra-cflags="$FLAGS"
make clean
make install
其中一些路径相关的参数,一定要确定该路径是对的,可以去ndk目录下查看都否有该文件,比如armeabi-v7a用的android-17,而arm64-v8a中要用android-21,因为android-17中没有arch-arm64。
- NDK_ROOT:环境变量中配置的NDK路径
- prefix:输出目录
- static:静态库
- tra-cflags:这个可以在AS工程目录下app/.externalNativeBuild/cmake/debug/arm64-v8a/build.ninja中找到,这个是AS编译时产生的,要确保AS中使用的ndk版本和Linux现在用的ndk版本一样,然后把copy出来的字符串其中的ndk路径换成Linux当前环境的ndk路径。(可能还会有一些其他的小改动,可以参考上看的尝试一下,或者百度一下)
但是编译x264我们需要注意一点,x264在进行环境检测的时候,使用的是比较宽松的方式,对于我们目前需要编译的android-17为目标来说,编译出的库在使用上会出现问题(对于18以上不会)。
我们需要修改configure
脚本,在脚本中搜索cc_check
vim如何搜索:在vim里底线命令模式,输入 /cc_check
cc_check() {
......
if [ $compiler_style = MS ]; then
cc_cmd="$CC conftest.c -Werror=implicit-function-declaration $(cc_cflags $CFLAGS $CHECK_CFLAGS $2) -link $(cl_ldflags $2 $LDFLAGSCLI $LDFLAGS)"
else
cc_cmd="$CC conftest.c -Werror=implicit-function-declaration $CFLAGS $CHECK_CFLAGS $2 $LDFLAGSCLI $LDFLAGS -o conftest"
fi
......
}
向cc_cmd
内添加 -Werror=implicit-function-declaration
。
- 执行 sh build.sh 因为脚本中写了输出目录,所以如果编译成功,当前目录下应该是多出了个android目录,其中有个arm64-v8a(假设编译的是arm64-v8a)。
- 压缩arm64-v8a:zip -r arm64-v8 arm64-v8/
- 下载该文件到本地 scp ........... 并解压
- 解压后的x264把include文件夹直接放到main/cpp目录下,把libx264.a放到main/cpp/libs/arm64-v8中(目录随便放,这样看起来比较直观,没有目录就创建),贴下目录结构:
打马的是上面导入的librtmp - CmakeList中添加:
...
add_library( ...)
include_directories(include) #这个路径是相对CMakeLists.text的dir,不同版本AS中初始CMakeLists路径不同,这里有可能不同,比如会是include_directories(src/main/cpp/include)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}" ) #CMAKE_CXX_FLAGS会被添加到build.ninja的FLAGS中,ANDROID_ABI是内置变量,不要直接写死armeabi-v7a或arm64-v8
find_library(...)
target_link_libraries(
...
x264)
目录问题导入librtmp时提到过,是相对此CMakeLists.text的dir
集成FAAC:
FAAC下载地址
这个集成跟X264基本一样,先服务器上编译成静态库,然后copy到项目里。过程不再详细写。把v8a的变异脚本贴一下。
#!/bin/bash
PREFIX=`pwd`/android/arm64-v8a
TOOLCHAIN=$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
CROSS_COMPILE=$TOOLCHAIN/bin/aarch64-linux-android
FLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 -g -DAN
DROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa,--noexecstack -Wformat -Werror
=format-security -O0 -fPIC"
export CC="$CROSS_COMPILE-gcc --sysroot=$NDK_ROOT/platforms/android-21/arch-arm64"
export CFLAGS="$FLAGS"
./configure \
--prefix=$PREFIX \
--host=aarch64-linux \
--with-pic \
--enable-shared=no
make clean
make install
如果需要v7a,对应改一下就哦了。
编译好之后把.h文件和.a文件copy到AS工程目录下。OJBK!!!!
项目地址:项目会不断更新,最终会完成推流操作。