【ijkplayer】引入Android项目(基于k0.8.8)
编译准备
git(Mac自带)、yasm(brew install yasm)、Android sdk(Android studio 默认)、ndk(r14b)、并配置环境变量
ndk 环境变量
(android-ndk-r14b)
export ANDROID_SDK=/Users/inke219223m/Library/Android/sdk/platform-tools
export ANDROID_NDK=/Volumes/Victory/dev/android-ndk-r14b
export PATH=$PATH:$ANDROID_SDK
export PATH=$PATH:$ANDROID_NDK
## mac环境需要配置下面亮项
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-linux-perf"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bzlib"
M1 芯片配置ndk-build
#!/bin/sh
# 原来的注释掉
#DIR="$(cd "$(dirname "$0")" && pwd)"
#$DIR/build/ndk-build "$@"
# M1 build
DIR="$(cd "$(dirname "$0")" && pwd)"
arch -x86_64 /bin/bash $DIR/build/ndk-build "$@"
ijk 项目下载和拉取 fmpeg 代码
# clone项目
git clone https://github.com/Bilibili/ijkplayer.git
# 进入ijkplayer-android目录
cd ijkplayer
# 切换到最新代码分支
git checkout -B latest k0.8.8
# 会检查下载ffmpeg代码
./init-android.sh
#初始化openSSL(使ijk编译后支持https)
./init-android-openssl.sh
编译前选择你的配置
官方库说明中提供了三种配置支持,每个sh脚本里有对应的配置信息,包含支持编码格式、流媒体协议类型等,如下截取一些decoders,enable标识支持该格式,disable则标识不支持。
支持解码格式
./configure --list-decoders
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-decoders"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac_latm"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flv"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=h264"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp3*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp6f"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=flac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=hevc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp8"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=vp9"
选择配置文件,ln -s 命令标识软连接,module.sh可以直接获取module-default.sh的配置
#If you prefer more codec/format
cd config
rm module.sh
ln -s module-default.sh module.sh
#If you prefer less codec/format for smaller binary size (include hevc function)
cd config
rm module.sh
ln -s module-lite-hevc.sh module.sh
#If you prefer less codec/format for smaller binary size (by default)
cd config
rm module.sh
ln -s module-lite.sh module.sh
编译
本次编译的是 Android 项目,所以先 cd 到 android/contrib 下 执行清除命令,然后编译对于的 so 库,all 标识编译所有架构的 so,想编译 armv7a 架构则将 all 替换成 armv7a
./compile-openssl.sh clean #清除
./compile-ffmpeg.sh clean #清除
./compile-openssl.sh all #编译
./compile-ffmpeg.sh all #编译

生成 ijkplayer 对应架构 so 文件(all 同上输入对应架构则生成对应架构动态链接库),动态链接库生成路径如下图所示(路径示例:ijkplayer-android/android/ijkplayer/ijkplayer-armv7a/src/main/libs/armeabi-v7a)
注意本步骤需要同意不受信任软件权限,具体参考地址
# 注意回到android 路径下
cd ..
# 执行脚步生成so 文件
./compile-ijk.sh all
到此 ijkplayer 编译完成,如果播放器之前逻辑已经写好,则直接替换项目中对应的动态链接库文件就行

使用
项目导入
首先新建一个 ijkplayerdemo 工程, 将文件夹的文件 ijkplayer/android/ijkplayer 目录下的 tool 初始化工程脚本 gradle 文件复制到刚新穿件的项目根目录,然后在根项目的 build.gradle 中加入统一版本 ext 配置,相当于一个 map,方便导入 library 统一引入配置。
ext {
compileSdkVersion = 30
buildToolsVersion = "30.0.0"
targetSdkVersion = 30
versionCode = 800800
versionName = "0.8.8"
}
导入 ijkplayer-example
-这个项目,他本身是一个可运行的项目,并且依赖前面编译好的各个版本动态链接库 library,将其变为library
则修改该模块 build.gradle 将 apply plugin: ‘com.android.application’ 改为 apply plugin: ‘com.android.library’。
ijkplayer-example 的清单文件还设置了启动的 Activity过滤器,将其删除
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
各个CPU架构动态链接库 library 合并,简化项目依赖
CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
# 指定 cmake 的最小版本
cmake_minimum_required(VERSION 3.10.2)
# 打印日志
message("当前CMake的路径是:${CMAKE_SOURCE_DIR}")
message("当前 CMAKE_ANDROID_ARCH_ABI 的路径是:${CMAKE_ANDROID_ARCH_ABI}")
# Log目录设置
IF (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Windows")
ADD_DEFINITIONS(-DWindows)
ELSE (${CMAKE_HOST_SYSTEM_NAME} MATCHES "Linux")
ADD_DEFINITIONS(-DLinux)
ENDIF ()
# Declares and names the project.
# 设置项目名称
project("mediaandroid")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 批量引入源文件
file(GLOB allCpp *.cpp)
aux_source_directory( src SRC_LIST )
include_directories( ${CMAKE_SOURCE_DIR}/inc )
# 加入cpp源文件
add_library( # Sets the name of the library.
mediaandroid
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
#native-lib.cpp # 替换 ${allCpp} 批量导入文件
${allCpp}
${SRC_LIST}
)
# 导入静态库
add_library(test_a STATIC IMPORTED)
# 开始真正的导入
set_target_properties(test_a PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libtest.a)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
# 只能找系统的
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
message("当前的log路径在哪里啊 >>>>>>>>>>>>>>>>> ${log-lib}")
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
#开始链接指定的库
target_link_libraries( # Specifies the target library.
mediaandroid
android
GLESv3
# Links the target library to the log library
# included in the NDK.
${log-lib}
)
处理依赖报错
ijkplayer-example依赖的包版本比较低,应该更改为我们对于版本support包,需要将ijkplayer-example的一些报错的类正确导包,和ijkplayer-java中一样,在ijkplayer-example目录下新建gradle.properties 文件并加入项目配置
POM_NAME=ijkplayer-example
POM_ARTIFACT_ID=ijkplayer-example
POM_PACKAGING=aar
ijkplayer-example 的 build.gardle 中productFlavors 配置删除
坑还是比较多的,不要着急,谷歌还是都能帮忙解决,注意关键字摄取,搞定完就能运行展示了,源码还需自己去理解。
将ijkplayer-example依赖到主项目工程
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//第三方
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
//导入子模块
implementation project(path: ':ijkplayer-example')
编译通过项目结构
测试播放
package cn.com.codingce.mediaandroid.activity.ijk;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.widget.EditText;
import android.widget.TableLayout;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import cn.com.codingce.mediaandroid.R;
import tv.danmaku.ijk.media.example.application.Settings;
import tv.danmaku.ijk.media.example.widget.media.AndroidMediaController;
import tv.danmaku.ijk.media.example.widget.media.IjkVideoView;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
/**
* 使用 ijkplayer demo 提供的 IjkVideoView
*
* @author 24607
*/
public class IjkPlayer extends AppCompatActivity {
private static final String TAG = "IjkPlayerActivity";
String mVideoPath1 = "https://www.apple.com/105/media/us/iphone-x/2017/01df5b43-28e4-4848-bf20-490c34a926a7/films/feature/iphone-x-feature-tpl-cc-us-20170912_1920x1080h.mp4";
private Settings settings;
private AndroidMediaController mAndroidMediaController;
IjkVideoView mVideoView;
EditText editVideoPath;
AppCompatButton btplay;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ijk_player);
settings = new Settings(this);
mAndroidMediaController = new AndroidMediaController(this, false);
IjkMediaPlayer.loadLibrariesOnce(null);
IjkMediaPlayer.native_profileBegin("libijkplayer.so");
mVideoView = findViewById(R.id.mVideoView);
mVideoView.setMediaController(mAndroidMediaController);
TableLayout videoMsg = new TableLayout(this);
mVideoView.setHudView(videoMsg);
editVideoPath = findViewById(R.id.editVideoPath);
editVideoPath.setText(mVideoPath1);
btplay = findViewById(R.id.btplay);
btplay.setOnClickListener(view -> {
if (TextUtils.isEmpty(editVideoPath.getText())) {
Toast.makeText(this, "视频地址不能为空", Toast.LENGTH_LONG).show();
} else {
mVideoView.setVideoURI(Uri.parse(editVideoPath.getText().toString().trim()));
mVideoView.start();
}
});
}
@Override
protected void onDestroy() {
try {
super.onDestroy();
mVideoView.stopPlayback();
mVideoView.release(true);
mVideoView.stopBackgroundPlay();
IjkMediaPlayer.native_profileEnd();
} catch (Exception e) {
Log.e(TAG, "onDestroy Exception" + e.getMessage());
}
}
}