Android 引入 FFMpeg 並列印編解碼庫
在編譯完 Android 平臺下的 FFMpeg 庫之後,我們接下來接入到 AndroidStudio 工程中。我們驗證的目的是想在 AndroidStudio 控制檯中列印 FFMpeg 所有支援的編解碼庫資訊,下面我們來一步一步的實現這個過程。
要完成這個功能主要有以下 2 步:
-
建立支援 C++ 的 AndroidStudio 工程。
-
配置 FFMpeg
1.1 建立支援 C++ 的 AndroidStudio 工程
建立一個支援 C++ 的 AndroidStudio 工程,具體如何建立請點選檢視NDK 基本知識點&第一個JNI示例分析
FFmpeg4Android
。
1.1.1 配置 build.gradle 檔案
-
- 指定輸出異常資訊和輸出的 so 庫為 arm 的 cpu 架構。
-
- 指定 CMakeList.txt 檔案的位置。
android { compileSdkVersion 26 defaultConfig { applicationId "com.liaowj.ffmpeg.helloworld" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" externalNativeBuild { //1 cmake { cppFlags "-frtti -fexceptions" //輸出 arm 架構 abiFilters 'armeabi' } } sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } //2. externalNativeBuild { cmake { //配置 CMakeList.txt 檔案 path "CMakeLists.txt" } } }
1.2 配置 FFMpeg
1.2.1 引入標頭檔案和so庫檔案
將編譯後的 FFMpeg 的標頭檔案和 so 庫拷貝到
ffmpeg4helloworld
工程下的中,具體看以下截圖,在這裡只拷貝 arm 架構的。
1.2.2 CmakeList 中配置 ffmpeg
CMakeList 配置 ffmpeg 主要分為四步:
- 第一步:匯入庫的標頭檔案路徑
匯入標頭檔案。匯入標頭檔案的目的是為了在引用時,只需要寫
.h
檔案的相對地址即可,而不需要寫絕對地址。
include_directories(src/main/cpp/includes)
- 第二步:新增動態庫
新增庫名稱為
avcodec-57
,SHARED
表示動態庫,IMPORTED
表示以匯入的方式使用該庫。這裡只是以avcodec-57
來演示, FFMepeg 其他 so 的引入是一樣的。
avcodec-57
是別名哦
add_library( avcodec-57 SHARED IMPORTED)
- 第三步:設定動態庫路徑
第一步已經給標頭檔案設定了路徑,下面給 so 庫設定路徑。這裡還是以
avcodec-57
為例。
set_target_properties( avcodec-57 # so 庫的名字,就是上面設定的別名
PROPERTIES IMPORTED_LOCATION # 匯入的方式引用
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so) # 該庫實際的位置,這個位置是相對 `CMakeList.txtx` 檔案的位置的。
- 第四步:連結動態庫
連結 FFMpeg 的動態庫。目的是將 so 庫和當前的工程建立關係。
target_link_libraries( # Specifies the target library.
native-lib # 當期工程的庫
# 連結動態庫
avcodec-57
...
log )
下面是 CMakeList.txt 配置程式碼:
cmake_minimum_required(VERSION 3.4.1)
include_directories(src/main/cpp/includes)
add_library( # Sets the name of the library.
native-lib
SHARED
src/main/cpp/native-lib.cpp)
add_library( avcodec-57 SHARED IMPORTED)
set_target_properties( avcodec-57
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so)
add_library( avdevice-57 SHARED IMPORTED)
set_target_properties( avdevice-57
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavdevice-57.so)
add_library( avfilter-6 SHARED IMPORTED)
set_target_properties( avfilter-6
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavfilter-6.so)
add_library( avformat-57 SHARED IMPORTED)
set_target_properties( avformat-57
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavformat-57.so)
add_library( avutil-55 SHARED IMPORTED)
set_target_properties( avutil-55
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavutil-55.so)
add_library( postproc-54 SHARED IMPORTED)
set_target_properties( postproc-54
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libpostproc-54.so)
add_library( swresample-2 SHARED IMPORTED)
set_target_properties( swresample-2
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswresample-2.so)
add_library( swscale-4 SHARED IMPORTED)
set_target_properties( swscale-4
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswscale-4.so)
target_link_libraries( # Specifies the target library.
native-lib
avcodec-57
avdevice-57
avformat-57
avfilter-6
avutil-55
postproc-54
swresample-2
swscale-4
log )
1.3 呼叫 FFMpeg API
- 在 Java 層載入動態庫
FFmpegDemo.java
package com.liaowj.ffmpeg.helloworld;
/**
* @author liaowj
* @time 2018/12/31 11:04 PM
* @desc
**/
public class FFmpegDemo {
//1.載入動態庫
static {
System.loadLibrary("native-lib");
System.loadLibrary("swresample-2");
System.loadLibrary("avcodec-57");
System.loadLibrary("avformat-57");
System.loadLibrary("swscale-4");
System.loadLibrary("postproc-54");
System.loadLibrary("avfilter-6");
System.loadLibrary("avdevice-57");
}
//native 方法,執行 jni 的程式碼
public n ative void logFFMpegInfo();
}
- 編寫 native 程式碼列印 FFMpeg 支援的編解碼庫
native-lib.cpp
#include <jni.h>
#include <string>
#include "android/log.h"
extern "C" {
#include <libavformat/avformat.h>
}
#define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"liaowj",FORMAT,##__VA_ARGS__);
extern "C"
JNIEXPORT void JNICALL
Java_com_liaowj_ffmpeg_helloworld_FFmpegDemo_logFFMpegInfo(JNIEnv *env, jobject instance) {
av_register_all();
AVCodec *c_temp = av_codec_next(NULL);
while (c_temp != NULL) {
switch (c_temp->type) {
case AVMEDIA_TYPE_VIDEO:
LOGI("[Video]:%s", c_temp->name);
break;
case AVMEDIA_TYPE_AUDIO:
LOGI("[Audio]:%s", c_temp->name);
break;
default:
LOGI("[Other]:%s", c_temp->name);
break;
}
c_temp = c_temp->next;
}
}
-
執行呼叫程式
關注控制檯即可看到輸出的列印資訊了。
/**
* @author liaowj
* @time 2018/12/31 11:36 PM
* @desc
**/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* 獲取 FFMpeg 相關資訊,列印到 TextView 中
*
* @param view
*/
public void logFFMpegInfo(View view) {
FFmpegDemo fFmpegDemo = new FFmpegDemo();
fFmpegDemo.logFFMpegInfo();
}
}
以上流程就是第一個 FFMpeg 程式,最後的 c++ 程式碼輸出的就是輸出 FFmpeg 的編解碼器資訊。
專案原始碼:
https://github.com/liaowjcoder/FFmpeg4Android
記錄於 2018年11月8日晚