首先感谢呼啸博主,我收藏了他的文章,以便于自己学习使用。
一、JNI
先创建一个支持C++的Android的工程:
File->New->New Project->Phone and Tablet->Native C++ ->然后选择C++的版本,不清楚C++各个版本的,可以选择Toolchain Default。点击Finished。完成创建。
在创建完成后,我们将视图从Android切换到project。相比普通Android项目,这里多了两个文件夹。一个是app目录下的.cxx目录。一个是src/main/cpp目录。.cxx文件夹就是我们c编译过程中的临时文件。再看cpp目录,这里有两个文件,一个是CMakeLists.txt。这个文件就是需要我们在这里写入要放入工程中所依赖的所有的C++库文件。而native-lib.cpp文件则是C++与JAVA互相调用的中转方法。颇有跨平台Android中JS Bridge的感觉。我们可以查看系统中帮我们创建的示例方法:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_wfffmpeg_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
这里是系统自动创建的示范。我们写自己的文件只需按照这个来就行。注意这里方法名的格式:
Java_com_example_wfffmpeg_MainActivity_stringFromJNI
即是java.com.example.wfffmpeg package下的MainActivity的stringFromJNI。简单来说就是通过命名的规则,来定位一个文件。因为方法名不能出现点号.,所以,方法名用下划线_来代替包名中的.
接着我们来看看MainActivity.java中怎么去和这个方法通信:
package com.example.wfffmpeg;
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");
}
@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(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
看这个文件,这是一个普通Activity。在static的静态区域,使用System.loadLibrary("native-lib")引入nativie-lib库文件,就是我们上面写的桥接文件。也就是说在这个Activity刚启动的时候就引入。接着是方法的声明。注意这里的声明有个前缀native.完整的声明就是 public native String stringFromJNI();而在这个Activity中我们使用这个方法就可以直接调用stringFromJNI();
现在。我们已经了解了JNI的使用方法。那么下面看下作为C++库的FFMPEG,我们在Android中怎么使用吧:
1.在上一篇文章中,我们所编译了FFMPEG,产生了一些库文件,现在我们要把这些库文件,拷贝到工程中去。首先,我们把include文件夹全部拷入libs文件夹下面。
include文件夹下面有这么几个文件夹:
1.libavcodec 编码/解码
2.libavdevice 复用/解复用库专用设备(读设备)
3.libavfilter 基于帧的编辑库图(加特效)
4.libavformat I/O多路复用/解复用库
5.libavutil 常见的实用工具库
6.libpostproc 后处理库
7.libswresample 音频重采样、格式转换和混合
8.libswscale 颜色转换和缩放的图书馆(图像拉伸,像素格式转换)
接着,在libs文件夹下,新建armeabi文件夹。然后把
libavcodec-57.so、libavdevice-57.so、libavfilter-6.so、libavformat-57.so、libavutil-55.so、libpostproc-54.so、libswresample-2.so libswscale-4.so
这8个文件拷入armeabi文件夹下,拷贝后的工程文件结构目录为:
2.在上面一段中,我们说过CMakeLists.txt文件。就是要写入我们工程中所依赖的C++库文件的。因此我们需要在这个文件中写入相关信息:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
include_directories(libs/include)
set(DIR ../../../../libs)
project("wfffmpeg")
add_library(avcodec-57
SHARED
IMPORTED)
set_target_properties(avcodec-57
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavcodec-57.so)
add_library(avdevice-57
SHARED
IMPORTED)
set_target_properties(avdevice-57
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavdevice-57.so)
add_library(avformat-57
SHARED
IMPORTED)
set_target_properties(avformat-57
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavformat-57.so)
add_library(avutil-55
SHARED
IMPORTED)
set_target_properties(avutil-55
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavutil-55.so)
add_library(postproc-54
SHARED
IMPORTED)
set_target_properties(postproc-54
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libpostproc-54.so)
add_library(swresample-2
SHARED
IMPORTED)
set_target_properties(swresample-2
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libswresample-2.so)
add_library(swscale-4
SHARED
IMPORTED)
set_target_properties(swscale-4
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libswscale-4.so)
add_library(avfilter-6
SHARED
IMPORTED)
set_target_properties(avfilter-6
PROPERTIES IMPORTED_LOCATION
${DIR}/armeabi/libavfilter-6.so)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
avfilter-6
avcodec-57
avdevice-57
avformat-57
avutil-55
postproc-54
swresample-2
swscale-4
# Links the target library to the log library
# included in the NDK.
${log-lib})
3.修改app build.gradle文件
在defaultConfig文件中加入:
defaultConfig{
/...
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
}
}
ndk {
//选择要添加的对应cpu类型的.so库。
abiFilters 'armeabi-v7a'
// 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
}
}
4.编译
Build -> clean project -> Refresh Linked C++ Projects
然后连接手机,跑一跑,试试这个函数能否调用。如果出现问题,可以在这几个方面排查下:
1.检查CMakeLists.txt中代码配置是否正确。
2.检查CMakeLists.txt中so库是否一致。
3.检查CMakeLists.txt中target_link_libraries()是否遗漏
4.检查build.gradle文件中配置是否正确。
5.尝试在Project Structure中更换SDK版本。
原文链接:https://blog.csdn.net/howlaa/article/details/112824965