Android平台--基于FFmpeg的播放器开发--Ndk调用ffmpeg接口【02】
一、JNI介绍
jni是java提供的一种java、c/c++能够互相调用的一种机制,Android Studio对此提供了很好的支持。
可以在创建Android project的时候,勾选【Include C++ support】,然后一路Next可以创建Sample工程。
二、JNI Sample工程分析
Java文件:
package com.example.bangl.jnitest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib"); //加载动态库,so里是要调用的c/c++接口实现
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI(); //navie方法,以关键字navite来声明
}
C/C++文件:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring
JNICALL
Java_com_example_bangl_jnitest_MainActivity_stringFromJNI(
//函数名称stringFromJNI和Java中的函数名称一致
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
我们可以根据上面的函数名特点来添加自己的jni测试函数
java层添加:
public native String JNITest();
native层添加:
extern "C" JNIEXPORT jstring
JNICALL
Java_com_example_bangl_jnitest_MainActivity_JNITest(
JNIEnv *env,
jobject /* this */) {
std::string hello = "JNI Test";
return env->NewStringUTF(hello.c_str());
}
ok,通过上面的过程,我们添加了自己的测试JNI函数
三、导入FFmpeg的so/头文件到工程中
上一篇中,我们已经生成了ffmpeg基于ARM架构的so和头文件,现在我们需要把他们添加到工程中。
1.导入头文件
a. 生成的include文件夹拷贝到XXX\AndroidStudioProjects\JNITest\app\src\main\cpp\目录下
b.修改app\CMakeLists.txt文件,添加include_directories(src/main/cpp/include),将ffmpeg的头文件
包含到Project中来
2.导入so
a.生成的so文件拷贝到C:\Users\bangl\AndroidStudioProjects\JNITest\app\libs\armeabi-v7a目录下
b.修改CMakeLists文件,添加:
#add ffmpeg library start
add_library( avcodec-58 SHARED IMPORTED )
add_library( avfilter-7-lib SHARED IMPORTED )
add_library( avformat-58-lib SHARED IMPORTED )
add_library( avutil-56-lib SHARED IMPORTED )
add_library( swresample-3-lib SHARED IMPORTED )
add_library( swscale-5-lib SHARED IMPORTED )
##add ffmpeg library end
set_target_properties(avcodec-58 PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libavcodec-58.so)
set_target_properties(avfilter-7-lib PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libavfilter-7.so)
set_target_properties(avformat-58-lib PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libavformat-58.so)
set_target_properties(avutil-56-lib PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libavutil-56.so)
set_target_properties(swresample-3-lib PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libswresample-3.so)
set_target_properties(swscale-5-lib PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/libs/armeabi-v7a/libswscale-5.so)
target_link_libraries( # Specifies the target library.
native-lib
avcodec-58
avfilter-7-lib
avformat-58-lib
avutil-56-lib
swresample-3-lib
swscale-5-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
上面的添加完毕之后,编译报下面的错误:C:/Users/bangl/AppData/Local/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: ../../../../libs/armeabi-v7a/libavcodec-58.so: incompatible target
C:/Users/bangl/AppData/Local/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: ../../../../libs/armeabi-v7a/libavfilter-7.so: incompatible target
C:/Users/bangl/AppData/Local/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: ../../../../libs/armeabi-v7a/libavformat-58.so: incompatible target
C:/Users/bangl/AppData/Local/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: ../../../../libs/armeabi-v7a/libavutil-56.so: incompatible target
C:/Users/bangl/AppData/Local/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: ../../../../libs/armeabi-v7a/libswresample-3.so: incompatible target
C:/Users/bangl/AppData/Local/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/windows-x86_64/lib/gcc/x86_64-linux-android/4.9.x/../../../../x86_64-linux-android/bin\ld: error: ../../../../libs/armeabi-v7a/libswscale-5.so: incompatible target
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
我们需要在app/build.gradle中添加
externalNativeBuild {
cmake {
cppFlags ""
}
ndk {
abiFilters "armeabi-v7a"
}
}
ok,这样之后,编译通过了,我们添加测试代码:
修改java层:
System.loadLibrary("avcodec-58");
System.loadLibrary("avfilter-7");
System.loadLibrary("avformat-58");
System.loadLibrary("avutil-56");
System.loadLibrary( "swresample-3");
System.loadLibrary("swscale-5")
修改native层:
JNICALL
Java_com_example_bangl_jnitest_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
const char* config_av_util = avutil_configuration(); //获取av util的build信息
return env->NewStringUTF(config_av_util);
//std::string hello = "Hello from C++";
//return env->NewStringUTF(hello.c_str());
}
添加编译后,apk运行不起来,logcat提示
java.lang.UnsatisfiedLinkError: dlopen failed: library "libavcodec-58.so" not found
ok,在app/gradle中添加:
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
编译运行,成功取到了av util的编译信息,说明jni成功调用到了ffmpeg中的接口。