编译ijkplayer

01.准备工作

下载

从github上下载源码,同时github上有完整的编译流程,可以看下。

安装Homebrew

简称brew。OSX上的软件包管理系统,简单来说,就是可以方便地安装、卸载和管理软件,软件包管理在类Unix系统上可是一件非常恶心的事情。
在命令行中敲入下面的命令,安装Homebrew,命令语句原汁原味,不需要修改:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

中间过程可能需要按下enter键或者输下密码,照提示做就是了,很简单的安装过程,成功后有明显的提示。如果安装失败了,请自行google/baidu,这里不探讨Homebrew相关知识。

安装git

git是啥就不用多说了,这个应该很多人都已经装过了,如果装过了就不需要再安装。利用刚才安装的Homebrew,在命令行中敲入下面的命令,安装git:

brew install git

安装yasm

貌似是一个汇编器,编译用的,总之装上就对了。利用刚才安装的Homebrew,在命令行中敲入下面的命令,安装yasm:

brew install yasm

环境变量配置

在~/.bash_profile文件中加入下面两行:

export ANDROID_SDK=[your sdk path]
export ANDROID_NDK=[your ndk path]

保存并退出.bash_profile,在命令行中输入source .bash_profile使配置生效,有时需要关闭终端才会生效。

02.编译

初始化

将ijkplayer根目录置为工作目录,执行以下命令:
1、从远程仓库clone ffmpeg到extra/ffmpeg,并以extra/ffmpeg为引用,clone到5个cpu架构对应的目录中,以armv7q为例,路径为android/contrib/ffmpeg-armv7a;
2、制作config/module-lite.sh的替身config/module.sh,该文件中配置了ffmpeg编译的配置项;
3、从远程仓库clone libyuv到extra/libyuv,并以extra/libyuv为引用,clone到ijkmedia/ijkyuv中。
综上,该脚本主要工作是从远程仓库下载ffmpeg和libyuv源码到本地。

./init-android.sh

这个脚本可以做下修改,只保留一份原始ffmpeg源码,这样当去修改源码的时候不会出现需要同步到其他5份的情况,同理,只保留一份libyuv。

编译ffmpeg

将工作目录切换到android/contrib,依次执行以下命令(必须切换,否则后续脚本运行会有问题):

清除之前编译好的ffmpeg库。

./compile-ffmpeg.sh clean

编译所有cpu架构的ffmpeg库(armv5、armv7a、arm64、x86、x86_64),其它参数参见附件的脚本。
实际的编译脚本是android/contrib/tools/do-compile-ffmpeg.sh。
以armv7a为例,结果输出到android/contrib/build/ffmpeg-armv7a/output,包含头文件、静态库和动态库。

./compile-ffmpeg.sh all

编译ijkplayer

将ijkplayer/android置为工作目录,执行下面命令:

编译ijkplayer动态库,这里的参数all和compile-ffmpeg.sh中的效果是一样的,其它参数的使用参考compile-ffmpeg.sh。
项目中预置了5个cpu架构对应的源码在android/ijkplayer目录下,以armv7a为例,位于android/ijkplayer/ijkplayer-armv7a,我们需要编译的mk文件和源文件位于上述目录的src/main/jni目录下,里面除了Application.mk是每个cpu架构对应独立的一份外,其它文件基本都是链接自ijkmedia目录下的文件。
该过程编译了以下几个库:
1、编译libandroid-ndk-profiler.a,输出到lib下
2、将之前编译生成的libijkffmpeg.so拷贝到lib下
3、编译ijkj4a静态库libijkj4a.a,编译libyuv静态库libyuv-static.a,输出到lib下
4、依赖libijkffmpeg.so、libijkj4a.a、libyuv-static.a、libcpufeatures.a(外部链接库)编译libijksdl.so,输出到lib下
5、依赖libijkffmpeg.so、libijksdl.so、libandroid-ndk-profiler.a,编译libijkplayer.so,输出到lib下
最终输出了libijkffmpeg.so、libijksdl.so、libijkplayer.so三个动态库

./compile-ijk.sh all

至此,我们的所有编译工作就完成了,在这里我有稍微省略了几个步骤,如果编译途中碰到错误,最好照着github上面的步骤一步步做下来。进入ijkplayer/android/ijkplayer目录,这里面的所有东西就是我们编译后的产出,也是后续项目中会使用到的库文件和源文件。

在这里插入图片描述
在这里插入图片描述

集成ijkplayer

下载下来的ijkplayer源码工程是不能直接集成到项目中使用的,需要先编译,然后集成编译后生成的子工程,该子工程位于[ijkplayer根目录]/android/ijkplayer。
在主工程中使用import module将ijkplayer作为module导入主工程,路径指向前面所说的ijkplayer编译后的子工程。导入后会发现不止一个module,而是有好几个module,最显眼的是一个abi对应一个module。这和我们平常的工程结构差异挺大的,通常我们是将所有需要的abi库都集中放到libs中。ijkplayer这样做的好处是,可以通过在gradle文件中指定需要编译的module来筛选需要的abi,挺有意思。
如果你看不惯他这种目录结构,也可以将你需要的so库挪到ijkplayer-java的libs目录下,然后删除所有abi对应的module。
编译一下,如果成功就没有问题,如果失败了,根据提示解决问题。

常见编译失败问题

提示compileSdkVersion有问题
ijkplayer使用了gradle的全局配置,在每个module的gradle文件中都可以看到如下代码

android {
    compileSdkVersion rootProject.ext.compileSdkVersion
    buildToolsVersion rootProject.ext.buildToolsVersion
}

解决方法有两个:

  1. 在根目录下的gradle文件中加入ext全局变量,并为每个出现过的ext参数定义。
  2. 将所有全局变量改成常量。

提示tools/gradle-on-demand.gradle找不到

tools目录就在之前编译完成的ijkplayer目录下,也就是和所有module在同个目录下,导入module的时候可能这个目录没有导进来,手动copy到工程目录下即可。

03. 我的实践

编译出来之后,我通过导入项目的方式把下面的项目导入到了Androidstudio,设置了sdk之后,编译,可以看到官方Demo了:中间切了网络。
在这里插入图片描述
在这里插入图片描述
按照博客的说法,这里面的很多cpu类型的代码都是可以删除掉的。在我们制作自己的aar包的时候,可以去掉。

我们看一下这个项目的结构:
在这里插入图片描述
编译IJKPlayer开源项目的so文件库走过的路
https://www.jianshu.com/p/2c1413486b01
这个是别人的实践,直接拷贝源码也是一种方法。

04. 为什么要编译?

交叉编译的概念和为什么要交叉编译这里就不细说了,感兴趣的可以去查资料。因为官方提供的远程maven依赖在交叉编译的时候可能提供的功能有限,比如不支持某些音视频编解码格式,所以需要我们自己可定制的去交叉编译自己需要的版本出来,为了功能的扩展或者是为了包体积的考虑等等。
这里就有个栗子,必须得编译一个自己版本的ijk:
编译IJKPlayer开源项目的so文件库走过的路
https://www.jianshu.com/p/2c1413486b01

05. 参考资料:

ijkplayer编译so库真没那么难
https://blog.csdn.net/coder_pig/article/details/79134625

什么是交叉编译,为什么要使用交叉编译?
https://blog.csdn.net/caoshangpa/article/details/79076813

Android CPU架构及so库兼容问题总结
https://blog.csdn.net/u010052279/article/details/81393143

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐