FFmpeg生成Android so庫
上篇介紹了如何生成so庫,這次介紹如何集成,
一、新建一個Android C++專案

這時候主工程目錄下會有cpp檔案夾,包含如下兩個檔案:
- CMakeLists.txt:cmake腳本組態檔,cmake會根據該腳本檔案中的指令去編譯相關的C/C++源檔案,并將編譯后產物生成共享庫或靜態塊,然后Gradle將其打包到APK中,
- native-lib.cpp:用來寫C相關的代碼,
二、引入so庫
- app/src/main/cpp:將生成的include整體復制進去
- src/main/jniLibs/arm64-v8a:創建檔案路徑,將生成的lib中的so庫復制進去

三、配置app/build.gradle
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.simple.ffmpeg"
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
//自動生成
externalNativeBuild {
cmake {
cppFlags ''
}
}
//1、手動添加
ndk {
abiFilters "arm64-v8a"
//abiFilters "armeabi-v7a"
}
//2、手動添加
packagingOptions {
pickFirst 'lib/arm64-v8a/libswscale.so'
pickFirst 'lib/arm64-v8a/libavcodec.so'
pickFirst 'lib/lib/arm64-v8a/libavutil.so'
pickFirst 'lib/arm64-v8a/libavutil.so'
pickFirst 'lib/arm64-v8a/libavformat.so'
pickFirst 'lib/arm64-v8a/libavfilter.so'
pickFirst 'lib/arm64-v8a/libswresample.so'
pickFirst 'lib/arm64-v8a/libavdevice.so'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
//自動生成
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.10.2'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
第一個手動添加如果沒有會報:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing process ../Android/sdk/cmake/3.10.2.4988404/bin/ninja with arguments {-C /Users/kewang/code/code_test/Ffmpeg/app/.cxx/cmake/debug/armeabi-v7a native-lib}
ninja: Entering directory `/Users/kewang/code/code_test/Ffmpeg/app/.cxx/cmake/debug/armeabi-v7a'
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
第二個手動添加如果沒有會報:
Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
> More than one file was found with OS independent path 'lib/arm64-v8a/libswscale.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
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
四、CMakeLists.txt鏈接so庫
需要在CMakeLists.txt中把相關的 so 添加和鏈接起來,要不然沒法使用,
cmake_minimum_required(VERSION 3.10.2)
# 支持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})
# 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( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# 配置目標so庫編譯資訊
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
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} )
五、native-lib.cpp添加測驗代碼
完成好CMakeLists之后需要測驗下到底成功沒,這塊列印輸出FFmpeg的資訊,
#include <jni.h>
#include <string>
#include <unistd.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_simple_ffmpeg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavcodec/jni.h>
JNIEXPORT jstring JNICALL
Java_com_simple_ffmpeg_MainActivity_ffmpegInfo(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);
}
}
注意這個函式名稱:Java_com_simple_ffmpeg_MainActivity_stringFromJNI,Java_包名的下劃線格式_Java需要呼叫的方法名稱,
六、加載native-lib.cpp測驗代碼
public class MainActivity extends AppCompatActivity {
// 加載so庫
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.sample_text);
//呼叫JNI方法
tv.setText(ffmpegInfo());
}
/**
* A native method that is implemented by the 'ffmpeg' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native String ffmpegInfo();
}
結果如下:

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/292760.html
標籤:其他
