FFmpeg系列(二)-Android项目引入FFmpeg库播放视频

系列一中讲述了如何编译FFmpeg的源码,如今就在Android项目中引入咱们编译出来的库,并实现播放一个在线视频的功能java

新建Android工程

新建一个支持ndk的Android工程,在AS中新建工程就再也不详述了,详细的新建ndk工程,能够参考AndroidStudio中使用JNI/NDK示例 须要注意的一点就是在新建导航中注意勾选Support C++这个选项,这样新建的Android工程就会有CMakeLists等进行NDK编译时必要的东东了。android

修改gradle配置

新建的Android工程须要对项目中的app/build.gradle作一些修改,其中主要修改的地方以下:git

android {
    ……
    defaultConfig {
        ……
        externalNativeBuild {
            // -Wno-deprecated-declarations 添加这个保证编译出的不少文件再也不报错
            cmake {
                cppFlags "-frtti -fexceptions -Wno-deprecated-declarations"
                cFlags "-DSTDC_HEADERS"
            }
        }
        ndk { // 声明编译的架构类型,指定为armeabi-v7a便可
            abiFilters "armeabi-v7a"
        }
    }

    externalNativeBuild {
        cmake { // 配置咱们本身的CMakeLists文件
            path file('CMakeLists.txt')
        }
    }
    
    sourceSets {
        main {
            // 指定存放native代码的目录,这里指定为jni和cpp皆可
            jni.srcDirs = ['src/main/jni', 'src/main/cpp/'] 
            // 指定jni库的存放目录为libs
            jniLibs.srcDirs = ['libs'] 
        }
    }
}
复制代码

上面配置须要特别说明的一点是,在cmake配置中的cppFlags务必添加-Wno-deprecated-declarations,这样确保咱们能使用一些过时的接口。另外在后面导入FFmpeg编译生成的代码到AS中会有不少标红,添加了这个配置属性后,各类讨厌的标红就去无踪了😏。github

导入FFmpeg代码和库文件

导入以前,先在咱们工程中的app/下新建libs文件夹,而后继续在libs下新建armeabi-v7a和include两个文件夹 架构

此外再在src/main/中新建jni文件
接着进入咱们以前编译好的FFmpeg文件目录中

  1. 将include下的文件所有拷贝到刚才新建的libs/include中
  2. 将lib下的几个so文件所有拷贝到刚才新建的libs/armeabi-v7a中

编写native代码使用FFmpeg

咱们编写一个NDK的桥接类NDKBridge,并在其中定义咱们本身的native库:
NDKBridge.javaapp

public class NDKBridge {
    static {
        // 自定义的native库
        System.loadLibrary("ndk_test_jni");
    }
    ……
}
复制代码

定义一个简单的播放器类FFVideoPlayer,并在其中声明一个名为render的native方法:
FFVideoPlayer.javaide

public class FFVideoPlayer extends SurfaceView {
    ……
    public void play(final String url) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                render(url, FFVideoPlayer.this.getHolder().getSurface());
            }
        }).start();
    }
    // 播放器渲染的方法,须要在native层中实现
    public native void render(String url, Surface surface);
}
复制代码

此时咱们尚未配置CMakeLists文件,也没有新建任何native代码,因此上面声明的native方法是会标红报错的post

配置CMakeLists

配置CMakeLists文件,指定咱们的native代码入口,并指定编译成的native库,以及引用的哪些native代码。下面列出一些须要注意的点,详细内容能够到项目工程中查看gradle

# 添加库——本身编写的库
# 库名称:ndk_test_jni
# 库类型:SHARED,表示动态库,后缀为.so(若是是STATIC,则表示静态库,后缀为.a)
# 库源码文件:src/main/jni/ndk_test_jni.cpp
add_library(ndk_test_jni
        SHARED
        src/main/jni/ndk_test_jni.cpp)

……
# 引入头文件,不然没法在ndk_test_jni.cpp中导入FFmpeg编译出的源文件
include_directories(libs/include)
复制代码

暂时先别执行syc操做,由于都没有ndk_test_jni.cpp文件,确定会失败!ui

编写native代码

根据CMakeLists中的配置,咱们须要在工程的src/main/jni中新建一个ndk_test_jni.cpp文件,而后再执行syc操做。
到上面声明native方法的地方,此时应该仍是标红报错。用鼠标点击右边标红的地方,使错误处于选中状态,而后点击ALT+Enter快捷键,此时AS会弹出建立须要的native方法,点击确认后就会自动在咱们的ndk_test_jni.cpp中新建一个空的Java_cain_tencent_com_androidexercisedemo_ffmpeg_FFVideoPlayer_render方法,这就是咱们在java层声明的native方法的实现。而后就能够愉快地到ndk_test_jni.cpp中去尽情发挥,实现各个native方法了。
具体的代码这里就不贴出来了,具体的能够到项目查看,当中注释也写得很明朗了。这里须要注意的一点就是咱们须要将各个native方法包裹在extern "C" {}中

extern "C" {
#include <cstdio>
#include "lame/lame.h"
//封装格式处理
#include <libavformat/avformat.h>
#include <android/native_window_jni.h>
#include <libavfilter/avfilter.h>
#include <libavcodec/avcodec.h>
//封装格式处理
#include <libavformat/avformat.h>
//像素处理
#include <libswscale/swscale.h>
#include <unistd.h>
/** * 解码视频播,渲染播放 */
extern "C"
JNIEXPORT void JNICALL Java_cain_tencent_com_androidexercisedemo_ffmpeg_FFVideoPlayer_render(JNIEnv *env, jobject instance,jstring url_,jobject surface) {
    ……
}
}
复制代码

不然在编译时会报各类unresolved错误
这里须要播放在线视频,所以也须要记得申请联网权限

播放效果

附录

项目地址

参考

AndroidStudio中使用JNI/NDK示例
在Mac上编译移植FFmpeg-4.0.3到Android平台

相关文章
相关标签/搜索