RTMPDump 用来处理 RTMP 流媒体的开源工具包。能够单独使用 RTMP 通信,也可以集成到 FFmpeg 中通过 FFmpeg 接口来使用 RTMPDump。
下载地址:http://rtmpdump.mplayerhq.hu/
介绍两种方式引入 RTMPDump 的方式,一种使用 NDK 提供的交叉编译工具来进行编译成静态库再引入,第二种源码集成。实际场景中可自行选择,如果源码不多的情况下推荐使用源码集成的方式。不过有时候我们需要大量引入 C/C++ 库,这个时候还是考虑使用静态库的方式,这样源文件就不显得很多。
交叉编译工具
使用 NDK 提供的交叉编译工具来生成静态库,首先我们下载源码,可以查看一下源码。一般开源项目都会提供 Makefile 或 CMake 编译脚本。RTMPDump 提供了 Makefile,不过它有两个,一个是根目录下,另一个在 librtmp 下。 先来看根目录下:
....
# 编译工具 gcc, 但是我在用 mac 时会使用 clang 替代,具体看我后面编译脚本。
CC=$(CROSS_COMPILE)gcc
# 链接器
LD=$(CROSS_COMPILE)ld
# 目标系统
SYS=posix
#SYS=mingw
# Openssl 加密,因为 RTMP 流媒体协议支持双向加密
CRYPTO=OPENSSL
#CRYPTO=POLARSSL
#CRYPTO=GNUTLS
LIBZ=-lz
LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ)
LIB_OPENSSL=-lssl -lcrypto $(LIBZ)
LIB_POLARSSL=-lpolarssl $(LIBZ)
CRYPTO_LIB=$(LIB_$(CRYPTO))
DEF_=-DNO_CRYPTO
CRYPTO_DEF=$(DEF_$(CRYPTO))
DEF=-DRTMPDUMP_VERSION=\"$(VERSION)\" $(CRYPTO_DEF) $(XDEF)
OPT=-O2
# 编译参数 XCFLAGS 会从外部指定.
CFLAGS=-Wall $(XCFLAGS) $(INC) $(DEF) $(OPT)
LDFLAGS=-Wall $(XLDFLAGS)
......
LIBRTMP=librtmp/librtmp.a
INCRTMP=librtmp/rtmp_sys.h librtmp/rtmp.h librtmp/log.h librtmp/amf.h
......
PROGS=rtmpdump rtmpgw rtmpsrv rtmpsuck
# 依赖两个目标:LIBRTMP 和 PROGS, 由于我们生成的是 Android 平台,所以这里我们不关心 PROGS,后面我会删掉这个目标。
all: $(LIBRTMP) $(PROGS)
$(PROGS): $(LIBRTMP)
# 安装,创建文件、复制文件到指定目录
install: $(PROGS)
-mkdir -p $(BINDIR) $(SBINDIR) $(MANDIR)/man1 $(MANDIR)/man8
cp rtmpdump$(EXT) $(BINDIR)
cp rtmpgw$(EXT) rtmpsrv$(EXT) rtmpsuck$(EXT) $(SBINDIR)
cp rtmpdump.1 $(MANDIR)/man1
cp rtmpgw.8 $(MANDIR)/man8
@cd librtmp; $(MAKE) install
clean:
rm -f *.o rtmpdump$(EXT) rtmpgw$(EXT) rtmpsrv$(EXT) rtmpsuck$(EXT)
@cd librtmp; $(MAKE) clean
FORCE:
# 执行 librtmp 目录下的 Makefile 文件.
$(LIBRTMP): FORCE
@cd librtmp; $(MAKE) all
# 调用编译器编译生成 rtmpdump.o
rtmpdump: rtmpdump.o
$(CC) $(LDFLAGS) -o $@$(EXT) $@.o $(LIBS)
....
librtmp 目录下的 Makefile.
......
# CC 编译器
CC=$(CROSS_COMPILE)gcc
# 链接器
LD=$(CROSS_COMPILE)ld
# ar 打包
AR=$(CROSS_COMPILE)ar
# 目标系统
SYS=posix
# OPENSSL 加密.
CRYPTO=OPENSSL
#CRYPTO=GNUTLS
DEF_POLARSSL=-DUSE_POLARSSL
DEF_OPENSSL=-DUSE_OPENSSL
DEF_GNUTLS=-DUSE_GNUTLS
DEF_=-DNO_CRYPTO
REQ_GNUTLS=gnutls,hogweed,nettle
REQ_OPENSSL=libssl,libcrypto
PUB_GNUTLS=-lgmp
LIBZ=-lz
LIBS_posix=
LIBS_darwin=
LIBS_mingw=-lws2_32 -lwinmm -lgdi32
LIB_GNUTLS=-lgnutls -lhogweed -lnettle -lgmp $(LIBZ)
LIB_OPENSSL=-lssl -lcrypto $(LIBZ)
LIB_POLARSSL=-lpolarssl $(LIBZ)
PRIVATE_LIBS=$(LIBS_$(SYS))
CRYPTO_LIB=$(LIB_$(CRYPTO)) $(PRIVATE_LIBS)
CRYPTO_REQ=$(REQ_$(CRYPTO))
CRYPTO_DEF=$(DEF_$(CRYPTO))
PUBLIC_LIBS=$(PUB_$(CRYPTO))
......
SHARED=yes
......
DEF=-DRTMPDUMP_VERSION=\"$(VERSION)\" $(CRYPTO_DEF) $(XDEF)
OPT=-O2
CFLAGS=-Wall $(XCFLAGS) $(INC) $(DEF) $(OPT) $(SO_DEF)
LDFLAGS=$(XLDFLAGS)
OBJS=rtmp.o log.o amf.o hashswf.o parseurl.o
# 生成 librtmp.a 以及动态库
all: librtmp.a $(SO_LIB)
clean:
rm -f *.o *.a *.$(SOX) *$(SO_EXT) librtmp.pc
# 目标依赖于 OBJS
librtmp.a: $(OBJS)
$(AR) rs $@ $?
librtmp$(SO_EXT): $(OBJS)
$(CC) $(SO_LDFLAGS) $(LDFLAGS) -o $@ $^ $> $(CRYPTO_LIB)
ln -sf $@ librtmp.$(SOX)
# 生成目标的规则.
log.o: log.c log.h Makefile
rtmp.o: rtmp.c rtmp.h rtmp_sys.h handshake.h dh.h log.h amf.h Makefile
amf.o: amf.c amf.h bytes.h log.h Makefile
hashswf.o: hashswf.c http.h rtmp.h rtmp_sys.h Makefile
parseurl.o: parseurl.c rtmp.h rtmp_sys.h log.h Makefile
librtmp.pc: librtmp.pc.in Makefile
sed -e "s;@prefix@;$(prefix);" -e "s;@libdir@;$(libdir);" \
-e "s;@VERSION@;$(VERSION);" \
-e "s;@CRYPTO_REQ@;$(CRYPTO_REQ);" \
-e "s;@PUBLIC_LIBS@;$(PUBLIC_LIBS);" \
-e "s;@PRIVATE_LIBS@;$(PRIVATE_LIBS);" librtmp.pc.in > $@
install: install_base $(SO_INST)
install_base: librtmp.a librtmp.pc
-mkdir -p $(INCDIR) $(LIBDIR)/pkgconfig $(MANDIR)/man3 $(SODIR)
cp amf.h http.h log.h rtmp.h $(INCDIR)
cp librtmp.a $(LIBDIR)
cp librtmp.pc $(LIBDIR)/pkgconfig
cp librtmp.3 $(MANDIR)/man3
......
整体流程大概分析一下,告诉了我们编译规则和依赖,以及安装目录。那么接下来编写 NDK 交叉编译脚本,基于 Mac 平台编写,linux 更改一下工具链位置。
# 交叉编译工具链,基于 ndk-r17c
# 你的交叉编译工具链位置,这里使用的是独立工具链生成.
TOOLCHAIN= /XX/standalone-toolchain/armv7a-standalone-toolchain
# 加入到系统路径
export PATH=$PATH:$TOOLCHAIN/bin
# 目标
target_host=arm-linux-androideabi
# 编译目标品台 api 版本
ANDROID_API=21
# 指定编译器 cflags 编译参数
export XCFLAGS="-isysroot ${TOOLCHAIN}/sysroot -isystem ${TOOLCHAIN}/sysroot/usr/include/${target_host} -D__ANDROID_API__=${ANDRO$
# 交叉编译工具,使用的是 NDK 提供的
export CROSS_COMPILE=${TOOLCHAIN}/bin${target_host}-
# 使用 clang 编译器
CC=$target_host-clang
AR=$target_host-ar
LD=$target_host-ld
make clean
# 安装,指定 SYS 为 android, prefix 安装路径, 不指定 CRYPTO=, 不生成共享库 SHARED ,去掉 ssl 加密
make install SYS=android prefix=`pwd`/install CC=$CC AR=$AR LD=$LD CRYPTO= SHARED= XDEF=-DNO_SSL
chmod +x librtmp_build.sh
./librtmp_build.sh
生成的目录
在 Android Studio 中使用
新建一个 CXX 工程,然后将编译出来头文件和静态库文件拷贝到项目中,如图
CMakeLists.txt 配置文件
cmake_minimum_required(VERSION 3.4.1)
include_directories(${CMAKE_SOURCE_DIR}/include/librtmp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}")
add_library(
native-lib
SHARED
native-lib.cpp )
target_link_libraries(
native-lib
log
rtmp
)
测试获取 RTMPDump 版本
#include <jni.h>
#include <string>
#include "rtmp.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_hxj_rtmpdumpdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
char *str = "hello xxx";
char version[100];
sprintf(version, "rtmpdump version: %d", RTMP_LibVersion());
return env->NewStringUTF(version);
}
引入源码的方式
前面大概介绍了下 Makefile 规则,引入源码的只需要将 librtmp 目录下的源码引入,根目录下生成一些工具,而我们不必关心。
# librtmp 目录下的 Makefile.
# 依赖的目标.
OBJS=rtmp.o log.o amf.o hashswf.o parseurl.o
# 生成 librtmp.a 以及动态库
all: librtmp.a $(SO_LIB)
# 目标依赖于 OBJS
librtmp.a: $(OBJS)
$(AR) rs $@ $?
# 生成目标的规则.
log.o: log.c log.h Makefile
rtmp.o: rtmp.c rtmp.h rtmp_sys.h handshake.h dh.h log.h amf.h Makefile
amf.o: amf.c amf.h bytes.h log.h Makefile
hashswf.o: hashswf.c http.h rtmp.h rtmp_sys.h Makefile
parseurl.o: parseurl.c rtmp.h rtmp_sys.h log.h Makefile
可以知道我们需要那些文件,这里其实就是所有的.h 和 .c 文件。 这里我们新建一个目录 sources 用来存放.h 和 .c 文件,可以使用如下命令拷贝
注意 librtmp 路径
cp -rf ../librtmp/*.h ../librtmp/*.c ./sources
在工程新建一个目录 librtmp,然后拷贝源文件进入
修改 CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.4.1)
include_directories(${CMAKE_SOURCE_DIR}/librtmp)
set(src_dir ${CMAKE_SOURCE_DIR}/librtmp)
file(GLOB srcs ${src_dir}/*.c)
# 或者使用 aux_source_directory 替代 set 和 file 两个指令.
# aux_source_directory(${CMAKE_SOURCE_DIR}/librtmp srcs)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO")
add_library(
native-lib
SHARED
native-lib.cpp
${srcs}
)
target_link_libraries(
native-lib
log
)
由于 RTMPDump 使用到了 openssl, 我这里没有选择使用所以通过编译指令去掉。否则会报错,读者可以去掉试试。
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO")