目录:
RTMP(一)录屏直播理论入门
RTMP(二)搭建推流服务
RTMP (三)音视频采集与数据封包
RTMP(四)交叉编译与CameraX
RTMP (五)摄像头数据处理
RTMP (六)音视频编码推流
使用Android设备进行直播,相比之前手机录屏直播,更为广泛的应用则是摄像头的直播。使用摄像头采集图像数据进行直播分享与手机录屏直播的区别只有采集的图像数据源不同。但是我们使用过MediaCodec进行过编码了。
本次我们将使用第三方软编码库来完成音视频的编码,然而使用软编码库则需要将其移植至Android,我们首先将在Linux/Mac下编译Android可用的库文件即进行交叉编译。
X264
x264是一个开源的H.264/MPEG-4 AVC视频编码函数库,是最好的有损视频编码器之一。 它将作为我们直播数据的视频编码库。
FFmpeg中同样实现了H.264的编码,同时FFmpeg也能够集成X264。本次我们将直接使用X264来进行视 频编码而不是FFmpeg
X264 主页
下载源码:(前提是已经安装git并存在环境变量)
git clone https://code.videolan.org/videolan/x264.git
并不是所有的库都已经存在configure文件,可能只存在configure.ac和makefile.am。这种情况需要借助autoconf来生成configure。
cd x264
ls
发现已经帮助我们生成好了configuration文件
如果存在configure,这时候我们第一反应一定是执行help
./configure --help
Usage: ./configure [options]
Help:
-h, --help print this message
Standard options:
--prefix=PREFIX install architecture-independent files in PREFIX
[/usr/local]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[PREFIX]
--bindir=DIR install binaries in DIR [EPREFIX/bin]
--libdir=DIR install libs in DIR [EPREFIX/lib]
--includedir=DIR install includes in DIR [PREFIX/include]
--extra-asflags=EASFLAGS add EASFLAGS to ASFLAGS
--extra-cflags=ECFLAGS add ECFLAGS to CFLAGS
--extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS
--extra-rcflags=ERCFLAGS add ERCFLAGS to RCFLAGS
Configuration options:
--disable-cli disable cli
--system-libx264 use system libx264 instead of internal
--enable-shared build shared library
--enable-static build static library
--disable-bashcompletion disable installation of bash-completion script
--enable-bashcompletion force installation of bash-completion script
--bashcompletionsdir=DIR install bash-completion script in DIR [auto]
--disable-opencl disable OpenCL features
--disable-gpl disable GPL-only features
--disable-thread disable multithreaded encoding
--disable-win32thread disable win32threads (windows only)
--disable-interlaced disable interlaced encoding support
--bit-depth=BIT_DEPTH set output bit depth (8, 10, all) [all]
--chroma-format=FORMAT output chroma format (400, 420, 422, 444, all) [all]
Advanced options:
--disable-asm disable platform-specific assembly optimizations
--enable-lto enable link-time optimization
--enable-debug add -g
--enable-gprof add -pg
--enable-strip add -s
--enable-pic build position-independent code
Cross-compilation:
--host=HOST build programs to run on HOST
--cross-prefix=PREFIX use PREFIX for compilation tools
--sysroot=SYSROOT root of cross-build tree
External library support:
--disable-avs disable avisynth support
--disable-swscale disable swscale support
--disable-lavf disable libavformat support
--disable-ffms disable ffmpegsource support
--disable-gpac disable gpac support
--disable-lsmash disable lsmash support
-
--prefix
设置编译结果输出目录,一般规范都会存在这个参数 -
--exec-prefix
参数表示我们可以借助这个对编译器(gcc/clang)设置选项 「类似javac设置-classpath」 -
--disable-cli
这个配置是关闭编译命令行工具,在Android,是自己编译代码,用不到,也可以不管,倒库的是后不用就好 -
--enable-shared & --enable-static
这两个参数是指我们编译成静态库.a 还是动态库.so
静态库-> xxxx.c 生成xxxx.a 里面函数
编译时,从xxxx.a 中找到这个函数,与xxxx.c 一起生成一个 a.so
最终 可能 .a 库 10M
动态库-> xxxx.a 生成xxxx.so 里面函数
编译时,只会找有没有这个函数,有就行不做其他操作
运行时,当a.so 执行到这个函数,在动态去找对应的函数
最终,会有两个so .so 6M a.so 5M. 加起来会稍微大一点
多个库情况,a.so 和 b.so 都需要x264
那么这个时候我们应该选择动态库。 静态库会编译两份,动态库是用到时候去找可以公用一份。
-
--enable-debug & --enable-gprof & --enable-strip
给编译器传递参数 相当 gcc -g / clang -g -
--enable-pic
如果编译Android使用的动态库,使用PIC 指令。有的--with-pic. 一些脚本没有提供那么我们可以加上gcc -fPIC 通过 CFLAGS 变量 CFLAGS=“-g -fPIC -xxx" 开启
x264 还给我们提供了跨平台的参数Configuration options:
--cross-prefix
--cross-prefix=前缀- 那么我们相当于使用“gcc xxx.c” 就会用 “前缀-gcc xxxx.c” 编译
--sysroot
查找库,有点类似-L 使用。但是有区别
--extra-cflags
作为传递给编译器的参数,所以就算有些库没有--extra-cflags配置,我们也可以自己创建变量cFLAGS传参
比如指定了搜索路径/abc/
会在 指定的路径/abc/usr/lib/libxxx.so(libxxx.a)
/abc/usr/include/xxx.h
gcc -Lxxx -Ixxx
gcc -Labc
会在 /abc/libxxx.so(libxxx.a)
根据上面的分析我们形成配置脚本, 对于android 我们需要用ndk编译。但是ndk19 以上移除了gcc,高版本我们需要用clang编译工具。在toolchains\llvm 下面可以找到
/Users/xxx/Android/.../sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/
类似路径,我的是Macbook路径
我们如何指定clang 编译器。那么需要给编译器变量CC 的编译器变量
printf -> 这种实现在哪? 标准类库中 好比(java->jdk/rt.jar -> java 官方提供的库)
那么需要我们 c/c++ -> NDK 中的头文件与库 才能给Android中使用
#!/bin/bash
# NDK目录
NDK_ROOT=/Users/xxx/Android/android_SDK/sdk/ndk/21.1.6352462
#编译后安装位置 pwd表示当前目录
PREFIX=`pwd`/android/armeabi-v7a
#目标平台版本,我们将兼容到android-21
API=21
#编译工具链目录
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64
#小技巧,创建一个AS的NDK工程,执行编译,
#然后在 app/.cxx/cmake/debug(release)/自己要编译的平台/ 目录下自己观察 build.ninja与 rules.ninja
#虽然x264提供了交叉编译配置:--cross-prefix,如--corss-prefix=/NDK/arm-linux-androideabi-
#那么则会使用 /NDK/arm-linux-androideabi-gcc 来编译
#然而ndk19开始gcc已经被移除,由clang替代。
# 小常识:一般的库都会使用$CC 变量来保存编译器,我们自己设置CC变量的值为clang。
export CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
export CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
#--extra-cflags会附加到CFLAGS 变量之后,作为传递给编译器的参数,所以就算有些库没有--extra-cflags配置,我们也可以自己创建变量cFLAGS传参
FLAGS="--target=armv7-none-linux-androideabi21 --gcc-toolchain=${TOOLCHAIN} -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security -Oz -DNDEBUG -fPIC "
# echo ${FLAGS}
# prefix: 指定编译结果的保存目录 `pwd`: 当前目录
./configure --prefix=${PREFIX} \
--disable-cli \
--enable-static \
--enable-pic=no \
--host=arm-linux \
--cross-prefix=${TOOLCHAIN}/bin/arm-linux-androideabi- \
--sysroot=${TOOLCHAIN}/sysroot \
--extra-cflags="$cleFLAGS"
make install
FAAC
FAAC是一个MPEG-4和MPEG-2的AAC编码器,我们将使用它作为音频编码库。在Linux/Mac中下载源码:
wget https://nchc.dl.sourceforge.net/project/faac/faac-src/faac-1.29/faac-1.29.9.2.tar.gz
# 解压
tar xvf faac-1.29.9.2.tar.gz
# 进入facc目录
cd faac-1.29.9.2
类似x2264我们编译FAAC 了
-----------------------------------------------------
CameraX
CameraX 是 Android Jetpack 的新增功能,通过该功能,向应用添加相机功能变得更加容易。该库提供了很多兼容性修复程序和解决方法,有助于在很多设备上打造一致的开发者体验。关于CameraX的使用在官网有详细文档及 Example
我们需要获取摄像头的数据自行编码,需要使用分析图片功能。CameraX获取数据格式为YUV_420_888,此数据 被包含在Image中,从Image取出YUV数据,