1.error: undefined reference to ‘av_version_info()’

出错原因: ffmpeg是纯C的库,头文件没有做好C++调用的准备 用extern “C”{}套住ffmpeg头文件,用C 语言的编译规则来编译ffmpeg代码,就可以了

解决办法:

1
2
3
extern "C"{ 
#include <libavutil/avutil.h>
}

2.libavutil/log.c:186: error: undefined reference to ‘stderr’

出错原因:
代码中使用了大量的标准IO设备:stderr 等,这些在NDK15以后,这些都不被支持了,代码本身 没问题,只是编译器链接时找不到对应的静态库定义了;

解决方案:
在编译选项中添加语句-DANDROID_API=[你的android API版本号]即可; 比如我的测试手机为 android 5.1.1 对应 API = 22,编译选项中应该添加:-DANDROID_API=22
adb shell 获取 android 系统版本: adb shell getprop ro.build.version.release adb shell 获取 android 系统 API 版本: adb shell getprop ro.build.version.sdk

3.libavformat/utils.c:513: error: undefined reference to ‘av_parser_close’

出错原因: 链接静态库先后顺序不正确,引起的符号定义找不到。
解决方案:

  1. 修改静态库的链接顺序。

    1
    2
    3
    4
    target_link_libraries( 
    native-lib
    avfilter avformat avcodec avutil swresample swscale log
    )
  2. 忽略静态库的链接顺序。

    1
    2
    3
    4
    5
    6
    target_link_libraries( 
    native-lib
    -Wl,--start-group
    avcodec avfilter avformat avutil swresample swscale -Wl,--end-group
    log
    )

4.libavformat/http.c:1649: error: undefined reference to ‘inflateEnd’

出错原因: 找不到的z库中的函数的实现。因为 ffmpeg 依赖了z库。编译ffmpeg的时候如果仔细看编译 时输出的日志,就可以看到 External libraries: zlib
解决方案:添加z库的依赖。

1
2
3
4
5
6
7
target_link_libraries( 
native-lib
-Wl,--start-group
avcodec avfilter avformat avutil swresample swscale -Wl,--end-group
log
z
)

5.libavformat/hls.c:845: error: undefined reference to ‘atof’

出错原因:
Google have moved some of the C standard library functions like atof() from being inline functions in header files to normal functions. The latest NDKs will default to building a .so that is only compatible with the latest Android devices that have the atof() function in the device’s standard C library (libc.so). This means if you run a library on an older device that has an older version of the C library, you will get an error loading the dll as the expected atof() function will not exist.
解决方案: 修改ffmpeg编译脚本,指定Android API版本为17,重新编译。

这里又有一个问题:
libavcodec/v4l2_buffers.c:434:44: error: call to ‘mmap’ declared with attribute error: mmap is not available > with _FILE_OFFSET_BITS=64 when using GCC until android-21. Either raise your minSdkVersion, disable > _FILE_OFFSET_BITS=64, or switch to Clang.

所以21版本以下,需要取消 _FILE_OFFSET_BITS宏定义。添加编译参数: -U_FILE_OFFSET_BITS

6.混合编译FFmpeg和Rtmp

6.1 下载最新库
1
2
3
4
5
6
7
// 下载rtmp
wget https://codeload.github.com/yixia/librtmp/zip/refs/heads/master
unzip master

// 下载最新ffmpeg
wget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
tar -xvf ffmpeg-4.2.2.tar.bz2
6.2 单编rtmp脚本

编译androideabi架构

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

NDK_ROOT=/home/jackou/tools/android-ndk-r17c

CPU=arm-linux-androideabi

TOOLCHAIN=$NDK_ROOT/toolchains/$CPU-4.9/prebuilt/linux-x86_64

export XCFLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=17"
export XLDFLAGS="--sysroot=${NDK_ROOT}/platforms/android-17/arch-arm "
export CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-

make install SYS=android prefix=`pwd`/result CRYPTO= SHARED= XDEF=-DNO_SSL

编译arm64-v8a架构

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

NDK_ROOT=/home/jackou/tools/android-ndk-r17c

CPU=aarch64-linux-android

TOOLCHAIN=$NDK_ROOT/toolchains/$CPU-4.9/prebuilt/linux-x86_64

export XCFLAGS="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=17"
export XLDFLAGS="--sysroot=${NDK_ROOT}/platforms/android-17/arch-arm "
export CROSS_COMPILE=$TOOLCHAIN/bin/aarch64-linux-android-

make install SYS=android prefix=`pwd`/result CRYPTO= SHARED= XDEF=-DNO_SSL
6.2混编FFmpeg和rtmp

6.2.1 修改configure文件

6.2.1.1 最新版本的ffmpeg默认使用clang编译,可以修改configure文件来关闭

1
2
3
4
5
6
注释4210-4213行,关闭掉: 
4209
4210 #set_default target_os
4211 #if test "$target_os" = android; then 4212 # cc_default="clang"
4213 #fi
4214

6.2.1.2 由于ffmpeg 默认开启librtmp需要pkgconfig,这里我们手动关闭,修改ffmpeg的configure文件:

1
2
3
4
5
6
##注解掉6256行
6254 enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new
6255 enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo
6256 # enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket
6257 enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++"
6258 enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer

6.2.2 编译androideabi架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/bash

NDK_ROOT=/home/jackou/tools/android-ndk-r17c

CPU=arm-linux-androideabi

TOOLCHAIN=$NDK_ROOT/toolchains/$CPU-4.9/prebuilt/linux-x86_64

ANDROID_API=17

PREFIX=./android/armeabi-v7a/ffmpeg_rtmp

#rtmp路径
RTMP=/root/KevinStudyNDK/MyFFmpeg3/librtmp/result

./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-librtmp \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/$CPU- \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-$ANDROID_API/arch-arm \
--extra-cflags="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -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 -I$RTMP/include" \
--extra-ldflags="-L$RTMP/lib" \
--extra-libs="-lrtmp" \
--arch=arm \
--target-os=android

make clean

make install

编译arm64-v8a架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/bin/bash

NDK_ROOT=/home/jackou/tools/android-ndk-r17c

CPU=aarch64-linux-android

TOOLCHAIN=$NDK_ROOT/toolchains/$CPU-4.9/prebuilt/linux-x86_64

ANDROID_API=21

PREFIX=./android/arm64-v8a/ffmpeg_rtmp

#rtmp路径
RTMP=/home/jackou/ndk/ffmpeg/librtmp-master/result

./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--enable-librtmp \
--enable-cross-compile \
--cross-prefix=$TOOLCHAIN/bin/$CPU- \
--disable-shared \
--enable-static \
--sysroot=$NDK_ROOT/platforms/android-$ANDROID_API/arch-arm64 \
--extra-cflags="-isysroot $NDK_ROOT/sysroot -isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=$ANDROID_API -U_FILE_OFFSET_BITS -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=arm64-v8a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC -I$RTMP/include" \
--extra-ldflags="-L$RTMP/lib" \
--extra-libs="-lrtmp" \
--arch=aarch64 \
--target-os=android

make clean

make install

6.2.3 集成到AS中CMakelist脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 导入FFmpeg的头文件 
include_directories(${CMAKE_SOURCE_DIR}/ffmpeg/include)

# 导入FFmpeg的库文件
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -
L${CMAKE_SOURCE_DIR}/ffmpeg/libs/${CMAKE_ANDROID_ARCH_ABI}") # 导入Rtmp的库文件

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -
L${CMAKE_SOURCE_DIR}/rtmp/libs/${CMAKE_ANDROID_ARCH_ABI}")

target_link_libraries(
my-player
${log-lib}
-Wl,
--start-group
avcodec avfilter avformat avutil swresample swscale -Wl,
--end-group
z
)

7.搭建rtmp服务器

7.1 下载Nginx和rtmp-module
1
2
3
4
5
#下载Nginx
wget http://nginx.org/download/nginx-1.15.3.tar.gz tar xvf nginx-1.15.3.tar.gz

#下载rtmp-module
wget https://codeload.github.com/arut/nginx-rtmp-module/tar.gz/v1.2.1
7.2 执行配置和安装
1
2
3
4
# 生成makefile
./configure --prefix=./bin --add-module=../nginx-rtmp-module-1.2.1
# 生成结果在bin
make install

成功之后,会在/bin下生成conf html logs sbin几个文件。

7.3 配置Nginx
1
2
3
#进入到成果目录,并且配置nginx
cd /bin/conf
vim nginx.conf

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#启动nginx服务器就会报错,权限被拒绝
user root;

worker_processes 1;

#如果启动错误,这个就是错误日志详情
error_log logs/error.log debug;

events {
worker_connections 1024;
}

rtmp {
server {
#注意端口占用 流媒体服务器的端口
listen 1935;

#如果不加,可能会失败
application myapp {
live on;
#丢弃闲置5s的连接
drop_idle_publisher 5s;
}
}
}

#下面就是为了测试 http://139.224.136.101:8080/stat 控制面板的意思
http {
server {
#注意端口占用
listen 8080;
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}

location /stat.xsl
{
root /home/jackou/ndk/Nginx_RTMP/nginx-rtmp-module-1.2.1/;
}

location /control
{
rtmp_control all;
}

location /rtmp-publisher
{
root /home/jackou/ndk/Nginx_RTMP/nginx-rtmp-module-1.2.1/test;
}

location / {
root /home/jackou/ndk/Nginx_RTMP/nginx-rtmp-module-1.2.1/test/www;
}
}
}
7.4 启动服务
1
jackou@ubuntu:~/ndk/Nginx_RTMP/nginx-1.15.3$ sudo bin/sbin/nginx
1
2
3
4
5
6
7
8
9
10
11
12
nginx: [emerg] bind() to 0.0.0.0:1935 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:1935 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:1935 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:1935 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:1935 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:8080 failed (98: Address already in use)
nginx: [emerg] still could not bind()
#端口被占用需要停止服务
1
2
# 停止服务
sudo bin/sbin/nginx -s stop
1
2
#重启后输入如下域名查看是否启动成功
http://139.224.136.101:8080/stat

启动成功之后,就会出现这种情况,139.224.136.101是一个共有云服务器,需要自己买。

ngnix启动成功.png