在编译完 Android 平台下的 FFMpeg 库之后,我们接下来接入到 AndroidStudio 工程中。我们验证的目的是想在 AndroidStudio 控制台中打印 FFMpeg 所有支持的编解码库信息,下面我们来一步一步的实现这个过程。
要完成这个功能主要有以下 2 步:
-
创建支持 C++ 的 AndroidStudio 工程。
-
配置 FFMpeg
1.1 创建支持 C++ 的 AndroidStudio 工程
创建一个支持 C++ 的 AndroidStudio 工程,具体如何创建请点击查看NDK 基本知识点&第一个JNI示例分析,在这里我们只关注与 FFMpeg 相关的东西。这里我们创建的 AndroidStudio 工程名字为 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日晚