一、新建Native C++ 工程
首先,不同的工具版本在开发过程中会存在一定的问题,以下为本篇文章的工具版本:
- AndroidStudio版本:3.3
- Gradle版本:gradle-4.10.1-all
- NDK版本:android-ndk-r16b-windows-x86_64
- FFmpeg库版本:4.0(可参考文章"Linux环境下用NDK编译FFmpeg")
版本确定后,我们在AndroidStudio中,新建Native C++工程,项目名为FFmpegWorld
,包名为com.demo.ffmpegworld
,新建成功后,直接运行工程,如在首页出现Hello from C++
字样,表示NDK开发的准备工作完成。如遇到无法运行等问题,可自行百度解决,这里不再赘述。
题外话:随着AS不断的更新,对NDK的支持越来越友好,并且伴随着CMake的编译方法,旧有的android.mk方法已经显得过于繁琐(可以参考:Android NDK开发之HelloWorld)。
二、导入FFmpeg库
将项目由Android
视图转换为Project
视图。
在libs
目录下新建armeabi
文件夹,将FFmpeg的arm\lib
路径下带版本号的.so
文件拷贝过来。
在libs
目录下新建include
文件夹,将FFmpeg的arm\include
路径下的所有文件夹拷贝过来。
最终的拷贝结果如图:
打开app/build.gradle
文件,在android→defaultConfig
结点下,新增sourceSets
结点,并修改externalNativeBuild
结点,具体内容为:
defaultConfig {
//新增sourceSets 结点
sourceSets {
main {
jniLibs.srcDirs = ["libs"]
}
}
//修改externalNativeBuild 结点
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi"
}
}
}
打开src/main/cpp/CMakeLists.txt
文件,在第一个add_library
结点后,增加FFmpeg的关联代码(建议直接复制,路径容易出错):
#------------------------FFmpeg----------------------------------
include_directories(../../../libs/include)
set(DIR ../../../../libs)
MESSAGE("打印")
MESSAGE("路径 " ${DIR})
MESSAGE("路径 " ${CMAKE_CURRENT_SOURCE_DIR})
add_library(avcodec-58
SHARED
IMPORTED)
set_target_properties(avcodec-58
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavcodec-58.so)
add_library(avdevice-58
SHARED
IMPORTED)
set_target_properties(avdevice-58
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavdevice-58.so)
add_library(avformat-58
SHARED
IMPORTED)
set_target_properties(avformat-58
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavformat-58.so)
add_library(avutil-56
SHARED
IMPORTED)
set_target_properties(avutil-56
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavutil-56.so)
add_library(swresample-3
SHARED
IMPORTED)
set_target_properties(swresample-3
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libswresample-3.so)
add_library(swscale-5
SHARED
IMPORTED)
set_target_properties(swscale-5
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libswscale-5.so)
add_library(avfilter-7
SHARED
IMPORTED)
set_target_properties(avfilter-7
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavfilter-7.so)
#------------------------FFmpeg----------------------------------
三、编写Native代码
- 编写java类
FFmpegUtil
:
package com.demo.ffmpegworld; public class FFmpegUtil { static { System.loadLibrary("ffmpeg-util"); } /** * 获取FFmpeg的配置信息 * * @return 配置信息字符串 */ public static native String getAvcodecConfiguration(); }
- 在
app/src/main/cpp
文件夹下,创建ffmpeg-util.h
文件:
#ifndef FFMPEG_NATIVE_LIB_H #define FFMPEG_NATIVE_LIB_H #include <jni.h> #include <string> #include <android/log.h> extern "C" { //编码 #include "libavcodec/avcodec.h" //封装格式处理 #include "libavformat/avformat.h" //像素处理 #include "libswscale/swscale.h" #include <android/native_window_jni.h> #include <unistd.h> JNIEXPORT jstring JNICALL Java_com_demo_ffmpegworld_FFmpegUtil_getAvcodecConfiguration(JNIEnv *env, jobject /* this */); } #define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,##__VA_ARGS__); #define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"jason",FORMAT,##__VA_ARGS__); #endif //FFMPEG_NATIVE_LIB_H
- 在
app/src/main/cpp
文件夹下,创建ffmpeg-util.cpp
文件:
#include "ffmpeg-util.h" extern "C" JNIEXPORT jstring JNICALL Java_com_demo_ffmpegworld_FFmpegUtil_getAvcodecConfiguration(JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; char info[10000] = {0}; sprintf(info, "%s\n", avcodec_configuration()); return env->NewStringUTF(info); }
四、修改CMakeLists文件,编译运行
打开src/main/cpp/CMakeLists.txt
文件,修改第一个add_library
和最后一个target_link_libraries
结点,修改内容分别为:
#add_library结点
add_library( # Sets the name of the library.
ffmpeg-util
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
ffmpeg-util.cpp)
#target_link_libraries结点
target_link_libraries( # Specifies the target library.
ffmpeg-util
# Links the target library to the log library
# included in the NDK.
avcodec-58
avdevice-58
avformat-58
avutil-56
swresample-3
swscale-5
-landroid # Add this.
${log-lib})
修改MainActivity
代码,删除其自带的native方法,改为调用我们刚写好的getAvcodecConfiguration
方法:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(FFmpegUtil.getAvcodecConfiguration());
}
}
编译运行,成功后可以看到生成的.so
包可在app/build/intermediates/cmake/debug/obj
文件夹下找到。安卓界面显示详细的配置信息,至此FFmpeg的HelloWorld程序完成。