用户可用于在OpenHarmony环境下实现视频播放功能,支持视频源设置、播放控制、倍速播放、硬解码、视频录制等,基于FFmpeg,提供丰富的监听接口和配置选项。【此简介由AI生成】
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 年前 | ||
| 8 个月前 | ||
| 3 个月前 | ||
| 2 年前 | ||
| 2 个月前 | ||
| 1 年前 | ||
| 3 年前 | ||
| 3 年前 | ||
| 2 年前 | ||
| 3 个月前 | ||
| 3 年前 | ||
| 3 年前 | ||
| 3 年前 | ||
| 2 年前 | ||
| 3 年前 | ||
| 3 年前 | ||
| 5 个月前 | ||
| 1 年前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 年前 | ||
| 3 年前 | ||
| 7 个月前 | ||
| 3 年前 | ||
| 3 个月前 | ||
| 3 个月前 | ||
| 1 年前 | ||
| 1 年前 |
ijkplayer
本项目基于 ijkplayer 开发。
简介
ijkplayer 是 OpenHarmony 环境下可用的一款基于 FFmpeg 的视频播放器,支持视频播放、音频播放、倍速播放、硬解码、视频录制、截屏、HLS/RTSP/RTMP 直播流等功能。
效果展示

下载安装
ohpm install @ohos/ijkplayer
OpenHarmony ohpm 环境配置等更多内容,请参考如何安装 OpenHarmony ohpm 包。
约束与限制
兼容性
在下述版本验证通过:
- DevEco Studio: NEXT Beta1-5.0.3.806, SDK: API12 Release(5.0.0.66), ROM: OpenHarmony-5.0.0.71;
- DevEco Studio NEXT 5.0(5.0.3.427), SDK: API12, ROM: OpenHarmony-5.0.0.71;
监听音频中断事件需保证设备系统版本在 API 22 及以上。
设置音量需保证 SDK 版本在 API 12 及以上。
硬解码器 buffer 模式支持 10bit 视频需要 OpenHarmony API 22 及以上版本。
权限要求
使用以下功能时需在 module.json5 中声明对应权限:
| 权限 | 说明 | 必须申请 |
|---|---|---|
ohos.permission.INTERNET |
播放网络视频流(HTTP/RTSP/HLS/RTMP 等) | 是 |
ohos.permission.WRITE_IMAGEVIDEO |
将录制视频或截图保存到相册 | 仅录制/截图功能使用时 |
// module.json5 配置示例
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:NET_REQUEST_PERMISSION"
},
{
"name": "ohos.permission.WRITE_IMAGEVIDEO",
"reason": "$string:IMAGEVIDEO_REQUEST_PERMISSION",
"usedScene": {
"when": "always"
}
}
]
使用示例
以下示例展示播放一个网络视频的最小可运行流程:导入 → 配置 XComponent → 初始化播放器 → 播放。
id:id是组件唯一标识,用户自行设置
type:使用SURFACE,目前仅支持SURFACE。
libraryname:动态库名称 ijkplayer_napi
纯音频播放可以不使用Xcomponent。
Xcomponent的具体使用可以参考官方文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-xcomponent#xcomponent10
步骤 1:在页面中配置 XComponent
import { IjkMediaPlayer, OnPreparedListener, OnErrorListener } from "@ohos/ijkplayer";
@Entry
@Component
struct VideoPage {
@State aspRatio: number = 16 / 9;
private mContext: object | undefined = undefined;
private mIjkMediaPlayer = IjkMediaPlayer.getInstance();
private videoUrl: string = "https://example.com/sample.mp4";
build() {
Column() {
// 步骤 1:将 XComponent 绑定到播放器
XComponent({
id: 'xcomponentId',
type: XComponentType.SURFACE,
libraryname: 'ijkplayer_napi'
})
.onLoad((context) => {
this.mContext = context;
this.startPlay();
})
.onDestroy(() => {
this.mIjkMediaPlayer.release();
})
.width('100%')
.aspectRatio(this.aspRatio)
}
}
startPlay(): void {
// 步骤 2:初始化播放器
this.mIjkMediaPlayer.setContext(this.mContext, 'xcomponentId');
this.mIjkMediaPlayer.native_setup();
// 步骤 3:注册回调
let onPrepared: OnPreparedListener = {
onPrepared() {
console.info("视频已就绪,开始播放");
}
};
this.mIjkMediaPlayer.setOnPreparedListener(onPrepared);
let onError: OnErrorListener = {
onError(what: number, extra: number) {
console.error(`播放异常:what=${what}, extra=${extra}`);
}
};
this.mIjkMediaPlayer.setOnErrorListener(onError);
this.mIjkMediaPlayer.setMessageListener();
// 步骤 4:设置视频源并开始加载
this.mIjkMediaPlayer.setDataSource(this.videoUrl);
this.mIjkMediaPlayer.prepareAsync();
this.mIjkMediaPlayer.start();
}
}
使用说明
目前已支持的流媒体协议:HTTP/HTTPS,RTSP,HLS,RTMP,HTTP-FLV,FILE。
播放初始化
支持单例模式和多实例模式两种方式创建播放器:
import { IjkMediaPlayer } from "@ohos/ijkplayer";
// 单例模式(全局共享同一个播放器实例)
const mIjkMediaPlayer = IjkMediaPlayer.getInstance();
// 多实例模式(每次创建独立的播放器实例)
const mIjkMediaPlayer = new IjkMediaPlayer();
播放器初始化流程如下:
// 绑定 XComponent(视频播放时必须;纯音频播放使用 setAudioId 替代)
mIjkMediaPlayer.setContext(this.mContext, "xcomponentId");
// 初始化内部配置
mIjkMediaPlayer.native_setup();
// 设置视频源
mIjkMediaPlayer.setDataSource(url);
// 可选:设置 HTTP 请求头(如需鉴权或指定 User-Agent)
const headers = new Map<string, string>([
["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
["referer", "https://www.bilibili.com"],
]);
mIjkMediaPlayer.setDataSourceHeader(headers);
// 注册各类回调后,调用以下两个接口开始加载和播放
mIjkMediaPlayer.setMessageListener();
mIjkMediaPlayer.prepareAsync();
mIjkMediaPlayer.start();
播放控制
mIjkMediaPlayer.pause(); // 暂停
mIjkMediaPlayer.start(); // 恢复播放
mIjkMediaPlayer.stop(); // 停止
mIjkMediaPlayer.reset(); // 重置(可重新 setDataSource 后再播放)
mIjkMediaPlayer.release(); // 释放资源(页面销毁时调用)
mIjkMediaPlayer.seekTo("30000"); // 跳转到指定位置,单位:毫秒
获取播放进度
通过定时轮询 getCurrentPosition() 更新进度条:
// 启动进度轮询,每 500ms 查询一次
const timer = setInterval(() => {
const currentMs: number = mIjkMediaPlayer.getCurrentPosition();
const totalMs: number = mIjkMediaPlayer.getDuration();
const progress = totalMs > 0 ? (currentMs / totalMs) * 100 : 0;
console.info(`播放进度:${currentMs}ms / ${totalMs}ms (${progress.toFixed(1)}%)`);
}, 500);
// 停止时清除轮询
clearInterval(timer);
倍速播放
// 开启倍速播放(依赖 soundtouch 库)
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "soundtouch", "1");
mIjkMediaPlayer.setSpeed("2f"); // 设置为 2 倍速
mIjkMediaPlayer.getSpeed(); // 获取当前设置的倍速值
注意:无音频数据的视频无法进行倍速播放。
音量与屏幕常亮
mIjkMediaPlayer.setVolume("1.0", "1.0"); // 设置左右声道音量,取值范围 0.0~1.0
mIjkMediaPlayer.setScreenOnWhilePlaying(true); // 播放期间保持屏幕常亮
循环播放
mIjkMediaPlayer.setLoopCount(true); // 开启循环播放
mIjkMediaPlayer.isLooping(); // 查询是否已开启循环播放
高级参数配置
通过 setOption 配置播放器行为,常用参数如下:
// 精确寻帧:拖动后跳转到指定位置而非最近关键帧
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", "1");
// 预读缓冲区大小(字节),建议 100KB
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", "102400");
// 最大缓冲时长(毫秒),防止直播流累积延迟
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max_cached_duration", "3000");
// 无限制收流(适用于直播等长连接场景)
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "infbuf", "1");
// 超时设置(微秒),适用于弱网环境
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "10000000");
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "10000000");
setOption / setOptionLong 参数参考
以下列出所有可用的 setOption / setOptionLong 参数,均需在 prepareAsync() 前设置。
OPT_CATEGORY_PLAYER("4")—— 播放器层参数
| key | 值类型 | 默认值 | 说明 |
|---|---|---|---|
enable-accurate-seek |
整数 | 0 |
精确寻帧;1=跳转到精确时间点,0=跳转到最近关键帧(更快) |
soundtouch |
整数 | 0 |
启用 soundtouch 音调处理,倍速播放时保持音调;需先于 setSpeed() 设置 |
mediacodec-all-videos |
整数 | 0 |
开启所有视频格式(H.264/H.265 等)的硬件解码 |
overlay-format |
整数 | 808596553 |
视频输出像素格式:842094158=NV12,808596553=I420 |
max-buffer-size |
整数 | 15728640 |
预读缓冲区最大字节数(byte),超出后暂停预读;常用点播建议値:102400 |
min-frames |
整数 | 50000 |
开始播放前的最少缓冲帧数;降低可减少起播延迟,升高可减少卡顿 |
max_cached_duration |
整数 | 0 |
最大缓冲时长(毫秒),超出后停止缓冲;用于控制直播流延迟,如 "3000" |
infbuf |
整数 | 0 |
无限缓冲模式,忽略 max_cached_duration 限制;适用于点播或不限延迟直播 |
packet-buffering |
整数 | 1 |
包缓冲模式;0=禁用(实时性更高),1=启用 |
framedrop |
整数 | 0 |
丢帧閘値,视频落后音频超过此値时主动丢帧;直播建议 "5";0=不丢帧 |
start-on-prepared |
整数 | 1 |
1=prepared 回调后自动开始播放;0=需手动调用 start() |
loop |
整数 | 1 |
循环次数;0=无限循环,1=不循环(通常通过 setLoopCount() 设置) |
OPT_CATEGORY_FORMAT("1")—— 格式/协议层参数
| key | 值类型 | 默认值 | 说明 |
|---|---|---|---|
timeout |
整数 | 0 |
I/O 读写超时(微秒),适用于弱网环境;10000000=10 秒 |
connect_timeout |
整数 | 0 |
TCP 建连超时(微秒) |
listen_timeout |
整数 | 0 |
RTSP/TCP 服务器监听超时(微秒) |
addrinfo_timeout |
整数 | 0 |
DNS 解析超时(微秒) |
dns_cache_timeout |
整数 | 600000000 |
DNS 缓存有效期(微秒);-1=永久缓存,0=不缓存 |
rtsp_transport |
字符串 | udp |
RTSP 传输层协议:tcp(推荐,稳定)/ udp / udp_multicast |
allowed_extensions |
字符串 | — | 允许的文件扩展名,"ALL" 表示不限制 |
fetch_first |
字符串 | — | HLS 起播延迟优化;"on"=开启 |
headers |
字符串 | — | 自定义 HTTP 请求头(通常通过 setDataSourceHeader() 设置) |
protocol_whitelist |
字符串 | — | 允许的协议白名单,多个协议用逗号分隔(通常通过 setDataSourceHeader() 设置) |
OPT_CATEGORY_CODEC("2")—— 解码器层参数
| key | 值类型 | 默认值 | 说明 |
|---|---|---|---|
skip_loop_filter |
整数 | 0 |
跳过环路滤波:0=完整过滤,48=跳过 B/P 帧(降低 CPU 占用,轻微影响画质) |
注意:
setOption用于设置字符串类型参数,setOptionLong用于设置整数类型参数(值也传入字符串,如"1")。两者均须在prepareAsync()前调用。
音频焦点监控
import { InterruptEvent, InterruptHintType } from '@ohos/ijkplayer';
import { Callback } from '@ohos.base';
const audioInterruptCallback: Callback<InterruptEvent> = (event) => {
if (event.hintType === InterruptHintType.INTERRUPT_HINT_PAUSE) {
mIjkMediaPlayer.pause();
} else if (event.hintType === InterruptHintType.INTERRUPT_HINT_RESUME) {
mIjkMediaPlayer.start();
} else if (event.hintType === InterruptHintType.INTERRUPT_HINT_STOP) {
mIjkMediaPlayer.stop();
}
};
// 订阅音频中断事件
mIjkMediaPlayer.on('audioInterrupt', audioInterruptCallback);
// 取消订阅
mIjkMediaPlayer.off('audioInterrupt');
音频设备断开和连接监控
import { InterruptEvent, DeviceChangeReason } from '@ohos/ijkplayer';
import { Callback } from '@ohos.base';
const deviceChangeCallback: Callback<InterruptEvent> = (event) => {
if (event.reason === DeviceChangeReason.REASON_NEW_DEVICE_AVAILABLE) {
// 新设备接入,继续播放
} else if (event.reason === DeviceChangeReason.REASON_OLD_DEVICE_UNAVAILABLE) {
// 设备断开,暂停播放
mIjkMediaPlayer.pause();
}
};
// 订阅设备变化事件
mIjkMediaPlayer.on('deviceChange', deviceChangeCallback);
// 取消订阅
mIjkMediaPlayer.off('deviceChange');
开启硬解码
// 开启 H.264 和 H.265 硬解码
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-all-videos", "1");
// 设置输出像素格式:NV12(842094158) 或 I420(808596553)
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", "842094158");
注意:硬解码器 buffer 模式支持 10bit 视频需要 OpenHarmony API 22 及以上版本。
自适应播放分辨率变换视频
支持自适应播放分辨率发生变换的视频,软解与硬解均可,通过既有 API 实现,无需额外接口。
import { OnVideoSizeChangedListener } from "@ohos/ijkplayer";
const sizeListener: OnVideoSizeChangedListener = {
onVideoSizeChanged(width: number, height: number, sar_num: number, sar_den: number) {
console.info(`分辨率变换:${width}x${height}, sar=${sar_num}/${sar_den}`);
// 建议同步更新 XComponent 或容器布局,避免画面拉伸
}
};
mIjkMediaPlayer.setOnVideoSizeChangedListener(sizeListener);
片源分辨率变换时 onVideoSizeChanged 会多次触发;getVideoWidth() / getVideoHeight() 返回当前生效分辨率。
轨道切换
获取媒体信息后,通过轨道索引切换音频或字幕轨道:
// 获取媒体流信息(包含音视频轨道列表)
const mediaInfo: object = mIjkMediaPlayer.getMediaInfo();
console.info(`媒体信息:${JSON.stringify(mediaInfo)}`);
// 切换到指定轨道(trackId 从 getMediaInfo 中获取)
mIjkMediaPlayer.selectTrack("1"); // 选择轨道 ID 为 1
// 取消选中当前轨道
mIjkMediaPlayer.deselectTrack("1");
视频录制
注意:保存录制视频到相册需申请
ohos.permission.WRITE_IMAGEVIDEO权限。
// 开始录制
const savePath: string = getContext(this).cacheDir + "/record.mp4";
mIjkMediaPlayer.setRecordDefaultFrameRate("30", false); // 设置默认帧率(仅在视频流帧率不可用时生效)
const started: boolean = mIjkMediaPlayer.startRecord(savePath);
// 查询录制状态
const isRecording: boolean = mIjkMediaPlayer.isRecord();
// 停止录制并保存到相册
mIjkMediaPlayer.stopRecord().then((result) => {
if (result) {
console.info("录制已停止,文件保存至:" + savePath);
}
});
截屏
注意:保存截图到相册需申请
ohos.permission.WRITE_IMAGEVIDEO权限。
const screenshotPath: string = getContext(this).cacheDir + "/screen.jpg";
mIjkMediaPlayer.screenshot(screenshotPath).then((result) => {
if (result) {
console.info("截图已保存至:" + screenshotPath);
}
});
字幕实时回调
import { OnTimedTextListener } from "@ohos/ijkplayer";
// 注册字幕回调(应在 setMessageListener 前设置)
const timedTextListener: OnTimedTextListener = {
onTimedText(text: string) {
console.info("字幕:" + text);
}
};
mIjkMediaPlayer.setOnTimedTextListener(timedTextListener);
注意:
setOnTimedTextListener需在setMessageListener()前调用。字幕回调通过MEDIA_TIMED_TEXT(值 99)事件触发。
HLS 起播优化
// 开启 HLS 起播延迟优化(默认关闭)
mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "fetch_first", "on");
异步停止与释放
// 以下异步接口适用于性能敏感场景(如快速切换视频源)
mIjkMediaPlayer.stopAsync().then((result) => {
console.info("异步停止完成");
});
mIjkMediaPlayer.releaseAsync().then((result) => {
console.info("异步释放完成");
});
接口说明
API
| 名称 | 参数 | 返回值 | 说明 |
|---|---|---|---|
| setContext | context: object, id?: string | void | 指定 XComponent 的 context 和 id(可选),播放视频时必须调用 |
| setAudioId | id: string | void | 仅播放音频时调用,指定音频对象 ID(替代 setContext) |
| setDebug | open: boolean | void | 开启或关闭调试日志 |
| native_setup | mode?: VideoCodecMode | void | 初始化配置,并指定视频解码器解码方式,默认为buffer模式,在配置播放器之前必须调用 |
| setDataSource | url: string | void | 设置视频源地址(支持 HTTP/HTTPS/RTSP/RTMP/HLS) |
| setDataSourceHeader | headers: Map<string, string> | void | 设置视频源的 HTTP 请求头 |
| setOption | category: string, key: string, value: string | void | 设置字符串类型播放参数(playback 前调用) |
| setOptionLong | category: string, key: string, value: string | void | 设置整数类型播放参数(playback 前调用) |
| prepareAsync | - | void | 异步加载视频资源 |
| start | - | void | 开始或恢复播放 |
| pause | - | void | 暂停播放 |
| stop | - | void | 停止播放 |
| stopAsync | - | Promise<boolean> | 异步停止播放 |
| reset | - | void | 重置播放器状态(可重新设置视频源) |
| release | - | void | 释放播放器资源 |
| releaseAsync | - | Promise<boolean> | 异步释放资源 |
| seekTo | msec: string | void | 跳转到指定位置,单位:毫秒 |
| isPlaying | - | boolean | 返回是否正在播放 |
| getDuration | - | number | 返回视频总时长,单位:毫秒 |
| getCurrentPosition | - | number | 返回当前播放位置,单位:毫秒 |
| getVideoWidth | - | number | 返回视频宽度,单位:像素 |
| getVideoHeight | - | number | 返回视频高度,单位:像素 |
| getVideoSarNum | - | number | 返回视频宽高比的分子 |
| getVideoSarDen | - | number | 返回视频宽高比的分母 |
| getAudioSessionId | - | number | 返回音频 session ID |
| setSpeed | speed: string | void | 设置倍速,如 "1f"、"2f"(需先开启 soundtouch 选项) |
| getSpeed | - | number | 返回当前设置的倍速值 |
| setVolume | leftVolume: string, rightVolume: string | void | 设置左右声道音量;SDK API 12 及以上版本生效 |
| setScreenOnWhilePlaying | on: boolean | void | 设置播放期间是否保持屏幕常亮 |
| setLoopCount | looping: boolean | void | 设置是否循环播放 |
| isLooping | - | boolean | 返回是否开启了循环播放 |
| selectTrack | track: string | void | 切换至指定轨道 |
| deselectTrack | track: string | void | 取消指定轨道的选中状态 |
| getMediaInfo | - | object | 返回媒体流信息(含音视频轨道列表) |
| setMessageListener | - | void | 将事件监听器注册到 native 层,注册回调前必须调用 |
| setOnPreparedListener | listener: OnPreparedListener | void | 视频加载就绪时触发 |
| setOnVideoSizeChangedListener | listener: OnVideoSizeChangedListener | void | 视频宽高信息可用时触发 |
| setOnCompletionListener | listener: OnCompletionListener | void | 播放完成时触发 |
| setOnInfoListener | listener: OnInfoListener | void | 播放器内部状态变更时触发(详见下方 OnInfoListener 回调值说明) |
| setOnErrorListener | listener: OnErrorListener | void | 播放异常时触发 |
| setOnBufferingUpdateListener | listener: OnBufferingUpdateListener | void | 缓冲进度更新时触发,percent 为缓冲百分比 |
| setOnSeekCompleteListener | listener: OnSeekCompleteListener | void | seek 操作完成时触发 |
| setOnTimedTextListener | listener: OnTimedTextListener | void | 字幕文本时间戳事件触发时回调,onTimedText(text: string) 参数为字幕内容 |
| on | type: 'audioInterrupt', callback: Callback<InterruptEvent> | void | 订阅音频中断事件;需 API 22 及以上 |
| on | type: 'deviceChange', callback: Callback<InterruptEvent> | void | 订阅音频设备断开/接入事件 |
| off | type: 'audioInterrupt' | void | 取消订阅音频中断事件 |
| off | type: 'deviceChange' | void | 取消订阅音频设备变化事件 |
| setRecordDefaultFrameRate | frameRate: string, isPriority: boolean | boolean | 设置录制默认帧率;isPriority 为 true 时仅在流帧率缺失时生效 |
| startRecord | saveFilePath: string | boolean | 开始录制,返回是否成功 |
| isRecord | - | boolean | 返回是否正在录制 |
| stopRecord | - | Promise<boolean> | 异步停止录制,返回是否成功 |
| screenshot | saveFilePath: string | Promise<boolean> | 异步截取当前帧并保存至指定路径 |
| getVideoDecoder | - | number | 返回当前视频解码器类型;1=软解(AVCodec),2=硬解(MediaCodec) |
| getVideoOutputFramesPerSecond | - | number | 返回视频实际输出帧率(fps) |
| getVideoDecodeFramesPerSecond | - | number | 返回视频解码帧率(fps) |
| getVideoCachedDuration | - | number | 返回视频缓冲时长(毫秒) |
| getAudioCachedDuration | - | number | 返回音频缓冲时长(毫秒) |
| getVideoCachedBytes | - | number | 返回视频缓冲字节数 |
| getAudioCachedBytes | - | number | 返回音频缓冲字节数 |
| getVideoCachedPackets | - | number | 返回视频缓冲包数 |
| getAudioCachedPackets | - | number | 返回音频缓冲包数 |
| getAsyncStatisticBufBackwards | - | number | 返回异步统计回退缓冲大小 |
| getAsyncStatisticBufForwards | - | number | 返回异步统计前进缓冲大小 |
| getAsyncStatisticBufCapacity | - | number | 返回异步统计缓冲容量 |
| getTrafficStatisticByteCount | - | number | 返回累计下载流量(字节) |
| getCacheStatisticPhysicalPos | - | number | 返回缓存统计物理位置 |
| getCacheStatisticFileForwards | - | number | 返回缓存统计文件前进位置 |
| getCacheStatisticFilePos | - | number | 返回缓存统计文件位置 |
| getCacheStatisticCountBytes | - | number | 返回缓存统计字节计数 |
| getBitRate | - | number | 返回当前播放比特率(bit/s) |
| getTcpSpeed | - | number | 返回当前 TCP 下载速度(byte/s) |
| getSeekLoadDuration | - | number | 返回最近一次 seek 加载耗时(毫秒) |
| getDropFrameRate | - | number | 返回当前丢帧率 |
| getFileSize | - | number | 返回媒体文件总大小(byte);直播流返回 0 |
| setCacheShare | share: string | void | 设置缓存数据共享;"1"=开启,"0"=关闭 |
onErrorListener回调值说明
onError(what: number, extra: number) 回调中 what 取值含义如下:
| what 值 | 常量名 | 说明 |
|---|---|---|
| 1 | MEDIA_ERROR_UNKNOWN | 未知错误 |
| 100 | MEDIA_ERROR_SERVER_DIED | 服务器死亡 |
| 200 | MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK | 不支持渐进式播放 |
| -1004 | MEDIA_ERROR_IO | IO 错误 |
| -1007 | MEDIA_ERROR_MALFORMED | 格式错误 |
| -1010 | MEDIA_ERROR_UNSUPPORTED | 不支持 |
| -110 | MEDIA_ERROR_TIMED_OUT | 超时 |
| -10000 | MEDIA_ERROR_IJK_PLAYER | 播放器错误 |
OnInfoListener 回调值说明
onInfo(what: number, extra: number) 回调中 what 取值含义如下:
| what 值 | 常量名 | 说明 |
|---|---|---|
| 3 | MEDIA_INFO_VIDEO_RENDERING_START | 视频开始渲染 |
| 701 | MEDIA_INFO_BUFFERING_START | 开始缓冲 |
| 702 | MEDIA_INFO_BUFFERING_END | 缓冲结束 |
| 10001 | MEDIA_INFO_VIDEO_ROTATION_CHANGED | 视频旋转角度已改变(extra = 旋转角度,单位:度) |
| 10002 | MEDIA_INFO_AUDIO_RENDERING_START | 音频开始渲染 |
| 10003 | MEDIA_INFO_AUDIO_DECODED_START | 音频开始解码 |
| 10004 | MEDIA_INFO_VIDEO_DECODED_START | 视频开始解码 |
| 10005 | MEDIA_INFO_OPEN_INPUT | 开始打开输入源(开始建立或读取媒体输入) |
| 10006 | MEDIA_INFO_FIND_STREAM_INFO | 已发现并解析流信息(流媒体的轨道/编码信息可用) |
| 10007 | MEDIA_INFO_COMPONENT_OPEN | 解码/渲染组件已打开(如解码器或渲染器初始化完成) |
| 10008 | MEDIA_INFO_VIDEO_SEEK_RENDERING_START | seek 后开始渲染视频 |
| 10009 | MEDIA_INFO_AUDIO_SEEK_RENDERING_START | seek 后开始渲染音频 |
| 10100 | MEDIA_INFO_MEDIA_ACCURATE_SEEK_COMPLETE | 精确 seek 完成(extra/arg 包含seek位置) |
InterruptEvent 参数说明
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| forceType | InterruptForceType | 是 | 打断操作由系统执行(INTERRUPT_FORCE)或由应用处理(INTERRUPT_SHARE) |
| hintType | InterruptHint | 是 | 中断类型提示,详见下方枚举表 |
| reason | DeviceChangeReason | 否 | 设备变化原因,仅 deviceChange 事件包含此字段 |
InterruptForceType 枚举
| 名称 | 值 | 说明 |
|---|---|---|
| INTERRUPT_FORCE | 0 | 由系统强制执行打断操作 |
| INTERRUPT_SHARE | 1 | 由应用决定是否响应打断 |
InterruptHint 枚举
| 名称 | 值 | 说明 |
|---|---|---|
| INTERRUPT_HINT_NONE | 0 | 无提示 |
| INTERRUPT_HINT_RESUME | 1 | 提示恢复播放 |
| INTERRUPT_HINT_PAUSE | 2 | 提示暂停播放 |
| INTERRUPT_HINT_STOP | 3 | 提示停止播放 |
| INTERRUPT_HINT_DUCK | 4 | 提示降低音量(不停止) |
| INTERRUPT_HINT_UNDUCK | 5 | 提示恢复正常音量 |
DeviceChangeReason枚举
| 名称 | 值 | 说明 |
|---|---|---|
| REASON_UNKNOWN | 0 | 未知原因 |
| REASON_NEW_DEVICE_AVAILABLE | 1 | 新设备可用 |
| REASON_OLD_DEVICE_UNAVAILABLE | 2 | 旧设备不可用,应用应考虑暂停播放 |
| REASON_OVERRODE | 3 | 设备被用户或系统覆盖 |
VideoCodecMode 枚举
| 名称 | 值 | 说明 |
|---|---|---|
| BUFFER | 0 | 视频解码器使用buffer模式解码 |
| SURFACE | 1 | 视频解码器使用surface模式解码 |
OnTimedTextListener 回调说明
onTimedText(text: string) 在播放含字幕轨道的视频时触发,text 为字幕内容字符串。
MessageType 常量说明
MessageType 类定义了播放器内部消息类型,可通过 setMessageListener 回调中的 what 参数匹配,也可通过导入直接引用。
import { MessageType } from "@ohos/ijkplayer";
| 常量名 | 值 | 说明 |
|---|---|---|
MEDIA_PREPARED |
1 |
视频已加载就绪 |
MEDIA_PLAYBACK_COMPLETE |
2 |
播放完成 |
MEDIA_BUFFERING_UPDATE |
3 |
缓冲进度更新 |
MEDIA_SEEK_COMPLETE |
4 |
seek 完成 |
MEDIA_SET_VIDEO_SIZE |
5 |
视频宽高信息已获取 |
MEDIA_TIMED_TEXT |
99 |
字幕文本时间戳事件 |
MEDIA_ERROR |
100 |
播放异常 |
MEDIA_INFO |
200 |
播放器内部信息事件 |
MEDIA_AUDIO_INTERRUPT |
201 |
音频中断事件 |
MEDIA_AUDIO_DEVICE_CHANGE |
202 |
音频设备变化事件 |
MEDIA_SET_VIDEO_SAR |
10001 |
视频宽高比参数已更新 |
PropertiesType 统计属性常量
PropertiesType 类定义了播放器内部统计属性常量,配合 getVideoDecoder、getVideoCachedDuration 等统计诊断 API 的返回值使用,也可直接通过底层属性接口查询。
import { PropertiesType } from "@ohos/ijkplayer";
浮点属性常量
| 常量名 | 值 | 说明 |
|---|---|---|
PROP_FLOAT_VIDEO_DECODE_FRAMES_PER_SECOND |
"10001" |
视频解码帧率 |
PROP_FLOAT_VIDEO_OUTPUT_FRAMES_PER_SECOND |
"10002" |
视频输出帧率 |
FFP_PROP_FLOAT_PLAYBACK_RATE |
"10003" |
播放倍速(setSpeed / getSpeed 内部使用) |
FFP_PROP_FLOAT_DROP_FRAME_RATE |
"10007" |
丢帧率 |
解码器类型常量(配合 getVideoDecoder() 返回值使用)
| 常量名 | 值 | 说明 |
|---|---|---|
FFP_PROPV_DECODER_UNKNOWN |
"0" |
未知解码器 |
FFP_PROPV_DECODER_AVCODEC |
"1" |
软件解码(FFmpeg AVCodec) |
FFP_PROPV_DECODER_MEDIACODEC |
"2" |
硬件解码(MediaCodec) |
缓存统计属性常量(整数属性)
| 常量名 | 值 | 说明 |
|---|---|---|
FFP_PROP_INT64_VIDEO_CACHED_DURATION |
"20005" |
视频缓冲时长(毫秒) |
FFP_PROP_INT64_AUDIO_CACHED_DURATION |
"20006" |
音频缓冲时长(毫秒) |
FFP_PROP_INT64_VIDEO_CACHED_BYTES |
"20007" |
视频缓冲字节数 |
FFP_PROP_INT64_AUDIO_CACHED_BYTES |
"20008" |
音频缓冲字节数 |
FFP_PROP_INT64_VIDEO_CACHED_PACKETS |
"20009" |
视频缓冲包数 |
FFP_PROP_INT64_AUDIO_CACHED_PACKETS |
"20010" |
音频缓冲包数 |
FFP_PROP_INT64_BIT_RATE |
"20100" |
当前比特率(bit/s) |
FFP_PROP_INT64_TCP_SPEED |
"20200" |
TCP 下载速度(byte/s) |
FFP_PROP_INT64_LATEST_SEEK_LOAD_DURATION |
"20300" |
最近一次 seek 加载耗时(毫秒) |
FFP_PROP_INT64_TRAFFIC_STATISTIC_BYTE_COUNT |
"20204" |
累计下载流量(byte) |
FFP_PROP_INT64_LOGICAL_FILE_SIZE |
"20209" |
媒体文件总大小(byte) |
FFP_PROP_INT64_SHARE_CACHE_DATA |
"20210" |
缓存数据共享开关(setCacheShare 内部使用) |
关于混淆
- 代码混淆,请查看代码混淆简介
- 如需在代码混淆过程中排除 ijkplayer 库,请在
obfuscation-rules.txt中添加以下规则:
-keep
./oh_modules/@ohos/ijkplayer
注意事项
状态管理(必读):使用 ijkplayer 时,必须为播放器实例添加完整的生命周期状态管理,否则会出现资源泄漏或 crash。请参考 Demo 中 IjkplayerMapManager 的实现。
跨页面使用:在多页面场景(如列表页与详情页共用播放器)中,需在页面跳转时正确传递和恢复 XComponent 绑定,避免播放黑屏。参考 Navigation 场景示例 和 非 Navigation 场景示例。
多实例回调独立性:使用
new IjkMediaPlayer()创建多实例时,每个实例的回调是独立的,确保对每个实例分别调用setOnXxxListener,避免回调被覆盖。
屏幕旋转黑屏:屏幕旋转导致 XComponent 重建时,需在
onLoad回调中重新调用setContext,并根据当前播放状态恢复播放。
自适应播放分辨率变换视频:片源分辨率变换时
onVideoSizeChanged会多次触发,需同步更新 XComponent 或容器布局,避免画面拉伸或黑边。参考 IjkVideoDynamicResolutionPage.ets。
手动切换视频分辨率:ijkplayer 播放器仅支持视频播放时自适应分辨率变化。业务上的手动切换分辨率需在码流源端(如摄像头修改编码参数)单独实现,播放器不提供推流或编码参数配置能力。
源码编译
以下步骤仅适用于需要从源码编译的开发者,普通用户通过
ohpm install @ohos/ijkplayer安装即可。
编译三方依赖库
-
FFmpeg(版本 ff4.0--ijk0.8.8--20210426--001):FFmpeg 源码 — 参考 FFmpeg-ff4.0 编译指导。编译完成后将
FFmpeg-ff4.0文件夹改名为ffmpeg。 -
soundtouch(版本 ijk-r0.1.2-dev):soundtouch 源码 — 将
doc/soundtouch-ijk复制到thirdparty目录,在lycium目录执行./build.sh soundtouch-ijk。 -
libyuv(版本 ijk-r0.2.1-dev):libyuv 源码 — 将
doc/libyuv-ijk复制到thirdparty目录,在lycium目录执行./build.sh libyuv-ijk。 -
openh264(版本 openh264-2.4.1):openh264 源码 — 参考 openh264 编译脚本,编译完成后输出至
lycium/usr/openh264。 -
将
ffmpeg文件夹复制到ijkplayer/src/main/cpp/third_party/ffmpeg。 -
将
openssl-3.4.0文件夹复制到ijkplayer/src/main/cpp/third_party,改名为openssl,并将x86_64/lib64改为x86_64/lib。 -
将
soundtouch、yuv、openh264文件夹复制到ijkplayer/src/main/cpp/third_party,如下图所示:

IDE 编译运行
- 使用 DevEco Studio,选择 Tools → SDK Manager → OpenHarmony SDK,勾选 native 并下载,API 版本 ≥ 9。
- 开发板选用 RK3568,ROM 从 OpenHarmony CI 下载最新版本。
- 使用
git clone下载源码,不要直接从网页下载压缩包。
目录结构
|---- ohos_ijkplayer
| |---- entry/ # 示例代码
| |---- ijkplayer/ # ijkplayer 库
| |---- cpp/ # Native 模块
| |---- ijkplayer/ # ijkplayer 核心业务
| |---- ijksdl/ # ijkplayer SDL 适配层
| |---- napi/ # NAPI 接口封装
| |---- proxy/ # 代理层(衔接 NAPI 与 ijkplayer)
| |---- third_party/ # 三方库依赖(ffmpeg/yuv/soundtouch/openh264)
| |---- utils/ # 工具类
| |---- ets/ # ArkTS 接口模块
| |---- callback/ # 播放器回调接口定义
| |---- common/ # 常量与枚举(MessageType、PropertiesType)
| |---- utils/ # 工具类(LogUtils)
| |---- IjkMediaPlayer.ets # 对外暴露的核心 API
| |---- index.ets # 库入口,导出所有公开 API
| |---- README.md # 英文文档
| |---- README_zh.md # 中文文档
贡献代码
使用过程中发现任何问题,欢迎提 Issue 或发 PR 共建。
开源协议
本项目基于 LGPLv2.1 or later,请自由地享受和参与开源。