ohos_ijkplayer_fix:基于 OpenHarmony 的视频播放器项目

用户可用于在OpenHarmony环境下实现视频播放功能,支持视频源设置、播放控制、倍速播放、硬解码、视频录制等,基于FFmpeg,提供丰富的监听接口和配置选项。【此简介由AI生成】

分支7Tags32
文件最后提交记录最后更新时间
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 类定义了播放器内部统计属性常量,配合 getVideoDecodergetVideoCachedDuration 等统计诊断 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 安装即可。

编译三方依赖库

  1. FFmpeg(版本 ff4.0--ijk0.8.8--20210426--001):FFmpeg 源码 — 参考 FFmpeg-ff4.0 编译指导。编译完成后将 FFmpeg-ff4.0 文件夹改名为 ffmpeg

  2. soundtouch(版本 ijk-r0.1.2-dev):soundtouch 源码 — 将 doc/soundtouch-ijk 复制到 thirdparty 目录,在 lycium 目录执行 ./build.sh soundtouch-ijk

  3. libyuv(版本 ijk-r0.2.1-dev):libyuv 源码 — 将 doc/libyuv-ijk 复制到 thirdparty 目录,在 lycium 目录执行 ./build.sh libyuv-ijk

  4. openh264(版本 openh264-2.4.1):openh264 源码 — 参考 openh264 编译脚本,编译完成后输出至 lycium/usr/openh264

  5. ffmpeg 文件夹复制到 ijkplayer/src/main/cpp/third_party/ffmpeg

  6. openssl-3.4.0 文件夹复制到 ijkplayer/src/main/cpp/third_party,改名为 openssl,并将 x86_64/lib64 改为 x86_64/lib

  7. soundtouchyuvopenh264 文件夹复制到 ijkplayer/src/main/cpp/third_party,如下图所示:

third_party 目录结构

IDE 编译运行

  1. 使用 DevEco Studio,选择 Tools → SDK Manager → OpenHarmony SDK,勾选 native 并下载,API 版本 ≥ 9。
  2. 开发板选用 RK3568,ROM 从 OpenHarmony CI 下载最新版本。
  3. 使用 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,请自由地享受和参与开源。

项目介绍

用户可用于在OpenHarmony环境下实现视频播放功能,支持视频源设置、播放控制、倍速播放、硬解码、视频录制等,基于FFmpeg,提供丰富的监听接口和配置选项。【此简介由AI生成】

定制我的领域