前言
关于ffmpeg so库的编译,网上存在各种教程。有些基于windows,有些基于linux~而基于linux的:一般会选择安装虚拟机,在其上跑ubuntu系统。其实各种方式都是可以的,只要最后可以编译出我们需要的so库,就是正道。
win10开始自带了linux的子系统,我们可以直接使用该子系统进行编译工作,而无需安装虚拟机等繁琐流程。本章将详细罗列完整流程,大致流程会跟网上类似,但也有更新:
- 编译新版的ffmpeg
- demo中会使用ffmpeg新版的api(注:网上好多教程的demo部分其实无法正常使用,部分api在新版已经废弃)
开启linux子系统
启用子系统服务
打开【启用或关闭 Windows 功能】,勾选【适用于Linux的Windows子系统】或【Windows Subsystem For Linux】
安装完成后,重启电脑
安装linux
打开Microsoft store,搜索linux
这里选择安装Ubuntu 18.04 LTS(当然,版本可以自己选择适用的)
启动ubuntu
安装完成后,即可在开始菜单启动该ubuntu子系统。该子系统纯命令模式,大伙可以在编译过程中顺便熟悉下linux的命令,哈哈~
编译准备
先安装和下载需要的文件,并配置好环境
创建ffmpeg文件夹(非必须)
只是为了将所有资源整合到一起,统一管理,可以忽略该流程
下载ffmpeg
下载ndk
安装jdk并解压ndk
为什么需要这么繁琐,还要安装jdk呢?本来打算安装unzip用于解压ndk的,但是由于文件过大,unzip解压会失败,最后选择使用jar进行解压
- sudo apt-get install default-jdk
- jar xvf android.zip
安装vim
主要用于编辑编译脚本,当然也可以使用其他的文本编辑器进行
- sudo apt-get install vim
编译
调整configure文件,修改生成生成以lib为前缀,.so为后缀的so库
这里可以使用vim进行修改。vim的查找快捷键为:先按ESC键,然后再 / , 输入需要搜索的关键字
修改前:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
修改后:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'
编写编译脚本:android_build.sh
#!/bin/bash
NDK_DIR=/home/king/ffmpeg/android-ndk-r16b
SYSROOT=${NDK_DIR}/platforms/android-19/arch-arm/
TOOLCHAIN=${NDK_DIR}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function android_build
{
./configure \
--prefix=$PREFIX \
--disable-doc \
--enable-shared \
--disable-static \
--disable-symver \
--enable-gpl \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver
--cross-prefix=${TOOLCHAIN}/bin/arm-linux-androideabi- \
--target-os=android \
--arch=arm \
--enable-cross-compile \
--sysroot=${SYSROOT} \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
CPU=armv7-a
PREFIX=./android/$CPU
ADDI_CFLAGS="-marm"
android_build
给编译脚本增加权限
- sudo chmod -R 777 android_build.sh
开始编译
- ./android_build.sh
完成
编译完成后,会在当前目录/android/armv7-a/目录下看到生成的so库
so库的使用
使用新版的android studio可以很方便的给现有项目增加c++,直接在对应的module右键,选择Add C++ to Module,即可生成需要的文件。这里不使用这种便捷方式,而是使用最原始的流程,一步一步的构建整个流程。
创建FFmpegUtil类并声明本地方法
public class FFmpegUtil {
static {
System.loadLibrary("ffmpegdemo");
}
//JNI
public native String avformatinfo();
public native String avcodecinfo();
public native String protocols();
public native String bsf();
}
使用javac编译源文件FFmpegUtil.java,生成FFmpegUtil.class
执行javac FFmpegUtil.java即可(该步骤在所在源文件目录执行)
使用javah -jni生成C头文件
javah用法:
javah [options] <classes>
其中, [options] 包括:
-o <file> 输出文件 (只能使用 -d 或 -o 之一)
-d <dir> 输出目录
-v -verbose 启用详细输出
-h --help -? 输出此消息
-version 输出版本信息
-jni 生成 JNI 样式的标头文件 (默认值)
-force 始终写入输出文件
-classpath <path> 从中加载类的路径
-cp <path> 从中加载类的路径
-bootclasspath <path> 从中加载引导类的路径
<classes> 是使用其全限定名称指定的
(例如, java.lang.Object)。
根据说明,执行的命令应该为:
javah -jni com.example.ffmpegdemo.FFmpegUtil
这里有一点需要注意的是,执行目录不是在FFmpegUtil.class所在的路径,而应该是在app\src\main\java\路径下
执行成功后,可以在该目录下看到生成了com_example_ffmpegdemo_FFmpegUtil.h文件
用C代码或CPP代码写函数原型的实现
- 在app\src\main\下增加cpp文件夹
- 创建可以在该目录下看到生成了com_example_ffmpegdemo_FFmpegUtil.cpp文件,实现具体的函数
添加ffmpeg so库的引用
- 在app\路径下添加libs文件夹
- 将几个平台的so库添加到libs目录下
- 将相应的头文件添加到libs目录下,统一放在include下
- 在module的build.gradle配置相关信息
android {
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
abiFilters "armeabi-v7a"
}
}
ndk {
//我们只有armeabi-v7a就只配置这个就行了
abiFilters 'armeabi-v7a'
}
}
}
编写CMakeLists.txt文件
CMake文件的编写,官方有详细的教程:配置CMake。主要工作就是配置引用的so库和相应的头文件等消息,具体内容可看demo。
在module的build.gradle配置CMakeLists.txt
android {
...
externalNativeBuild {
cmake {
// 要注意相对路径,我这里直接放在app\路径下
path file('CMakeLists.txt')
}
}
}
使用
基本配置完成,可以正常的在module中使用FFmpegUtil提供的native方法啦~上图两张:
总结
总的流程下来,主要包含两方面:
- 如何不安装虚拟机编译新版ffmpeg的so库
- 如何使用编译出来的so库,即一般ndk的开发流程 当然,就像上边提及的,android studio对于ndk开发支持越来越好,也越来越简便。那为什么上边没有使用简便的方法呢?有时候你需要自己一步一步进行开发才能理解ADT在背后为我们做了哪些事情,假如脱离ADT我们可以怎么去完成相应的事情。
最后附上demo地址:gitee-demo