Unbuntu环境编译 Android平台可用ffmpeg(带三方库fdk-aac和lame)

零、准备

一、理论基础

1.1、shell 中的环境变量

设置环境变量的方法有三种:

  • 第一种是NDKROOT=你的实际路径 这是一种临时的环境变量,只在当前终端可见可用,而且对于一些层级更深的编译不可见,除非你清楚的知道你的变量就在这一层shell中使用
  • 第二种是export CC=YOUR_CC,这种也是一种临时的环境变量,但它的可见性比第一种更广,能够在子级甚至更深的目录中生效或使用。所以保守情况下我们对一些系统环境变量重新赋值时我们会加上export
  • 第三种是系统级的环境变量配置,它会在我们终端初始化时就进行设置,NDKROOT路径。我们要了解这个是因为我们需要在编写我们的shell时,能简化一些内容,比如将常用的文件路径以常量的方式定义,后续我们只需要引用常量即可,对于修改也很方便。对于一些系统自身的环境变量,设置环境变量会覆盖它的值,所以在定义环境变量时注意你是想覆盖它的值还是想新建一个环境变量,通过 envprint 可以查看终端下所有环境变量。

1.2、GCC相关编译指令

我们编译Android端可用的代码,首先需要指定CC工具就是C语言编译器,如果不指定我们使用的是Linux下默认的CC,编译出来的程序也就只能Linux下可用了,对于Android平台不可用,毕竟二者还是有区别的,所以我们需要指定我们的CC。CC的路径就在我们的NDK路径下,NDK包含了各架构的编译工具,当然也包括CXX C++语言编译器。下面会具体讲到。 其次我们需要指定库,我们编译的ffmpeg如果想集成fdk-aac等三方库就得引入三方库的动态链接库的和头文件,指定外部库的编译指令需要有CFLAGS(C编译程序的命令行参数。) -I三方库的头文件路径,以及LDFLAGS(链接器的命令行参数)-L三方库的库文件路径(动态或静态库)

二、配置NDK

  • 下载对应的NDK版本并解压到电脑

尽量不要用中文,且注意NDK版本,如果编译出现奇怪的问题无法解决的话不妨换个NDK版本试试吧,太老的就不要用了。

  • 设置NDK路径到环境变量

打开我们的环境变量文件

vim ~/.bashrc

在最后加上我们的NDK的路径,并重新赋值PATH,PATH是系统默认的环境变量,我们需要再它的基础上添加,不然会导致原有的环境变量不可用

export NDKROOT=/home/zhoubin/Documents/android-ndk-r21c
export PATH=$NDKROOT:$PATH

使环境变量生效

source ~/.bashrc

三、编译开胃菜

3.1 编译lame.so

  • 下载lame源码压缩包并解压
  • 编写我们的shell脚本(以32位V7为例)

在解压的源码路径下编写一个build_v7.sh(名字你随便起)

#NDKROOT我们已经配置环境变量了所以可以直接用,TOOLCHAIN我们在这设置一个零时变量
TOOLCHAIN="$NDKROOT/toolchains/llvm/prebuilt/linux-x86_64" 
#重新赋值我们的CC和CXX,用我们Android自己的C编译器,而且会有32和64之分
#32位V7的我们用armv7a-linux-androideabi
#64位V8的我们用aarch64-linux-android
HOST=armv7a-linux-androideabi
V=21
#至于这个21你可以自己选版本号,看你的目录下有哪些版本
export CC=$TOOLCHAIN/bin/$HOST$V-clang
export CXX=$TOOLCHAIN/bin/$HOST$V-clang++
echo $CC
#PREFIX定义我们的编译输出目录,这里指的是上级目录下新建armeabi-v7a文件夹存放
PREFIX=$(dirname $(pwd))/armeabi-v7a

#最简版本 指定编译动态链接库不编译静态库
#其它参数配置可以在lame源码根目录下执行./configure -h查看默认和支持的配置
function build_config
{
	./configure \
	--enable-static=no \
	--host=$HOST \ #我们代码需要运行的平台
	--disable-frontend \ #不编译可执行的命令程序
	--prefix=$PREFIX
}
build_config
make clean
make -j8 #8是线程数 数字越大编译速度越快,前提是你电脑支持
make install

如果直接这样编译是会出问题的,问题出在./fdk-aac-2.0.2/libSBRdec/src/lpp_tran.cpp文件下,它引用了一个找不到的头文件"log/log.h",我们需要把它替换成"android/log.h",同时将 android_errorWriteLog方法注释掉,如果你很看重这段log的话你可以替换成自己的log(可以但不是很必要),你其实也可以把有__ANDROID__包裹的三段都注释掉。 稍等一会不出意外的话我们就能在我们设置的PREFIX路径看到我们的.so库和头文件之类

3.2 编译ffd-aac.so

其实流程和lame是一样的,不一样的是fdk-aac没有--disable-frontend这个配置,你通过./configure -h看它的帮助里有哪些配置项也能知道。

四、编译ffmpeg

  • 下载ffmpeg源码

下载方式很多,可以下载压缩包也可以git clone获取

  • 修改动态链接库输出名字

如果不修改动态链接库名字那么它本来的样子是libavutils.56.so这种形式和我们平常的命名习惯有所出入,而且网友说Android无法加载(此处并没有证伪,意义不大),所以稳妥起见我们还是把名字改一下。 修改源码根目录下的 configure文件中的

SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'  
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'  
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'  
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'  

修改成

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

  • 编写shell

有了前面的经验其实大多都已经差不多,与前面稍微不同的是我们需要引入ffd-aac和lame的编译好的包,所以我们的CFLAGSLDFLAGS需要配置,我们可以单独配置ffd-aac和lame的头文件和库文件路径,也可以放同一路径下,我更倾向于放同一路径下,起码没那么的路径要指定。其它的一些就是ffmpeg的配置设置了,同样可以通过

./configure -h

查看ffmpeg的可选配置和默认配置。下面是我的shell脚本,我们可以根据自己的需求设置使能特定的编译器,例如我们如果只做音频的编辑我们可以只使能音频的编解码器,去掉视频的编解码,这样我们的包的大小更小编译所花的时间更少,当然你如果不介意包体积,反而更怕有些编解码器漏掉配置你也可以不特定设置,只要使能我们的ffd-aac和lame包即可。当然有些配置是需要三方包的,比如ffplay是需要引入SDL三方包的,它是依靠SDL进行播放,X264也是需要三方包的,默认并不带X264,引入这些三方包其实和lame是一样的,这里就不一一说了。有些配置我会注释在下面的shell脚本里,这是一个v8版本的shell脚本

#!/bin/bash
NDK=$NDKROOT

#我编译的ffd-aac和lame动态链接库生成的位置
EXTC=$(pwd)/libextern
lib_cflag="-I$EXTC/armeabi-v8a/include"
lib_ldflags="-L$EXTC/armeabi-v8a/lib"

#arm
CPU=arm

#版本号,可自选
V=21

#armv7a 和 aarch64
ARCH=aarch64

#32位V7的我们用armv7a-linux-androideabi
#64位V8的我们用aarch64-linux-android
HOST=aarch64-linux-android

TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin

CROSS_PREFIX=$TOOLCHAIN/aarch64-linux-android-

SYSROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot

PREFIX=$(pwd)/android/$ARCH
configure()
{
    ./configure \
    --prefix=$PREFIX \
    --enable-cross-compile \#交叉编译所需配置 使能交叉编译
    --cross-prefix=$CROSS_PREFIX \#交叉编译所需配置,在这个路径下自动去找到nm ar等这些编译工具
    --target-os=android \#交叉编译所需配置 指定代码运行环境
    --arch=$ARCH \#交叉编译所需配置 指定架构(指令集)
    --extra-cflags=$lib_cflag \ #引入外部头文件
    --extra-ldflags=$lib_ldflags \ #引入外部链接库文件
    --cc=$TOOLCHAIN/$HOST$V-clang \
    --cxx=$TOOLCHAIN/$HOS$V-clang++ \
    --disable-static \
    --enable-shared \
    --disable-doc \#禁用文档编译
    --disable-programs \#禁用编译命令行程序
    --disable-avdevice \
    --disable-network \#禁用了网络加载音视频
    --disable-symver \
    --enable-gpl \#开源代码所需
    --enable-pic \#编译位置无关代码
    --enable-jni \#适配Android的jni
    --enable-pthreads \
    --enable-libfdk-aac \
    --enable-neon \#开源代码所需 fdk-aac和lame需要,毕竟别人开源的东西
    --enable-nonfree \#开源代码所需
    --enable-libmp3lame 
  
}

build()
{
    configure
    make clean
    make -j8
    make install
}

build

看完上面你可能有几个问题:

  • 什么是位置无关代码

百度安全验证

  • 什么是nm ar

ar和nm命令的使用_流子的专栏-CSDN博客
在这里不做过多阐述,有兴趣可以去了解,不想了解其实关系不大

五、总结

因为我目前以音频编辑为主,所以引入的都是音频的库,如果有同学想引入x264、opencv这些都是可以的,ffmpeg的可玩性很强。我目前也是一个新手。写这篇文章的原因在于网上有很多教怎么编译的,但是少有讲为什么这么配置,大抵还有一些也是到处复制过来的东西,所以我虽然能编译但是也有很多不懂的地方。所以我花了一点时间讲很多开始并不理解的东西去整理,才有了这篇文章,一来是写一篇自己看得懂的流程,二来也希望帮助到其他人。如果有错误的地方请大家批评指正。如果想要我编译好的动态链接库的也可以私聊我发邮箱。

猜你喜欢

转载自blog.csdn.net/qq_37841321/article/details/122294098