ffmpeg編譯
編譯環(huán)境:
- ndk-21.2.6472646
- ffmpeg-4.2.3
- AndroidStudio 4.0
1.下載源碼
解壓得到目錄

2.修改configure腳本
-
搜索
CMDLINE_SET,添加一行cross_prefix_clangCMDLINE_SET=" $PATHS_LIST ar arch as assert_level build_suffix cc objcc cpu cross_prefix # 新增命令行參數(shù) 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

內(nèi)容如下 具體內(nèi)容需要根據(jù)自己電腦上面ndk環(huán)境進(jìn)行修改
#!/bin/bash
set -x
# 目標(biāo)Android版本
API=19
CPU=armv7-a
#so庫(kù)輸出目錄
OUTPUT=/Users/tanyuanchao/Desktop/ffmpeg/ffmpeg-4.2.3/android/$CPU
# NDK的路徑,根據(jù)自己的NDK位置進(jìn)行設(shè)置
NDK=/Users/tanyuanchao/Library/Android/sdk/ndk/21.2.6472646
# 編譯工具鏈路徑
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64
# 編譯環(huán)境
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
# 這里是定義用幾個(gè)CPU編譯
make -j12
make install
}
build
- 這里我android目標(biāo)版本選擇19
- cpu架構(gòu)選擇armv7-a
- 輸出路徑,ndk路徑自己配置。
4.修改文件為可執(zhí)行文件
chmod +x build_android_clang.sh
5.執(zhí)行開(kāi)始編譯
./build_android_clang.sh
6.編譯完成后得到的目錄

- include文件夾下為頭文件
- lib文件夾下為動(dòng)態(tài)鏈接庫(kù).so文件
android中引入編譯后的庫(kù)
新建項(xiàng)目或者已有項(xiàng)目中進(jìn)行以下操作
1.修改app的build.gradle新增如下內(nèi)容
android {
defaultConfig {
// 新增1
externalNativeBuild {
cmake {
cppFlags ""
// 配置cmake編譯的cpu架構(gòu),否則會(huì)還回去找其他架構(gòu),由于我們只編譯的armeabi-v7a,所以找不到其他會(huì)報(bào)錯(cuò)
abiFilters 'armeabi-v7a'
}
}
}
// 新增2
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
2.創(chuàng)建jniLibs文件夾來(lái)放動(dòng)態(tài)庫(kù)!?。?!這里有坑
- 在下面新建armeabi-v7a文件夾然后將之前編譯后的so文件拷貝進(jìn)來(lái)

3.創(chuàng)建cpp文件夾
在src/main/目錄下新建cpp文件夾
cpp文件夾新建ffmpeg目錄,然后將編譯后的include文件夾全部拷貝過(guò)來(lái)
-
cpp文件夾新建native-lib.cpp,內(nèi)容可以先不管,主要是返回ffmpeg的一些信息,用來(lái)后面測(cè)試是否成功
#include <jni.h> #include <string> #include <unistd.h> extern "C"{ #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavfilter/avfilter.h> #include <libavcodec/jni.h> 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庫(kù)和頭文件所在目錄,方面后面使用 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相關(guān)的so庫(kù) 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 ) # 查找代碼中使用到的系統(tǒng)庫(kù) find_library( log-lib log ) # 配置目標(biāo)so庫(kù)編譯信息 add_library( native-lib SHARED native-lib.cpp ) # 指定編譯目標(biāo)庫(kù)時(shí),cmake要鏈接的庫(kù) target_link_libraries( # 指定目標(biāo)庫(kù),native-lib 是在上面 add_library 中配置的目標(biāo)庫(kù) native-lib # 4. 連接 FFmpeg 相關(guān)的庫(kù) avutil swresample avcodec avfilter swscale avformat avdevice # Links the target library to the log library # included in the NDK. ${log-lib} )第1步:設(shè)置動(dòng)態(tài)庫(kù)文件夾和頭文件夾在你當(dāng)前項(xiàng)目的目錄位置
第3步:依次將so庫(kù)添加進(jìn)來(lái)
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中初始化方法進(jìn)行加載native-lib.cpp文件
- 將textview內(nèi)容設(shè)置為調(diào)用庫(kù)文件返回的方法
5.進(jìn)行運(yùn)行
出現(xiàn)的問(wèn)題,
- 如果運(yùn)行到模擬器,且架構(gòu)為x86會(huì)出現(xiàn)以下問(wèn)題
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"
因?yàn)槲覀兲峁┑膕o文件值提供了armeabi-v7a架構(gòu)支持的,所以會(huì)出現(xiàn)這個(gè)問(wèn)題,解決方案,換cpu架構(gòu)的模擬器,或者直接運(yùn)行到手機(jī)
-
直接運(yùn)行到手機(jī),或者進(jìn)行打包,出現(xiàn)的問(wèn)題
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還記得之前說(shuō)的有坑的地方吧,創(chuàng)建的目錄為jniLibs,找的很多方案,也不知道具體的原因,AS版本為4.0,然后嘗試將jniLibs這個(gè)文件夾的名字修改,我將s去掉,然后修改CMakeLists.txt文件中的第一步
# 1. 定義so庫(kù)和頭文件所在目錄,方面后面使用 set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLib/${ANDROID_ABI})
就可以打包成功了
運(yùn)行效果

以上內(nèi)容根據(jù):開(kāi)發(fā)的貓 的文章進(jìn)行操作,記錄實(shí)現(xiàn)過(guò)程中出現(xiàn)的問(wèn)題