1.下载NDK
1.1 创建好目录结构
华为云Ubuntu linux默认进来是在root根目录下,我们使用mkdir android命令创建一个android文件夹,然后cd android进入android文件夹下,再mkdir NDK创建一个目录,最终下载存放ndk的目录是/root/android/NDK。
1.2 下载NDK
进入/root/android/NDK目录, 使用如下命令下载NDK:
wget -O ndkR21.zip https://dl.google.com/android/repository/android-ndk-r21-linux-x86_64.zip
我下载的是2020年6月29日最新的NDK版本,最终保存的文件路径是/root/android/NDK/ndkR21.zip
1.3 解压NDK压缩包
使用unzip ndkR21.zip 命令解压zip文件,最终的android NDK的主路径是 /root/android/NDK/android-ndk-r21d 其中android-ndk-r21d为解压出来的文件夹名。
2.下载ffmpeg
2.1 创建好存放目录
使用cd命令进入android目录下,我们使用mkdir ffmpeg命令创建一个ffmpeg文件夹.最终下载并保存ffmpeg源码的目录将是/root/android/ffmpeg
2.2 下载ffmpeg
我下载的是2020年6月14日的官网版本V4.2.3
cd ffmpeg进入ffmpeg文件夹,使用如下命令
wget https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2
压缩包存放路径是/root/android/ffmpeg/ffmpeg-snapshot.tar.bz2
2.3 解压ffmpeg压缩包
cd命令 进入ffmpeg目录,使用tar命令解压tar.bz2文件。
tar xvf ffmpeg-snapshot.tar.bz2 命令解压源码。其中xvf中的x表示解压,v表示输出解压过程信息,f表示文件。
最终ffmpeg源码的路径是:root/android/ffmpeg/ffmpeg-4.2.3
二. 配置环境和编译
1. 配置NDK环境变量
登录你的linux服务器,打开root目录,输入命令:
vim ~./bashrc 打开这个文件,配置NDK_ROOT环境变量。如果bashrc这个文件找不到,请使用ls -a命令列出bashrc这个文件,因为有时候这个文件是隐藏的。
如上图在文件的末尾,插入红色框起来的两句代码。
我的ndk下载解压后的文件夹存放在/root/android/NDK/android-ndk-r21d
这样配置后,我们就可以在shell脚本里直接使用NDK_ROOT这个变量来代替冗长的NDK存放路径了。
2. 编译ffmpeg解码库
注意,最新的ffmpeg编译for android,不再使用gcc++编译器了,而是使用clang编译,因此以下脚本也是针对最新版的NDK(21rd及以上)和ffmpeg(4.2.3及以上)的。
2.1 编译64位 armv8-a架构下的静态库和so动态库
2.1.1 编写脚本
cd 命令打开到 root/android/ffmpeg/ffmpeg-4.2.3 源码目录下,使用vim build.sh创建一个文件,输入以下脚本:
#!/bin/bash
make clean
API=21
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=$API -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -marm -march=$CPU -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"
ADDI_LDFLAGS="";
function build_android
{
echo "Compiling FFmpeg for $CPU and path is $NDK_ROOT"
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--enable-static \
--enable-shared \
--disable-encoders \
--disable-avdevice \
--disable-muxers \
--disable-filters \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC
--cxx=$CXX
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot/" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed and ndk path is $NDK_ROOT"
}
ARCH=arm64
CPU=armv8-a
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
build_android
以上脚本可编译出供android 64位armv8-a CPU架构下使用的静态解码库和动态解码库(解码包括视频和音频解码),主要用于制作播放器来播放网络上的点播视频,播放网红直播等,到时候我们优先使用静态库,动态库会增大APK安装包大小。
脚本中各配置项的注解如下,供大家参考学习:
#!/bin/bash
make clean
API=21
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=$API -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -marm -march=$CPU -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"
ADDI_LDFLAGS="";
function build_android
{
echo "Compiling FFmpeg for $CPU and path is $NDK_ROOT"
./configure \
--prefix=$PREFIX \
--enable-small \ #编译出来的库文件小
--disable-programs \ #不编译命令行程序,即不能用cmd命令来让编解码器执行或调用其它功能。
--enable-static \ #编译静态库,即.a文件
--enable-shared \ #编译动态库
--disable-encoders \ #禁止掉编码器,因为我们将要做一个播放器,只需解码器
--disable-avdevice \ #将不编译libavdevice库,这个库用于读取摄像头设备的图像数据。
--disable-muxers \ #禁止封装音视频,因为我们要做的是播放器,是解封装
--disable-filters \ #禁止FFmpeg filter,filter提供了很多音视频特效处理的功能,比如视频缩放、截取、翻转、叠加等,相当于视频剪辑,这里我们将要做的是播放器,故不需要。
--cross-prefix=$CROSS_PREFIX \ #交叉编译前缀为:$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android- 即引入这个bin目录下的以aarch64-linux-android为前缀的交叉编译器相关的命令,aarch64是用clang编译arm64架构下的库
--target-os=android \ #为android系统编译ffmpeg
--arch=$ARCH \ #cpu架构为arm 64位
--cpu=$CPU \ #cpu指令集为armv8-a,它主要支持64位处理器,又向下兼容32位,更适合现在主流的64为CPU的手机,执行速度快。
--cc=$CC #指定用于编译C语言的编译器为$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang
--cxx=$CXX #指定用于编译C++语言的编译器为$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++
--enable-cross-compile \ #启用交叉编译,必须,因为要在linux PC环境下编译出能在android嵌入式系统下使用的so库,所以必须要用交叉编译,从一个平台编译出另一个平台(这里为android)可以使用的so库
--sysroot=$SYSROOT \ #指定逻辑目录,将在SYSROOT目录的usr文件夹下搜索NDK环境自带的头文件和库
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot/" \ #-isysroot指定头文件的搜索目录为$NDK_ROOT/sysroot/
--extra-ldflags="$ADDI_LDFLAGS" \ #设置要链接的目标库的存放目录,如ffmpeg将来要集成X264、AAC等音视频第三方库。目前不需要这些,此变量ADDI_LDFLAGS的值为空,我们用ffmpeg自带的音视频解码器进行播放视频。
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed and ndk path is $NDK_ROOT"
}
#自定义变量
ARCH=arm64
CPU=armv8-a
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
build_android #调用build_android函数,执行编译ffmpeg
2.1.2 执行脚本,编译成功
cd 进入ffmpeg-4.2.3 , 使用 ./build.sh命令执行2.1.1中书写的脚本。
整个编译过程,10分钟内吧,你可以去喝杯茶。
编译成功后,进入cd ffmpeg-4.2.3/android/armv8-a目录,就可以看到生成了如下3个目录,如下图:
其中lib里就存放的我们编译的目标库(静态和动态都)
cd lib命令打开lib文件夹,然后ls命令查看里面的内容如下:
其中libavcodec.a,libavfilter.a, libavformat.a, libavutil.a, libswresample.a,libswscale.a为静态库
对应的libavcodec.so,libavfilter.so, libavformat.so, libavutil.so, libswresample.so,libswscale.so为动态库。
2.2 编译32位CPU armv7-a架构下的静态库和so动态库
类似于编译armv8-a 64位CPU架构下的脚本,只是把CPU相关的参数换成了armv7-a 32位,还有交叉编译前缀都换成了arm-linux-androideabi。
2.2.1 编写脚本如下:
#!/bin/bash
make clean
API=21
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$API -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -marm -march=$CPU -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"
ADDI_LDFLAGS="";
function build_android
{
echo "Compiling FFmpeg for $CPU and path is $NDK_ROOT"
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--enable-static \
--enable-shared \
--disable-encoders \
--disable-avdevice \
--disable-muxers \
--disable-filters \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC
--cxx=$CXX
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot/" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed and ndk path is $NDK_ROOT"
}
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
build_android
2.2.2 执行脚本,编译成功
android目录下多了一个armv7-a目录,里面内容同armv8-a一样,只不过是32位的库。
我们可以把编译64位与32位的脚本融为一体,脚本如下:
#!/bin/bash
make clean
API=21
TOOLCHAIN=$NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=$API -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -marm -march=$CPU -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
INCLUDES=" -isystem $NDK_ROOT/sources/android/support/include"
ADDI_LDFLAGS="";
CPU_V7=armv7-a
CPU_V8=armv8-a
function build_android
{
if [ $CPU = $CPU_V7 ]
then
echo " FLAGS=$FLAGS,CROSS_PREFIX=$CROSS_PREFIX"
else
FLAGS="-isystem $NDK_ROOT/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=$API -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -marm -march=$CPU -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
echo " FLAGS=$FLAGS,CROSS_PREFIX=$CROSS_PREFIX"
fi
echo "Compiling FFmpeg for $CPU and path is $NDK_ROOT"
./configure \
--prefix=$PREFIX \
--enable-small \
--disable-programs \
--enable-static \
--enable-shared \
--disable-encoders \
--disable-avdevice \
--disable-muxers \
--disable-filters \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--cpu=$CPU \
--cc=$CC
--cxx=$CXX
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_ROOT/sysroot/" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
echo "The Compilation of FFmpeg for $CPU is completed and ndk path is $NDK_ROOT"
}
ARCH=arm
CPU=armv7-a
CC=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang
CXX=$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/arm-linux-androideabi-
PREFIX=$(pwd)/android/$CPU
build_android
ARCH=arm64
CPU=armv8-a
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
build_android
安装WinSCP软件。打开软件,输入用户名,我这里是root, 登录密码(linux服务器登录密码),然后填写服务器IP地址(我的华为云服务器IP).最后点登录按钮。你会发现WinSCP的资源管理器里全是linux服务器上的文件了,可以在文件的右键菜单里选择下载。
OK,今天先到这里,其实我们也不用学这些,因为现在视频直播,点播,编码压缩,解码等都使用的是第三方SDK,比如腾讯直播,网易直播,七牛等第三方SDK,不过这些SDK都是基于ffmpeg来做的并且是收费的,如果你们公司需要自主研发不想花钱,那你的知识就派上用场了。