# ijkplayer
## 简介
> ijkplayer是OpenHarmony环境下可用的一款基于FFmpeg的视频播放器。
## 演示
<img src="screenshot/ijkplayer-zh.gif" width="100%"/>
## 编译运行
1、通过IDE工具下载依赖SDK,Tools->SDK Manager->OpenHarmony SDK 把native选项勾上下载,API版本>=9
2、开发板选择RK3568,[ROM下载地址](http://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist). 选择开发板类型是rk3568,请使用最新的版本
3、使用git clone下载源码,不要直接通过gitee网页的方式下载
## 下载安装
```shell
ohpm install @ohos/ijkplayer
```
## 使用说明
```
import { IjkMediaPlayer } from "@ohos/ijkplayer";
import type { OnPreparedListener } from "@ohos/ijkplayer";
import type { OnVideoSizeChangedListener } from "@ohos/ijkplayer";
import type { OnCompletionListener } from "@ohos/ijkplayer";
import type { OnBufferingUpdateListener } from "@ohos/ijkplayer";
import type { OnErrorListener } from "@ohos/ijkplayer";
import type { OnInfoListener } from "@ohos/ijkplayer";
import type { OnSeekCompleteListener } from "@ohos/ijkplayer";
import { LogUtils } from "@ohos/ijkplayer";
```
### 在UI中配置XComponent控件
```
XComponent({
id: 'xcomponentId',
type: 'surface',
libraryname: 'ijkplayer_napi'
})
.onLoad((context) => {
this.initDelayPlay(context);
})
.onDestroy(() => {
})
.width('100%')
.aspectRatio(this.aspRatio)
```
### 播放
```
let mIjkMediaPlayer = IjkMediaPlayer.getInstance();
// 设置XComponent回调的context
mIjkMediaPlayer.setContext(this.mContext);
// 设置debug模式
mIjkMediaPlayer.setDebug(true);
// 初始化配置
mIjkMediaPlayer.native_setup();
// 设置视频源
mIjkMediaPlayer.setDataSource(url);
// 设置视频源http请求头
let headers = new Map([
["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
["referer", "https://www.bilibili.com"]
]);
mIjkMediaPlayer.setDataSourceHeader(headers);
// 使用精确寻帧 例如,拖动播放后,会寻找最近的关键帧进行播放,很有可能关键帧的位置不是拖动后的位置,而是较前的位置.可以设置这个参数来解决问题
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", "1");
// 预读数据的缓冲区大小
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", "102400");
// 停止预读的最小帧数
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "min-frames", "100");
// 启动预加载
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", "1");
// 设置无缓冲,这是播放器的缓冲区,有数据就播放
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", "0");
// 跳帧处理,放CPU处理较慢时,进行跳帧处理,保证播放流程,画面和声音同步
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", "5");
// 最大缓冲cache是3s, 有时候网络波动,会突然在短时间内收到好几秒的数据
// 因此需要播放器丢包,才不会累积延时
// 这个和第三个参数packet-buffering无关。
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", "3000");
// 无限制收流
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");
// 屏幕常亮
mIjkMediaPlayer.setScreenOnWhilePlaying(true);
// 设置超时
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "10000000");
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "10000000");
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "listen_timeout", "10000000");
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "addrinfo_timeout", "10000000");
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "dns_cache_timeout", "10000000");
let mOnVideoSizeChangedListener: OnVideoSizeChangedListener = {
onVideoSizeChanged(width: number, height: number, sar_num: number, sar_den: number) {
that.aspRatio = width / height;
LogUtils.getInstance()
.LOGI("setOnVideoSizeChangedListener-->go:" + width + "," + height + "," + sar_num + "," + sar_den)
that.hideLoadIng();
}
}
mIjkMediaPlayer.setOnVideoSizeChangedListener(mOnVideoSizeChangedListener);
let mOnPreparedListener: OnPreparedListener = {
onPrepared() {
LogUtils.getInstance().LOGI("setOnPreparedListener-->go");
}
}
mIjkMediaPlayer.setOnPreparedListener(mOnPreparedListener);
let mOnCompletionListener: OnCompletionListener = {
onCompletion() {
LogUtils.getInstance().LOGI("OnCompletionListener-->go")
that.currentTime = that.stringForTime(mIjkMediaPlayer.getDuration());
that.progressValue = PROGRESS_MAX_VALUE;
that.stop();
}
}
mIjkMediaPlayer.setOnCompletionListener(mOnCompletionListener);
let mOnBufferingUpdateListener: OnBufferingUpdateListener = {
onBufferingUpdate(percent: number) {
LogUtils.getInstance().LOGI("OnBufferingUpdateListener-->go:" + percent)
}
}
mIjkMediaPlayer.setOnBufferingUpdateListener(mOnBufferingUpdateListener);
let mOnSeekCompleteListener: OnSeekCompleteListener = {
onSeekComplete() {
LogUtils.getInstance().LOGI("OnSeekCompleteListener-->go")
that.startPlayOrResumePlay();
}
}
mIjkMediaPlayer.setOnSeekCompleteListener(mOnSeekCompleteListener);
let mOnInfoListener: OnInfoListener = {
onInfo(what: number, extra: number) {
LogUtils.getInstance().LOGI("OnInfoListener-->go:" + what + "===" + extra)
}
}
mIjkMediaPlayer.setOnInfoListener(mOnInfoListener);
let mOnErrorListener: OnErrorListener = {
onError(what: number, extra: number) {
LogUtils.getInstance().LOGI("OnErrorListener-->go:" + what + "===" + extra)
that.hideLoadIng();
prompt.showToast({
message:"亲,视频播放异常,系统开小差咯"
});
}
}
mIjkMediaPlayer.setOnErrorListener(mOnErrorListener);
mIjkMediaPlayer.setMessageListener();
mIjkMediaPlayer.prepareAsync();
mIjkMediaPlayer.start();
```
### 暂停
```
mIjkMediaPlayer.pause();
```
### 停止
```
mIjkMediaPlayer.stop();
```
### 重置
```
mIjkMediaPlayer.reset();
```
### 释放
```
mIjkMediaPlayer.release();
```
### 快进、后退
```
mIjkMediaPlayer.seekTo(msec);
```
### 倍数播放
```
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", "1");
mIjkMediaPlayer.setSpeed("2f");
```
### 屏幕常亮
```
mIjkMediaPlayer.setScreenOnWhilePlaying(true);
```
### 循环播放
```
mIjkMediaPlayer.setLoopCount(true);
```
### 设置音量
```
mIjkMediaPlayer.setVolume(leftVolume, rightVolume);
```
## 接口说明
### IjkMediaPlayer.getInstance()
| 接口名 | 参数 | 返回值 | 说明 |
| ---------------------------| --------------------------- | ----------------- | ----------------------------------------- |
| setContext | context: object | void | 设置XComponent回调的context |
| setDebug | open: boolean | void | 设置日志开关 |
| native_setup | 无 | void | 初始化配置 |
| setDataSource | url: string | void | 设置视频源地址 |
| setDataSourceHeader | headers: Map<string, str