版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huanghuangjin/article/details/81809739
ndk-build 脚本用于在NDK中心启动构建脚本
自动探测你的开发系统和应用项目文件以确定要构建的内容
生成二进制文件
将二进制文件复制到应用的项目路径
JNI:java中只能调用c,但是可以在c中调用c++
ABI(应用二进制界面),包含:
CPU指令集
内存字节顺序
可执行二进制文件的格式
解析的各种约定。对齐限制,堆栈使用和调用函数
android支持的ABI:
NEON(浮点的协处理器) 提供一组变量/矢量指令和寄存器(与FPU共享) armeabi 默认 , armeabi-v7a (NEON)
-mfpu=vfp 也可以用 -mfpu=neon
-march=armv7-a (暂定只编译适用于 armeabi-v7a 指令集的版本) --extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -march=armv7-a -mfpu=neon -mfloat-abi=softfp "
配置samba文件共享工具:
sudo apt-get install samba 安装samba
sudo vim /etc/samba/smb.conf 打开配置文件,并光标移到文件末尾,添加:(空格缩进都无所谓)
[mpeg] 共享目录在windows显示的名字
comment = my mpeg 共享的描述
path = /home/hankin/Desktop/mpeg 共享文件路径
browseable = yes 共享文件可以浏览
readonly = no 不只可读
sudo smbpasswd -a hankin 为访问samba共享的文件设置一个用户名,回车后会提示设置密码。 设置好用户后需要重启samba
sudo /etc/init.d/samba restart 重启samba,但是我在ubuntu18上的是 /etc/init.d/smbd
至此在windows运行 \\192.168.1.103 输入创建的用户密码,就可以共享ubuntu中的文件了
Ubuntu18中下载ffmpeg源码,交叉编译ffmpeg:
wget http://ffmpeg.org/releases/ffmpeg-3.4.tar.bz2 ffmpeg-4.0.2.tar.bz2 , 下载ffmpeg到当前目录,不同ffmpeg版本,配置的编译脚本可能有差异
也可以用 git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg 下载到ffmpeg文件夹
unzip android-ndk-r14b-linux-x86_64.zip 解压ndk 下载地址:https://developer.android.google.cn/ndk/downloads/
tar -xvf ffmpeg-3.4.tar.bz2 解压ffmpeg,会生成目录。不要在make编译过的目录下以其他指令集的方式再次编译,会报错,这个时候应该重新tar一个ffmpeg编译
cd ffmpeg-3.4 进入解压目录
sudo apt-get install make 安装make,编译ffmpeg,cmake最终也用make编译的
./configure 配置(.表示ffmpeg的解压目录),生成编译ffmpeg的makefile文件,下面是具体的配置内容。 如果 configure 出错,./ffbuild/config.log中会给出具体错误信息
export NDK=/home/hankin/Desktop/mpeg/ffmpeg/android-ndk-r14b 设置NDK环境变量,export命令设置的变量仅限当前登陆有效,即是一次性的。 可以用 env 命令查看当前所有设置的环境变量
export PLATFORM=$NDK/platforms/android-21/arch-arm 设置PLATFORM环境变量,指定编译的平台,为了兼容,版本不要设的太高?,$NDK表示取环境变量NDK的值
编译ffmpeg时会用到该架构下的so库和头文件
export TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 设置TOOLCHAIN环境变量,工具链,交叉编译工具,linux系统用来做交叉编译
export CPU=armv7-a 设置CPU变量
export PREFIX=./android/$CPU 设置PREFIX变量,设置路径,路径设在哪都可以
./configure \
--prefix=$PREFIX \ 输出的目录,放不同的编译选项的ffmpeg,甚至不同版本的ffmpeg
--target-os=android \ 交叉编译参数,目标系统(有些老版本ffmpeg可以用linux表示android)。 参数意思可以参考 https://blog.csdn.net/handsomehong/article/details/72786174
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \ 交叉编译参数,交叉编译工具
--arch=arm \ 交叉编译参数,cpu架构
--cpu=armv7-a \ 交叉编译参数,选择所需的最低CPU(影响指令选择,可能会在较旧的CPU上崩溃)
--sysroot=$PLATFORM \ 交叉编译参数,交叉编译的系统所依赖的头与库文件在哪里,用该架构下的文件模拟交叉编译的环境
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " \ 交叉编译参数,附加参数,给gcc的,
-I$PLATFORM/usr/include 告诉gcc头文件路径,android-ndk-r14b 使用这个路径
新版的ndk头文件路径已经不在这里了,include路径不对的话,make编译会报错找不到一些头文件
-fPIC gcc编译动态库的选项
-DANDROID 生成宏ANDROID,让gcc知道是ANDROID平台
-mfpu=neon 还可以用 -mfpu=vfp , 最终可以用不同参数编译下,再对比下结果,对比性能
-mfloat-abi=softfp 目前软计算与硬计算区别不大。这两个指令只能用于编译armv7-a,用于编译其他指令集会报错
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \ 使用c交叉编译工具 arm-linux-androideabi-gcc
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \ 使用nm工具NM,nm表示符号查看工具
--enable-shared \ --enable 表示开启的模块(有些是默认就开启的), --enable-shared 表示编译成动态库,3.4版本后这样配置,之前可能需要改动configure文件?
--enable-runtime-cpudetect \ 表示cpu探测,如果如果设置的cpu指令集不支持,自动检测支持的cpu指令集
--enable-gpl \ 表示通用的公共许可证,不开启认证可能一些开源库不能使用,但是开启可能你的一些代码需要开源,看你的选择
--enable-small \ 表示在指令集上编译的时候优先选择让最终编译出的文件变小的一些选项,因此可能会有一些损耗
--enable-cross-compile \ 表示交叉编译
--enable-asm \ 表示开启汇编指令
--enable-neon \ 告诉ffmpeg,开启支持neon协处理器,这个协处理器并不是表示硬解码
--enable-jni \ 开启jni,这里ffmpeg会反过来,通过jni调用java的mediacodec代码去硬解码
--enable-mediacodec \ 开启mediacodec
--enable-decoder=h264_mediacodec \ mediacodec硬解码
--enable-hwaccel=h264_mediacodec \ mediacodec硬件加速
--disable-debug \ --disable 表示禁止的模块,禁止主要是为了加快编译速度,如果开启一些下面的选项,可能还需要开启相应依赖的enable选项
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-postproc \
--disable-avdevice \
--disable-symver \
--disable-stripping
// 上述的用\的方式会报 ERROR: jni not found(windows与linux换行符差异导致的?) ,合成这样的一行就没问题了。 命令执行后会在当前目录下多生成一个 config.h 文件,同时改动一些目录内的文件
./configure --prefix=$PREFIX --target-os=android --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- --arch=arm --cpu=armv7-a --sysroot=$PLATFORM
--extra-cflags="-I$PLATFORM/usr/include -fPIC -DANDROID -mfpu=neon -mfloat-abi=softfp " --cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm --enable-shared --enable-runtime-cpudetect --enable-gpl --enable-small --enable-cross-compile
--enable-asm --enable-decoder=h264_mediacodec --enable-hwaccel=h264_mediacodec --disable-debug --disable-static --disable-doc --disable-ffmpeg
--disable-ffplay --disable-ffprobe --disable-ffserver --disable-postproc --disable-avdevice --disable-symver --disable-stripping
make -j16 make编译,-j16表示开16个线程来编译,加快编译速度
make install 编译安装,执行完此步后,会生成 ./android/arm7v-a 目录,头文件、库文件、doc等都会复制到安装路径下
make clean 清除
最后将这一些列的命令写成shell脚本 build_ffmpeg340_android_v7a.sh 包含配置了neon与mediacodec的编译命令与不包含它们的编译命令,
包含了neon与mediacodec生成的库解码速度比不包含的效率几乎高一倍,包含的解码1080*1920的视频,8线程情况下每秒可解200多帧
如果想看shell脚本执行的命令指令,执行脚本时使用 bash -x ../build_ffmpeg340_android_v7a.sh 即可
设置ffmpeg的库的路径:
-DANDROID_ABI=armeabi-v7a // gradle 传递给 cmake 的变量,即build.gradle中配置的 abiFilters 的值
set(FFMPEG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/%{ANDROID_ABI}) // ffmpeg库的路径设置到变量 FFMPEG_DIR 中
add_library(avformat SHARED IMPORTED) 这里只是标识要生成一个 libavformat.so 的库,IMPORTED 表示需要后面的导入,这里与源码是不一样的,源码是直接就编译成so库了
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${FFMPEG_DIR}/libavformat.so) 表示用 ${FFMPEG_DIR}/libavformat.so 生成 libavformat.so 库,IMPORTED_LOCATION 表示本地导入的路径
target_link_libraries(hjMedia android avformat avcodec swscale avutil ${log-lib}) 表示用多个库链接生成 hjMedia 库,多个库间用空格或分号或回车符隔开
将linux下编译好的ffmpeg的头文件拷贝进as .\android\armv7-a-neon-hard\include to src/main/cpp/mpeg/include 不同指令集编译出来的include都是一样的
将linux下编译好的ffmpeg的库文件拷贝进as .\android\armv7-a-neon-hard\lib to src/main/ffmpegLibs/armeabi-v7a 其他指令集的对应
as安装 CMake simple highlighter 插件,支持编辑 CMakeLists.txt文件时,变量、注释等高亮
JNI原始数据类型:
JNI引用数据类型:(java中的对象都相当于c++中的引用,java与c++不能共享相同的内存空间,因为java的内存回收机制是垃圾回收,即引用计数,当计数为0时jvm就会回收内存,而c++需要程序员手动释放,所以当由java传递一个对象给c++时,用完后需要在c++层面进行引用计数的销毁,否则会造成jvm内存泄漏)