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中的接口。

Android平台--基于FFmpeg的播放器开发--Ndk调用ffmpeg接口【02】