博主的上一篇文章《ffmpeg的介绍,编译与使用》
一,前期基础知识储备
1. ijkplayer 官方项目地址:https://github.com/Bilibili/ijkplayer
ijkplayer 是一个基于 ffmpeg 的轻量级 Android/iOS 视频播放器。实现了跨平台功能,API易于集成;编译配置可裁剪,方便控制安装包大小;支持硬件加速解码,更加省电。可以通过编译来实现更多格式的支持,可以说只要是 ffmpeg 支持的格式 ijkplayer 就支持。
2. Ubuntu 下载地址:https://cn.ubuntu.com/
官方中文名“友帮拓”,也有班图、乌班图、乌斑兔、乌帮图、笨兔等非官方译名。
Ubuntu是一个以桌面应用为主的Linux操作系统,是世界上最流行的Linux系统之一。
1)虚拟机下体验:
运行虚拟机,在虚拟机中获得更完整的体验。下载安装虚拟机。成功安装后运行虚拟机,选择菜单栏中的“管理”→“导入虚拟电脑”选项,将所下载体验镜像导入虚拟机,最后运行Ubuntu虚拟机,这样就可以获得比较真实的体验。在虚拟机中几乎可以完成所有操作,没有限制。
小白菜Windows10系统安装Linux(ubuntu)虚拟机超详细教程
本文,选择这一种方式在Windows10系统中安装Ubutntu。
2)制作Live USB
还有一-种获得真实体验的途径,即制作LiveUSB,它比虚拟机更进一步,直接跑在真实的硬件环境中,更快且更加节省资源。
二,上手编译
具体步骤如下:
1. 配置环境 (windows)
1)安装 VMware 虚拟机并安装 Ubuntu 系统;
2)下载NDK SDK,上传至Ubuntu;
3) 配置好NDK SDK环境变量;
4) 安装git、yasm 和 make;
2. 正式编译 - 参考 ijkplayer 中编译 Android的步骤 Build Android
3. 项目中使用编译好的so库
1. 配置环境
1)安装 VMware 虚拟机并安装 Ubuntu 系统
小白菜Windows10系统安装Linux(ubuntu)虚拟机超详细教程
2)下载NDK SDK,上传至Ubuntu
下载好 Linux 版本的的 Android SDK 和 NDK,这里选择的分别是 android-sdk_r24.4.1-linux.tgz 和 android-ndk-r10e-linux-x86_64.zip,下载后可以使用如下命令解压文件:
tar -xvf android-sdk_r24.4.1-linux.tar
unzip android-ndk-r10e-linux-x86_64.zip
切记不要将 NDK 目录放在虚拟机的共享目录下,为保证编译顺利进行应将 NDK 目录放在 Ubuntu 的系统目录,也就是 /home/用户名 下面的目录。
3) 配置好NDK SDK环境变量
在 Ubuntu 下的 /home/用户名/ ,按 Ctrl+h 查看 .bashrc 文件并配置 SDK 和 NDK 环境变量,参考如下:
NDK=/home/chinstyle/android/android-ndk-r10e
export NDK
ADB=/home/chinstyle/android/android-sdk-linux/platform-tools
export ADB
# ANDROID_NDK和ANDROID_SDK路径
ANDROID_NDK=/home/chinstyle/android/android-ndk-r10e
export ANDROID_NDK
ANDROID_SDK=/home/chinstyle/android/android-sdk-linux
export ANDROID_SDK
# 加入到PATH路径
PATH=${PATH}:${NDK}:${ADB}:${ANDROID_NDK}:${ANDROID_SDK}
配置完成后保存并关闭 .bashrc,打开 Terminal 输入 ndk-build -v 查看 ndk 是否配置成功,运行日志如下则配置成功:
Ctrl + Alt + T - 打开终端。
若是提示 ndk -build 权限不够,则需要给权限,建议给整个ndk文件夹权限。
chmod -R 777 文件夹
参数-R是递归的意思
777表示开放所有权限
4) 安装git、yasm 和 make
sudo apt-get update
sudo apt install git
sudo apt install yasm
sudo apt install make
使用 git --version 和 make -v 查看 git 和 make 工具是否安装成功,成功则显示对应版本号,参考如下:
chinstyle@chinstyle-virtual-machine:~$ git --version
git version 2.25.1
chinstyle@chinstyle-virtual-machine:~$ make -v
GNU Make 4.2.1
为 x86_64-pc-linux-gnu 编译
Copyright (C) 1988-2016 Free Software Foundation, Inc.
许可证:GPLv3+:GNU 通用公共许可证第 3 版或更新版本<http://gnu.org/licenses/gpl.html>。
本软件是自由软件:您可以自由修改和重新发布它。
在法律允许的范围内没有其他保证。
2. 正式编译
参考 ijkplayer 中编译 Android的步骤 Build Android
//clone ijkplayer源码
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer
cd ijkplayer
git checkout -B latest k0.8.8
//使用更轻量的module-lite.sh
cd ijkplayer/config
rm module.sh
ln -s module-lite module.sh
//下载ffmpeg源码 - 耗时较长
cd ijkplayer
./init-android.sh
//编译arm64 ffmpeg
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh arm64 // 若是使用all 则编译所有架构的so
//编译ijkplayer,生成arm64 so文件
cd ijkplayer/android
./compile-ijk.sh arm64 // 若是使用all 则编译所有架构的so
提几点注意事项:
1)git checkout -B latest k0.8.8 - 要切换到此分支,要不然后续使用C++方法会缺失;
2)ln -s module-lite module.sh - ijkplayer 提供了3个版本的编译脚本配置
module-default.sh:默认,如果你喜欢更多类型可以用这个;
module-lite-hevc.sh:如果您更喜欢较小的二进制大小的编解码器/格式(包括hevc功能)
module-lite.sh:如果您更喜欢较小的二进制大小的编解码器/格式(默认情况下)
区别:lite.sh相当于在default.sh的基础上,关闭了所有的解码器等全体操作,然后按照需求,比如开启对应的解码器。具体可以打开编译脚本查看。你可以打开module.sh自行进行修改。
3)compile-ffmpeg.sh arm64 & compile-ijk.sh arm64 :这里只编译arm64位的so库,这样编译时间短点。若是需要编译所有架构的so,则把arm64换成all就行了。
编译时间较长,需要耐心等待。
4)编译结果 - 生成对应的so库
编译的ijkplayer 项目整体如下:
3. 使用编译好的so库
1)添加ijkplayer依赖
//ijkplayer player
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
//ijkplayer so文件
implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
这是直接使用ijkplayer提供的依赖,可以直接使用。
我们这里选择使用自己刚刚编译好的so。把“ijkplayer-java” 和 “ijkplayer-arm64” 2个项目全部拷贝至我们的项目中,以项目依赖的方式直接使用。
setting.gradle
include ':app', 'ijkplayer-arm64','ijkplayer-java'
build.gradle
// implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
// implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
api project(path: ':ijkplayer-arm64')
api project(path: ':ijkplayer-java')
2)播放raw/assets下的音乐文件
// 播放raw下的音乐
public void onIjkPlayRaw(View view) {
//实例化播放内核
tv.danmaku.ijk.media.player.IjkMediaPlayer ijkPlayer = new tv.danmaku.ijk.media.player.IjkMediaPlayer();
//获得播放源访问入口
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.ynew); // 注意这里的区别
//构建IjkPlayer能识别的IMediaDataSource,下面的RawDataSourceProvider实现了IMediaDataSource接口
RawDataSourceProvider sourceProvider = new RawDataSourceProvider(afd);
//给IjkPlayer设置播放源
ijkPlayer.setDataSource(sourceProvider);
//设置准备就绪状态监听
ijkPlayer .setOnPreparedListener((IMediaPlayer.OnPreparedListener) mp -> {
// 开始播放
ijkPlayer.start();
});
//准备播放
ijkPlayer.prepareAsync();
}
// 播放assets下的音乐
public void onIjkPlayAsset(View view) {
tv.danmaku.ijk.media.player.IjkMediaPlayer ijkPlayer = new tv.danmaku.ijk.media.player.IjkMediaPlayer();
AssetManager am = getAssets();
try {
AssetFileDescriptor afd = am.openFd("intput.aac");
RawDataSourceProvider sourceProvider = new RawDataSourceProvider(afd);
ijkPlayer.setDataSource(sourceProvider);
} catch (IOException e) {
e.printStackTrace();
}
ijkPlayer .setOnPreparedListener((IMediaPlayer.OnPreparedListener) mp -> {
ijkPlayer.start();
});
ijkPlayer.prepareAsync();
}
// ijkplayer播放本地文件的入口
public class RawDataSourceProvider implements IMediaDataSource {
private AssetFileDescriptor mDescriptor;
private byte[] mMediaBytes;
public RawDataSourceProvider(AssetFileDescriptor descriptor) {
this.mDescriptor = descriptor;
}
@Override
public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
if(position + 1 >= mMediaBytes.length){
return -1;
}
int length;
if(position + size < mMediaBytes.length){
length = size;
}else{
length = (int) (mMediaBytes.length - position);
if(length > buffer.length)
length = buffer.length ;
length--;
}
System.arraycopy(mMediaBytes, (int) position, buffer, offset, length);
return length;
}
@Override
public long getSize() throws IOException {
long length = mDescriptor.getLength();
if(mMediaBytes == null){
InputStream inputStream = mDescriptor.createInputStream();
mMediaBytes = readBytes(inputStream);
}
return length;
}
@Override
public void close() throws IOException {
if(mDescriptor != null)
mDescriptor.close();
mDescriptor = null;
mMediaBytes = null;
}
private byte[] readBytes(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteBuffer.write(buffer, 0, len);
}
return byteBuffer.toByteArray();
}
public static RawDataSourceProvider create(Context context, Uri uri){
try {
AssetFileDescriptor fileDescriptor = context.getContentResolver().openAssetFileDescriptor(uri, "r");
return new RawDataSourceProvider(fileDescriptor);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
至此,我们编译ijkplayer就完成了。
参考文章