因为毕设项目涉及在安卓手机上处理音视频,需要使用OpenCV和FFmpeg库,所以前段时间一直在找Android如何引入OpenCV和FFmpeg,相关教程在网上可以搜到很多,但因为教程编写的时间都很久,很多都存在问题。本文以Opencv-4.5.1和FFmpeg-4.4版本为例,记录下Android项目引入两个音视频库的过程。
Opencv-4.5.2
本次教程引入OpenCV的方式:OpenCV Android SDK + OpenCV动态库 + JNI(可以同时使用Java和C++进行开发)
开发环境:macOS Big Sur-11.2.3 + Android Studio-4.1.2
-
下载相关工具。点击工具栏的SDK Manager,点击SDK Tools,选中CMake和NDK(Side by side),点击apply即可下载所需工具
-
新建Android C++工程
-
下载OpenCV-Android-SDK。下载地址OpenCV Release
-
Android工程引入OpenCV-SDK。点击 File -> new -> Import Module, 选中 OpenCV-Android-SDK/sdk/java 文件夹,点击确定,就会自动识别处模块,导入完成后,会在工程目录下发现 OpenCV 的库,settings.gradle 文件也会相应改变
-
修改OpenCV库的SDK版本。点击 File -> Project Structure- Modules ,选中OpenCV模块,修改SDK版本为你工程对应的SDK版本
-
APP引入OpenCV依赖。打开app目录下的build.gradle,添加OpenCV依赖
dependencies { ... //path后填的之前导入的OpenCV Module名称 implementation project(path: ':opencv452') } 复制代码
此时点击 File -> Project Structure-Dependencies,选中app模块,可以看到已经引入opencv452的依赖
-
修改Opencv模块中的build.gradle设置。
-
首行的
apply plugin: ‘com.android.application’
修改为apply plugin: ‘com.android.library’
-
去掉
defaultConfig { applicationId "org.opencv" } 复制代码
最后Opencv模块中的build.gradle如下图所示:
-
-
将 OpenCV-Android-SDK/sdk/native/libs 目录下全部内容复制到工程目录/app/src/main/jniLibs 目录下(jniLibs目录需要新建)
-
复制头文件。将 OpenCV-Android-SDK/sdk/native/jni/include 目录下全部内容复制到 工程目录/app/libs/include 目录下
-
编辑CMakeList.txt。打开/app/src/main/cpp/CMakeLists.txt文件,添加以下内容
# 该变量为真时会创建完整版本的Makefile set(CMAKE_VERBOSE_MAKEFILE on) #调用头文件的具体路径 include_directories(../../../libs/include) #增加opencv的动态库 add_library(opencv_lib SHARED IMPORTED) #建立链接, IMPORTED_LOCATION 后跟的是jniLibs的相对路径 set_target_properties(opencv_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libopencv_java4.so) 复制代码
-
修改build.gradle。修改app模块下的build.gradle,添加以下内容
-
在android {defaultConfig {cmake { … }}}中添加,具体内容见下方代码
defaultConfig { applicationId "com.bupt.compose3dvideo" minSdkVersion 25 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" //以下为需要添加的代码 arguments "-DANDROID_STL=c++_shared" //可选 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' abiFilters 'x86', 'armeabi-v7a' } } } 复制代码
-
在android {…}中添加,具体内容见下方代码
//以下为需要添加的代码 sourceSets { main { jni.srcDirs = ['/src/main/cpp'] jniLibs.srcDirs = ['src/main/jniLibs'] } } 复制代码
-
-
初始化OpenCV。
-
创建BaseApplication或者在MainActivity中初始化,在onCreate()中调用
OpenCVLoader.initDebug()
即可初始化OpenCV -
如果在BaseApplication中初始化,需要手动添加以下代码,MainActivity中已存在,不需手动添加
companion object { // Used to load the 'native-lib' library on application startup. init { System.loadLibrary("native-lib") } } 复制代码
-
以上就是引入Opencv库的全部步骤,因为同时引入了OpenCV-Android-SDK和OpenCV动态库,会极大增加安装包体积,但好处是可以同时使用Java和C++编程,而且使用FFmpeg时也需要使用JNI,此时先引入OpenCV动态库,方便以后FFmpeg的引入。
FFmpeg-4.4
FFmpeg库需要自己先编译,再引入安卓项目。我遇到的最大的问题是编译FFmpeg的安卓版本,因为网上的教程主要是使用NDK-20以前的版本进行编译,而NDK-20前后版本编译方式有一些差距,所以一开始总是编译失败,后来找到一篇文章,按照教程终于编译成功。
编译Android版本的FFmpeg
开发环境:macOS Big Sur-11.2.3 + Android Studio-4.1.2 + NDK-r22
-
使用homebrew安装yasm、pkg-config、gcc
-
下载FFmpeg和NDK,官网下载Download FFmpeg和NDK官网下载NDK
-
在FFmpeg文件夹下新建build_android.sh文件,文件内容如下
#!/bin/bash # 修改为你本地NDK目录 NDK=/Users/xxx/android-ndk-r22b TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64 API=30 function build_android() { cd ffmpeg-4.4 echo "Compiling FFmpeg for $CPU" ./configure \ --prefix=$PREFIX \ --libdir=$LIB_DIR \ --enable-shared \ --disable-static \ --enable-jni \ --disable-doc \ --disable-symver \ --disable-programs \ --target-os=android \ --arch=$ARCH \ --cpu=$CPU \ --cc=$CC \ --cxx=$CXX \ --enable-cross-compile \ --sysroot=$SYSROOT \ --extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" \ --extra-ldflags="$ADDI_LDFLAGS" \ --disable-asm \ $COMMON_FF_CFG_FLAGS make clean make -j8 make install echo "The Compilation of FFmpeg for $CPU is completed" echo "Output library : $LIB_DIR" cd .. } # 根据自己需要的 cpu, 放开对应的注释即可 # ## armv8-a # function v8() { # source "config-env.sh" # OUTPUT_FOLDER="arm64-v8a" # ARCH=arm64 # CPU="armv8-a" # TOOL_CPU_NAME=aarch64 # TOOL_PREFIX="$TOOLCHAIN/bin/$TOOL_CPU_NAME-linux-android" # CC="$TOOL_PREFIX$API-clang" # CXX="$TOOL_PREFIX$API-clang++" # SYSROOT="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" # PREFIX="${PWD}/android/$OUTPUT_FOLDER" # LIB_DIR="${PWD}/android/libs/$OUTPUT_FOLDER" # OPTIMIZE_CFLAGS="-march=$CPU" # build_android # } # ## armv7-a # function v7() { # source "config-env.sh" # OUTPUT_FOLDER="armeabi-v7a" # ARCH="arm" # CPU="armv7-a" # TOOL_CPU_NAME=armv7a # TOOL_PREFIX="$TOOLCHAIN/bin/arm-linux-androideabi" # CC="$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang" # CXX="$TOOLCHAIN/bin/armv7a-linux-androideabi$API-clang++" # SYSROOT="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" # PREFIX="${PWD}/android/$OUTPUT_FOLDER" # LIB_DIR="${PWD}/android/libs/$OUTPUT_FOLDER" # OPTIMIZE_CFLAGS="-march=$CPU" # build_android # } # ## x86 # function x86() { # source "config-env.sh" # OUTPUT_FOLDER="x86" # ARCH="x86" # CPU="x86" # TOOL_CPU_NAME="i686" # TOOL_PREFIX="$TOOLCHAIN/bin/${TOOL_CPU_NAME}-linux-android" # CC="$TOOL_PREFIX$API-clang" # CXX="$TOOL_PREFIX$API-clang++" # SYSROOT="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" # PREFIX="${PWD}/android/$OUTPUT_FOLDER" # LIB_DIR="${PWD}/android/libs/$OUTPUT_FOLDER" # OPTIMIZE_CFLAGS="-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32" # build_android # } ## x86_64 function x86_64() { source "config-env.sh" OUTPUT_FOLDER="x86_64" ARCH="x86_64" CPU="x86-64" TOOL_CPU_NAME="x86_64" TOOL_PREFIX="$TOOLCHAIN/bin/${TOOL_CPU_NAME}-linux-android" CC="$TOOL_PREFIX$API-clang" CXX="$TOOL_PREFIX$API-clang++" SYSROOT="$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot" PREFIX="${PWD}/android/$OUTPUT_FOLDER" LIB_DIR="${PWD}/android/libs/$OUTPUT_FOLDER" OPTIMIZE_CFLAGS="-march=$CPU" build_android } # 简单使用说明 if [ -z $1 ]; then echo "Usage:" echo " $0 all" echo " $0 armv8" echo " all support cpu :armv7 armv8 x86 x86_64" exit -1 fi # 检测构建全部 HAVE_ALL=0 for arg in $@; do if [ "$arg" == 'all' ]; then HAVE_ALL=1 fi done if [ $HAVE_ALL -eq 1 ]; then x86 x86_64 v8 v7 exit 0 fi # 根据输入参数检测构建哪种cpu for arg in $@; do if [ "$arg" == 'x86' ]; then x86 fi if [ "$arg" == 'x86_64' ]; then x86_64 fi if [ "$arg" == 'armv8' ]; then v8 fi if [ "$arg" == 'armv7' ]; then v7 fi done # 当前NDK版本为r22b, ffmpeg版本为4.4 # 在原作者基础上有修改 # 1. API等级是30 # 2. 4.4 版本并不需要手动修改ffmpeg的configure文件,因为打出来的so文件是没有版本号的 # 3. ffmpeg 目录结构有修改, 所以有一个cd的过程 # 目录结构 # tree -L 1 # . # ├── android # 输出目录 # ├── build_ffmpeg_android.sh # 脚本 # ├── config-env.sh # 选项 # └── ffmpeg-4.3.1 # ffmpeg 目录 # 编译选项可以使用 ./configure -h 查看, 可以根据自己的需求开启或关闭编解码支持, 会显著降低so大小 # 本选项编译出的文件文件尺寸如下: # ll android/libs/arm64-v8a # total 11624 # -rwxr-xr-x 1 caijinglong staff 3.9M 7 26 16:28 libavcodec.so # -rwxr-xr-x 1 caijinglong staff 106K 7 26 16:28 libavfilter.so # -rwxr-xr-x 1 caijinglong staff 771K 7 26 16:28 libavformat.so # -rwxr-xr-x 1 caijinglong staff 443K 7 26 16:28 libavutil.so # -rwxr-xr-x 1 caijinglong staff 82K 7 26 16:28 libswresample.so # -rwxr-xr-x 1 caijinglong staff 398K 7 26 16:28 libswscale.so # 如果想要和ijkplayer那样将所有so合并为一个libffmpeg.so库,可以看下面的说明 # 说是合并,实际上so是不支持合并的, 需要编译出.a静态库而不是so动态库, 然后将多个静态库合并为一个so, 然后用TOOLCHAIN中的gcc命令进行合并 # gcc -shared -o -Wl --whole-archive avcodec.a avfilter.a other.a -Wl,--no-whole-archive 复制代码
-
在FFmpeg文件夹下新建config-env.sh文件,这个环境是 ijkplayer 的 ffmpeg 配置,文件内容如下
#! /usr/bin/env bash # shell/config.sh # 这个来自ijkplayer的ffmpeg配置, 会在上面的build脚本中被引入 #-------------------- # Standard options: export COMMON_FF_CFG_FLAGS= # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --prefix=PREFIX" # Licensing options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gpl" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-version3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-nonfree" # Configuration options: # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-static" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-shared" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-small" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-runtime-cpudetect" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-gray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-swscale-alpha" # Program options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-programs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffmpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffplay" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffprobe" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffserver" # Documentation options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-doc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-htmlpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-manpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-podpages" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-txtpages" # Component options: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avdevice" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avcodec" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avformat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avutil" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swresample" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-swscale" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-postproc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-avfilter" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avresample" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-pthreads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-w32threads" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-os2threads" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-network" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dwt" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lsp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-lzo" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mdct" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-rdft" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fft" # Hardware accelerators: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-d3d11va" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-dxva2" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vaapi" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vdpau" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-videotoolbox" # Individual component options: # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-everything" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-encoders" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=png" # ./configure --list-decoders export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-decoders" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h264" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=hevc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp8" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp9" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263i" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h263p" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mpeg4" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mjpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-hwaccels" # ./configure --list-muxers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-muxers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=mp4" # ./configure --list-demuxers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-demuxers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=concat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=data" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hls" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=live_flv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mov" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mp3" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegps" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegts" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpegvideo" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=flac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=hevc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=webm_dash_manifest" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mpeg4" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mjpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=avi" # ./configure --list-parsers export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-parsers" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac_latm" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=h264" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=flac" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=hevc" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=mpeg4" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=mpeg4video" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=mpegvideo" # ./configure --list-bsf export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-bsfs" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=chomp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=dca_core" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=dump_extradata" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=hevc_mp4toannexb" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=imx_dump_header" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpeg2jpeg" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mjpega_dump_header" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mov2textsub" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mp3_header_decompress" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=mpeg4_unpack_bframes" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=noise" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=remove_extradata" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=text2movsub" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=vp9_superframe" # ./configure --list-protocols export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocols" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=bluray" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=concat" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=crypto" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=gopher" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=icecast" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=libssh" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=md5" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=sctp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=srtp" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=subfile" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=unix" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-devices" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-filters" # External library support: export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-iconv" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-audiotoolbox" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-videotoolbox" # ... # Advanced options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cross-prefix=${FF_CROSS_PREFIX}-" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-cross-compile" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysroot=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --sysinclude=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-os=TAGET_OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-exec=CMD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --target-path=DIR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --toolchain=NAME" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --nm=NM" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ar=AR" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --as=AS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --yasmexe=EXE" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cc=CC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cxx=CXX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --dep-cc=DEPCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --ld=LD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cc=HOSTCC" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cflags=HCFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-cppflags=HCPPFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ld=HOSTLD" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-ldflags=HLDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-libs=HLIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --host-os=OS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-cxxflags=ECFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-ldflags=ELDFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-libs=ELIBS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --extra-version=STRING" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --optflags=OPTFLAGS" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --build-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --malloc-prefix=PREFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --progs-suffix=SUFFIX" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --arch=ARCH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --cpu=CPU" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-pic" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-sram" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-thumb" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-symver" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-hardcoded-tables" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-safe-bitstream-reader" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memalign-hack" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-lto" # Optimization options (experts only): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-altivec" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnow" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-amd3dnowext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mmxext" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ssse3" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-sse42" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-avx" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fma4" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv5te" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-armv6t2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vfp" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-neon" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vis" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-inline-asm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-yasm" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mips32r2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr1" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsdspr2" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-mipsfpu" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-fast-unaligned" # Developer options (useful when working on FFmpeg itself): # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-coverage" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-debug" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-debug=LEVEL" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-optimizations" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-extra-warnings" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-stripping" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --assert-level=level" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-memory-poisoning" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --valgrind=VALGRIND" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-ftrapv" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --samples=PATH" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-xmm-clobber-test" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-random=LIST" # export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --random-seed=VALUE" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf" export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bzlib" 复制代码
-
从终端进入FFmpeg文件目录,执行脚本
chmod +x build_android.sh
修改脚本执行权限./build_android.sh all
运行脚本- 编译过程中会提示clang等执行软件不安全,在Mac的设置-安全性与隐私-通用选项中点击允许即可
-
编译完成后,在FFmpeg文件夹中会生成一个android文件夹,其中.so文件就是编译好的库
Android工程引入FFmpeg
-
新建C++项目或者使用上文OpenCV项目
-
将FFmpeg文件夹中的android/libs对应CPU型号的.so文件,复制到安卓工程app/src/main/jniLibs/对应CPU型号的文件夹内
-
修改build.gradle文件
- 在android {defaultConfig {cmake { … }}}中添加,具体内容见下方代码
defaultConfig { applicationId "com.bupt.compose3dvideo" minSdkVersion 25 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" //以下为需要添加的代码 //可选 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64' abiFilters 'x86', 'armeabi-v7a' } } } 复制代码
-
在android {…}中添加,具体内容见下方代码
//以下为需要添加的代码 sourceSets { main { jni.srcDirs = ['/src/main/cpp'] jniLibs.srcDirs = ['src/main/jniLibs'] } } 复制代码
-
编辑CMakeList.txt。打开/app/src/main/cpp/CMakeLists.txt文件,添加以下内容
add_library(avcodec SHARED IMPORTED) # 注意,IMPORTED_LOCATION是引入.so文件的路径,此路经必须正确 set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavcodec.so) add_library(avformat SHARED IMPORTED) set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavformat.so) add_library(avutil SHARED IMPORTED) set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavutil.so) add_library(swresample SHARED IMPORTED) set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswresample.so) add_library(swscale SHARED IMPORTED) set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libswscale.so) add_library(avfilter SHARED IMPORTED) set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libavfilter.so) 复制代码
-
在com/bupt/opencvandffmpeg目录下新建jni文件夹,新建FFmpegCmd类,实现FFmpeg函数的调用,类内容如下:
object FFmpegCmd { private external fun run(cmdLen: Int, cmd: Array<String>): Int external fun test(): String? fun run(cmd: Array<String>): Int { return run(cmd.size, cmd) } init { System.loadLibrary("avutil") System.loadLibrary("avcodec") System.loadLibrary("swresample") System.loadLibrary("avformat") System.loadLibrary("swscale") System.loadLibrary("avfilter") } } 复制代码
之后就可以调用FFmpegCmd类中的函数。
// 这里记录一下普通JNI使用方式: // 1. 在 Java 层编写 native 方法 // 2. 使用 javah -jni 生成本地接口 // 3. 在 C++ 层实现接口 // 4. 在 Java 层调用 native 方法。 复制代码
总结
虽然成功引入了Opencv和FFmpeg库,但是仍存在很多问题,首先就是引入库文件后导致安装包体积过大的问题,以后有待优化;其次是安卓JNI的使用问题,因为是使用C++编程,对于C++我还不是很熟悉,需要继续学习。
在成功引入Opencv和FFmpeg库之前,每次遇到error都让我很焦躁,因为觉得按照网上教程的步骤来一定会成功,然而不断的error让我有想砸鼠标的冲动,幸好在查找资料、学习进步的过程中不断积累经验,总结之前失败的原因,最终成功引入Opencv和FFmpeg库,所以写下这边文章以记录自己成功的经验。总结的经验就是一定要耐心查找资料,而且要了解这些开源库各版本之间编译或者使用的区别,如果遇到编译error,可以直接复制error信息上网查找解决方案,一步一步来最后终会成功!
参考资料: