ffmpeg编译
编译环境:
- ndk-21.2.6472646
- ffmpeg-4.2.3
- AndroidStudio 4.0
1.下载源码
下载地址
解压得到目录
2.修改configure脚本
-
搜索
CMDLINE_SET
,添加一行cross_prefix_clang
CMDLINE_SET=" $PATHS_LIST ar arch as assert_level build_suffix cc objcc cpu cross_prefix # 新增命令行参数 cross_prefix_clang custom_allocator cxx dep_cc # 省略其他..... "
-
搜索
ar_default="${cross_prefix}${ar_default}"
修改其中两行# 初始为 ar_default="${cross_prefix}${ar_default}" cc_default="${cross_prefix}${cc_default}" cxx_default="${cross_prefix}${cxx_default}" nm_default="${cross_prefix}${nm_default}" pkg_config_default="${cross_prefix}${pkg_config_default}" #修改为 ar_default="${cross_prefix}${ar_default}" #------------------------------------------------这两行需要修改 cc_default="${cross_prefix_clang}${cc_default}" cxx_default="${cross_prefix_clang}${cxx_default}" #------------------------------------------------ nm_default="${cross_prefix}${nm_default}" pkg_config_default="${cross_prefix}${pkg_config_default}"
3.新建编译脚本build_android_clang.sh
内容如下 具体内容需要根据自己电脑上面ndk环境进行修改
#!/bin/bash
set -x
# 目标Android版本
API=19
CPU=armv7-a
#so库输出目录
OUTPUT=/Users/tanyuanchao/Desktop/ffmpeg/ffmpeg-4.2.3/android/$CPU
# NDK的路径,根据自己的NDK位置进行设置
NDK=/Users/tanyuanchao/Library/Android/sdk/ndk/21.2.6472646
# 编译工具链路径
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 编译环境
SYSROOT=$TOOLCHAIN/sysroot
function build
{
./configure \
--prefix=$OUTPUT \
--target-os=android \
--arch=arm \
--cpu=armv7-a \
--enable-asm \
--enable-neon \
--enable-cross-compile \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffplay \
--disable-ffprobe \
--disable-symver \
--disable-ffmpeg \
--sysroot=$SYSROOT \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--cross-prefix-clang=$TOOLCHAIN/bin/armv7a-linux-androideabi$API- \
--extra-cflags="-fPIC"
make clean all
# 这里是定义用几个CPU编译
make -j12
make install
}
build
- 这里我android目标版本选择19
- cpu架构选择armv7-a
- 输出路径,ndk路径自己配置。
4.修改文件为可执行文件
chmod +x build_android_clang.sh
5.执行开始编译
./build_android_clang.sh
6.编译完成后得到的目录
- include文件夹下为头文件
- lib文件夹下为动态链接库.so文件
android中引入编译后的库
新建项目或者已有项目中进行以下操作
1.修改app的build.gradle新增如下内容
android {
defaultConfig {
// 新增1
externalNativeBuild {
cmake {
cppFlags ""
// 配置cmake编译的cpu架构,否则会还回去找其他架构,由于我们只编译的armeabi-v7a,所以找不到其他会报错
abiFilters 'armeabi-v7a'
}
}
}
// 新增2
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
2.创建jniLibs文件夹来放动态库!!!!这里有坑
- 在下面新建armeabi-v7a文件夹然后将之前编译后的so文件拷贝进来
3.创建cpp文件夹
在src/main/目录下新建cpp文件夹
cpp文件夹新建ffmpeg目录,然后将编译后的include文件夹全部拷贝过来
-
cpp文件夹新建native-lib.cpp,内容可以先不管,主要是返回ffmpeg的一些信息,用来后面测试是否成功
#include
#include #include extern "C"{ #include #include #include #include JNIEXPORT jstring JNICALL Java_com_elitetyc_elitevideo_MainActivity_ffmpegName(JNIEnv *env, jobject /* this */) { char info[40000] = {0}; AVCodec *c_temp = av_codec_next(NULL); while (c_temp != NULL) { if (c_temp->decode != NULL) { sprintf(info, "%sdecode:", info); } else { sprintf(info, "%sencode:", info); } switch (c_temp->type) { case AVMEDIA_TYPE_VIDEO: sprintf(info, "%s(video):", info); break; case AVMEDIA_TYPE_AUDIO: sprintf(info, "%s(audio):", info); break; default: sprintf(info, "%s(other):", info); break; } sprintf(info, "%s[%s]\n", info, c_temp->name); c_temp = c_temp->next; } return env->NewStringUTF(info); } }
-
cpp文件夹新建CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1) # 支持gnu++11 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") # 1. 定义so库和头文件所在目录,方面后面使用 set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}) set(ffmpeg_head_dir ${CMAKE_SOURCE_DIR}/ffmpeg) # 2. 添加头文件目录 include_directories(${ffmpeg_head_dir}/include) # 3. 添加ffmpeg相关的so库 add_library( avutil SHARED IMPORTED ) set_target_properties( avutil PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavutil.so ) add_library( swresample SHARED IMPORTED ) set_target_properties( swresample PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libswresample.so ) add_library( avcodec SHARED IMPORTED ) set_target_properties( avcodec PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavcodec.so ) add_library( avfilter SHARED IMPORTED) set_target_properties( avfilter PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavfilter.so ) add_library( swscale SHARED IMPORTED) set_target_properties( swscale PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libswscale.so ) add_library( avformat SHARED IMPORTED) set_target_properties( avformat PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavformat.so ) add_library( avdevice SHARED IMPORTED) set_target_properties( avdevice PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavdevice.so ) # 查找代码中使用到的系统库 find_library( log-lib log ) # 配置目标so库编译信息 add_library( native-lib SHARED native-lib.cpp ) # 指定编译目标库时,cmake要链接的库 target_link_libraries( # 指定目标库,native-lib 是在上面 add_library 中配置的目标库 native-lib # 4. 连接 FFmpeg 相关的库 avutil swresample avcodec avfilter swscale avformat avdevice # Links the target library to the log library # included in the NDK. ${log-lib} )
第1步:设置动态库文件夹和头文件夹在你当前项目的目录位置
第3步:依次将so库添加进来
4.MainActivity修改
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvName.text = ffmpegName()
}
private external fun ffmpegName():String
companion object{
init {
System.loadLibrary("native-lib")
}
}
}
- companion object中初始化方法进行加载native-lib.cpp文件
- 将textview内容设置为调用库文件返回的方法
5.进行运行
出现的问题,
- 如果运行到模拟器,且架构为x86会出现以下问题
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.elitetyc.elitevideo-Ixc9OTEY7urV3gNO0Lazeg==/base.apk"],nativeLibraryDirectories=[/data/app/com.elitetyc.elitevideo-Ixc9OTEY7urV3gNO0Lazeg==/lib/x86, /system/lib, /system/product/lib]]] couldn't find "libnative-lib.so"
因为我们提供的so文件值提供了armeabi-v7a架构支持的,所以会出现这个问题,解决方案,换cpu架构的模拟器,或者直接运行到手机
-
直接运行到手机,或者进行打包,出现的问题
More than one file was found with OS independent path 'lib/armeabi-v7a/libavutil.so'. If you are using jniLibs and CMake IMPORTED targets, see https://developer.android.com/studio/preview/features#automatic_packaging_of_prebuilt_dependencies_used_by_cmake
还记得之前说的有坑的地方吧,创建的目录为jniLibs,找的很多方案,也不知道具体的原因,AS版本为4.0,然后尝试将jniLibs这个文件夹的名字修改,我将s去掉,然后修改CMakeLists.txt文件中的第一步
# 1. 定义so库和头文件所在目录,方面后面使用 set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLib/${ANDROID_ABI})
就可以打包成功了
运行效果
以上内容根据:开发的猫 的文章进行操作,记录实现过程中出现的问题