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

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

新建Android工程

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

修改gradle配置

新建的Android工程需要对项目中的app/build.gradle做一些修改,其中主要修改的地方如下:

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中会有很多标红,添加了这个配置属性后,各种讨厌的标红就去无踪了?。

导入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.java

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

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

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方法是会标红报错的

配置CMakeLists

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

# 添加库——自己编写的库
# 库名称: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文件,肯定会失败!

编写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平台

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值