参阅了网上较多的教程,由于各个教程使用Android studio版本存在差异性,照抄后果然出现了大翻车。经过摸索得出了以下亲测无误的方案。
一,ffmpeg存放位置。
ffmpeg有头文件和so库,还有各个CPU指令级对应的so库,网上的方法均均是放在project/module/libs下,这个目录是存在风险的在默认情况下build.gradle会进行以下定义:
dependencies {
...
implementation fileTree(dir: "libs", include: ["*.jar"])
..
}
即会将libs下的*.jar文件打包至项目,个人觉得放置在此处不太合适。所以我选择了放置在了project\module\src\main\ffmpeg
下。其目录结构如下
so存放相关目录
-arm64-v8a
--xxx.so
-armeabi-v7a
--xxx.so
...
#头文件存放相关目录
-libavcodec
-libavdevice
...
尝试过存在在jniLibs目录,但这个目录会与cmake文件中的相关定义冲突导致重复引入so,以致编译失败。
二,CMakeLists.txt文件定义。
文件内容如下
cmake_minimum_required(VERSION 3.10.2)
#引入头文件
include_directories(${CMAKE_SOURCE_DIR}/../ffmpeg/)
#引入so路径
set(DIR ${CMAKE_SOURCE_DIR}/../ffmpeg)
# Declares and names the project.
project("ffmpeg")
add_library(
native-lib
SHARED
native-lib.cpp )
#添加库
add_library(
avcodec
SHARED
IMPORTED
)
#${DIR}为上面定义的so路径,${ANDROID_ABI}为cpu指令路径
set_target_properties(
avcodec
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libavcodec.so)
add_library(
avdevice
SHARED
IMPORTED
)
set_target_properties(
avdevice
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libavdevice.so
)
add_library(
avfilter
SHARED
IMPORTED
)
set_target_properties(
avfilter
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libavfilter.so
)
add_library(
avformat
SHARED
IMPORTED
)
set_target_properties(
avformat
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libavformat.so
)
add_library(
avutil
SHARED
IMPORTED
)
set_target_properties(
avutil
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libavutil.so
)
add_library(
swresample
SHARED
IMPORTED
)
set_target_properties(
swresample
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libswresample.so
)
add_library(
swscale
SHARED
IMPORTED
)
set_target_properties(
swscale
PROPERTIES IMPORTED_LOCATION
${DIR}/${ANDROID_ABI}/libswscale.so
)
find_library(
log-lib
log )
#链接库
target_link_libraries(
native-lib
avcodec
avdevice
avfilter
avformat
avutil
swresample
swscale
${log-lib} )
需要注意的是引入头文件
步骤中${CMAKE_SOURCE_DIR}
变量这个变量表示CMakeLists.txt所在的目录,引入头文件
在自己编写的cpp文件中才能引入头文件不报错。
还需要注意${ANDROID_ABI}
这个变量,这个变量指的是编译时的CPU指令级参数,项目中一般情况下需要兼容多种指令集,而set_target_properties
不能重复映入不同指令集so的,需要通过参数进行引入。
三,cpp文件引入头文件和方法调用
#include <jni.h>
#include <string>
extern "C"{
//cpp必须使用该方法导入第三方头文件
#include "libavcodec/avcodec.h"
}
extern "C" JNIEXPORT jstring JNICALL
Java_top_foxhome_demo_ffmpeg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = avcodec_configuration();
return env->NewStringUTF(hello.c_str());
}
需要将头文件放置在extern "C"{...}
内,否则编译会出错,也无法进行方法调用。
四,build.gradle需要指明编译后生成的指令级。
externalNativeBuild {
cmake {
cppFlags ''
//添加cpu支持
abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'
}
}
abiFilters中的值需要与project\module\src\main\ffmpeg
支持的指令集对应,编译时CMakeLists.txt文件中${ANDROID_ABI}
也与之对应。
代码阅读链接
https://github.com/JunjieHuang945/helloFFMPEG