首先新建一个工程,并且勾选 Include C++ Support 即可得到一个基于CMake的模板工程。
在app目录下的build.gradle文件中,android节点下的defaultConfig节点下添加
// APP启动之后一直crash,原因就是没有找到我们在java文件里load的动态库
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
在externalNativeBuild节点下添加
// 指定abiFilters,因为AndroidStudio默认会编译所有架构的动态库
ndk{
abiFilters "armeabi"
}
修改完成后的android节点内容如下:
android {
compileSdkVersion 26
buildToolsVersion "27.0.3"
defaultConfig {
applicationId "com.mazaiting.ffmpegtest"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// APP启动之后一直crash,原因就是没有找到我们在java文件里load的动态库
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
externalNativeBuild {
cmake {
cppFlags "-fexceptions"
}
// 指定abiFilters,因为AndroidStudio默认会编译所有架构的动态库
ndk{
abiFilters "armeabi"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
cmake_minimum_required(VERSION 3.4.1)
find_library( log-lib
log )
set(distribution_DIR ../../../../libs)
add_library( native-lib
SHARED
src/main/cpp/native-lib.cpp )
add_library( avcodec-57
SHARED
IMPORTED)
set_target_properties( avcodec-57
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi/libavcodec-57.so)
add_library( avfilter-6
SHARED
IMPORTED)
set_target_properties( avfilter-6
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi/libavfilter-6.so)
add_library( avformat-57
SHARED
IMPORTED)
set_target_properties( avformat-57
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi/libavformat-57.so)
add_library( avutil-55
SHARED
IMPORTED)
set_target_properties( avutil-55
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi/libavutil-55.so)
add_library( swresample-2
SHARED
IMPORTED)
set_target_properties( swresample-2
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi/libswresample-2.so)
add_library( swscale-4
SHARED
IMPORTED)
set_target_properties( swscale-4
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/armeabi/libswscale-4.so)
include_directories(libs/include)
target_link_libraries( native-lib
avcodec-57
avfilter-6
avformat-57
avutil-55
swresample-2
swscale-4
${log-lib} )
配置命令解释:
add_library( avutil-55
SHARED
IMPORTED)
这里avutil-55表示库的名称,SHARED表示是共享库,一般.so文件,还有STATIC,一般.a文件。IMPORTED表示引用的不是生成的。
2). 用到的需要生产的.so文件
add_library( native-lib
SHARED
src/main/cpp/native-lib.cpp )
最后的参数是源码的路径,如果有更多的源码就接下去写上。
set_target_properties( avutil-55
PROPERTIES IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libavutil-55.so )
这里avutil-55是名字,然后是PROPERTIES IMPORTED_LOCATION加上库的路径。
include_directories(libs/include)
target_link_libraries( native-lib
avcodec-57
avfilter-6
avformat-57
avutil-55
swresample-2
swscale-4
${log-lib} )
如果你进入这一步说明之前的步骤已经没有任何问题,MainActivity.java内容如下:
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@InjectView(R.id.tv_info)
TextView mTvInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 使用了ButterKnife框架
ButterKnife.inject(this);
}
@OnClick({R.id.btn_protocol, R.id.btn_format, R.id.btn_codec, R.id.btn_filter})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btn_protocol:
mTvInfo.setText(urlprotocolinfo());
break;
case R.id.btn_format:
mTvInfo.setText(avformatinfo());
break;
case R.id.btn_codec:
mTvInfo.setText(avcodecinfo());
break;
case R.id.btn_filter:
mTvInfo.setText(avfilterinfo());
break;
default:
break;
}
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
// public native String stringFromJNI();
public native String urlprotocolinfo();
public native String avformatinfo();
public native String avcodecinfo();
public native String avfilterinfo();
}
activity_main.xml
#include
#include
#include
extern "C" {
//编码
#include "libavcodec/avcodec.h"
//封装格式处理
#include "libavformat/avformat.h"
//过滤器
#include "libavfilter/avfilter.h"
#define FFLOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"ffmpeg",FORMAT,##__VA_ARGS__);
#define FFLOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"ffmpeg",FORMAT,##__VA_ARGS__);
JNIEXPORT jstring JNICALL
Java_com_mazaiting_ffmpegtest_MainActivity_urlprotocolinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
av_register_all();
struct URLProtocol *pup = NULL;
struct URLProtocol **p_temp = &pup;
avio_enum_protocols((void **) p_temp, 0);
while ((*p_temp) != NULL) {
sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 0));
}
pup = NULL;
avio_enum_protocols((void **) p_temp, 1);
while ((*p_temp) != NULL) {
sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 1));
}
return env->NewStringUTF(info);
}
JNIEXPORT jstring JNICALL
Java_com_mazaiting_ffmpegtest_MainActivity_avformatinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
av_register_all();
AVInputFormat *if_temp = av_iformat_next(NULL);
AVOutputFormat *of_temp = av_oformat_next(NULL);
while (if_temp != NULL) {
sprintf(info, "%sInput: %s\n", info, if_temp->name);
if_temp = if_temp->next;
}
while (of_temp != NULL) {
sprintf(info, "%sOutput: %s\n", info, of_temp->name);
of_temp = of_temp->next;
}
return env->NewStringUTF(info);
}
JNIEXPORT jstring JNICALL
Java_com_mazaiting_ffmpegtest_MainActivity_avcodecinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
av_register_all();
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[%10s]\n", info, c_temp->name);
c_temp = c_temp->next;
}
return env->NewStringUTF(info);
}
JNIEXPORT jstring JNICALL
Java_com_mazaiting_ffmpegtest_MainActivity_avfilterinfo(JNIEnv *env, jobject instance) {
char info[40000] = {0};
avfilter_register_all();
AVFilter *f_temp = (AVFilter *)avfilter_next(NULL);
while(f_temp != NULL) {
sprintf(info, "%s%s\n", info, f_temp->name);
f_temp = f_temp->next;
}
return env->NewStringUTF(info);
}
jstring
Java_com_mazaiting_ffmpegtest_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
}
注:所有的包含C代码的方法都必须版含在extern "C"{}中