Android-通过cmake集成ffmpeg

2,741 阅读2分钟

今天给大家介绍把上次编译出来的ffmpeg文件集成到Android中。本文使用的cmake构建的ndk环境。

准备ffmpeg库文件

通过上篇文章Android-ffmpeg编译so文件,相信大家已经编译出来ffmpeg的头文件和so文件了。

如果大家没编译出来也不影响,大家可以点击下载ffmpeg库文件

cmake构建当前项目的NKD环境,同时集成ffmpeg

把我们当前的项目通过cmake构建一个NDK环境出来

  1. 在当前项目moudle下创建一个CMakeLists.txt文件
  2. 在当前moudle的build文件中添加以下内容
android{
    ...
    defaultConfig{
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
            ndk {
                abiFilters "armeabi" #我当前编译的是arm版本,所以此处指填写arm
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
  1. 把ffmpeg库文件导入项目,同时创建自己的C++源文件native-lib.cpp,如图所示

4. 编辑CMakeLists.txt 文件

# 设置最小使用版本
cmake_minimum_required(VERSION 3.4.1)

# 添加本地so库 native-lib:这个是声明引用so库的名称 SHARED:表示共享so库文件
# 构建so库的源文件
add_library(
    native-lib
    SHARED
    src/main/cpp/native-lib.cpp
)
# 使用系统ndk 提供的库,如 log库
# log-lib 这个指定的是在NDK库中每个类型的库会存放一个特定的位置,而log库存放
# 在log-lib中
# log 指定使用log库
find_library(
    log-lib
    log
)
#----------------------ffmpeg的库文件------------
# 加载头文件
include_directories(src/main/cpp/include)

# 加载avcodec-57库
add_library( avcodec-57
             SHARED
             IMPORTED)
set_target_properties( avcodec-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libavcodec-57.so)

add_library( avdevice-57
             SHARED
             IMPORTED)
set_target_properties( avdevice-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libavdevice-57.so)
add_library( avfilter-6
                SHARED
                IMPORTED)
set_target_properties( avfilter-6
                          PROPERTIES IMPORTED_LOCATION
                          ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libavfilter-6.so)
add_library( avformat-57
             SHARED
             IMPORTED)
set_target_properties( avformat-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libavformat-57.so)
add_library( avutil-55
             SHARED
             IMPORTED)
set_target_properties( avutil-55
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libavutil-55.so)
add_library( swresample-2
             SHARED
             IMPORTED)
set_target_properties( swresample-2
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libswresample-2.so)
add_library( swscale-4
             SHARED
             IMPORTED)
set_target_properties( swscale-4
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libswscale-4.so)
#----------------------end-----------------------

# 如果你本地的库(native-lib)想要调用log库的方法,
# 那么就需要配置这个属性,意思是把NDK库关联到本地库。
# 第一个参数表示本地的库 native-lib 要调用到log库的方法,即要被关联的库名称,log-lib 要关联的库名称
target_link_libraries(
    native-lib
    #ffmpeg------start----------
    avcodec-57
    avdevice-57
    avfilter-6
    avformat-57
    avutil-55
    swresample-2
    swscale-4
    #ffmpeg------end------------
    ${log-lib}
)
  1. 编译一下项目,这个时候就集成成功了

测试一下

  1. Java层,创建一个native方法,同时加载native-lib
public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView text = (TextView) findViewById(R.id.text);
        text.setText(helloNDK("你好 C++ \n"));
    }
    public native String helloNDK(String msg);
}
  1. C++层,对应创建helloNDK的方法
#include <jni.h>
#include <android/log.h>
extern "C"{
#include <libavformat/avformat.h>
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ffmpeg_1test_MainActivity_helloNDK(JNIEnv* env,jobject,jstring msg){
    char* chello = (char *) env->GetStringUTFChars(msg, JNI_FALSE);
    __android_log_print(ANDROID_LOG_ERROR,"tag","c : %s",chello);#log日志打印
    __android_log_print(ANDROID_LOG_ERROR,"tag","编码器配置: %s",avcodec_configuration());#log日志打印
    char * newstr = strcat(chello,avcodec_configuration());#将java传过来的字符串和编码器配置信息拼接起来并返回去
    return env->NewStringUTF(newstr);
}
  1. 运行得到以下结果