You need to enable JavaScript to run this app.
导航
基础功能
最近更新时间:2025.04.01 19:44:20首次发布时间:2025.04.01 19:44:20
我的收藏
有用
有用
无用
无用

本文为您介绍如何实现 HarmonyOS NEXT 播放器 SDK 的基础功能。

播放回调

订阅与取消

/**
  * 订阅播放回调,每次调用 SDK 内部会创建新的 IPlayEventObserver 并返回,
  * 同一次播放可订阅多次,使用完需要解除订阅。
  * @param dataSource, 设置的播放源
  * @param observerName, Observer命名标识,标记所在业务场景,方便后续异常定位
  * @returns
  */
subscribeObserverByPlayRequest(dataSource: DataSource, observerName: string): IPlayEventObserver

/**
  * 取消订阅,确保与订阅方法逻辑对称。
  * @param vid,对应播放源的 vid
  * @param playEventObserver,需要解除订阅的 IPlayEventObserver
  */
unsubscribeObserver(vid:string, playEventObserver: IPlayEventObserver)

回调事件

export interface IPlayEventObserver {
    
  /**
   * 首帧回调
   */
  onRenderFirstFrame(callback: Callback<string | undefined>): IPlayEventObserver
  
  /**
   * prepare 完成回调
   */
  onPrepared(callback: Callback<string | undefined>): IPlayEventObserver

  /**
   * 开始播放回调
   */
  onPlaying(callback: Callback<string | undefined>): IPlayEventObserver

  /**
   * 调用暂停后回调
   */
  onPaused(callback: Callback<string | undefined>): IPlayEventObserver

  /**
   * 调用 stop 后回调
   */
  onStopped(callback: Callback<string | undefined>): IPlayEventObserver

  /**
   * 播放至结尾回调,不论用户是否开启loop,播放至结尾均触发回调
   */
  onPlayEnd(callback: Callback<string | undefined>): IPlayEventObserver

  /**
   * 出现卡顿回调
   * @param start 为 true 开始卡顿;start 为 false 卡顿结束。
   */
  onBuffering(callback: (sourceID: string | undefined, start: boolean) => void): IPlayEventObserver

  /**
   * 播放器已经缓存的可播放进度
   * @param percent 百分比
   */
  onBufferingPercent(callback: (sourceID: string | undefined, percent: number) => void): IPlayEventObserver

  /**
   * 播放进度变化回调,默认间隔 1s 上报,因用户操作(seek)产生的时间变化会立刻上报
   * @param currentDuration 当前播放进度,单位 ms
   */
  onTimeChange(callback: (sourceID: string | undefined, currentDuration: number) => void): IPlayEventObserver

  /**
   * seek 完成回调
   * @param seekDoneTime seek 到的位置,单位 ms。
   * 精准位置需要通过 onTimeChange 获取,seek 回调的 time 仅代表完成用户某一次请求。
   */
  onSeekDone(callback: (sourceID: string | undefined, seekDoneTime: number) => void): IPlayEventObserver
  
  /**
   * 播放错误回调
   * @param error 错误信息,error.code 为错误码
   */
  onError(callback: (sourceID: string | undefined, error: BusinessError) => void): IPlayEventObserver
  
  /**
   * 获取到 VideoModel 回调
   * @param videoModel,播放使用的 VideoModel
   */
  onFetchVideoModel(callback: (sourceID: string | undefined, videoModel: VideoModel) => void): IPlayEventObserver
  
  /**
   * 视频宽高变化回调,仅系统播放器回调
   * @param width 视频宽
   * @param height 视频高
   */
  onVideoSizeChange(callback: (sourceID: string | undefined, width: number, height: number) => void): IPlayEventObserver
}

示例代码

// 订阅回调
this.playEventObserver = this.simPlayer
.subscribeObserverByPlayRequest(this.dataSource, 'FeedItemView')
  .onPrepared((sourceID) => {
  })
  .onPaused((sourceID) => {
  })
  .onPlaying((sourceID) => {
  })
  .onBuffering((sourceID, start) => {
  })
  .onTimeChange((sourceID, currentDuration) => {
  })
  .onBufferingPercent((sourceID, percent) => {
  })
  .onError((sourceID, error) => {
  })
  
// 结束播放时,取消订阅
this.simPlayer.unsubscribeObserver(this.dataSource.getVid(), this.playEventObserver)

播放控制

暂停与恢复播放

// 暂停播放
this.simPlayer.pause(this.dataSource.getVid())

// 恢复播放
this.simPlayer.resume(this.dataSource.getVid())

Seek 到指定位置播放

// 演示 seek 到 1 秒的位置
this.simPlayer.seek(1000);

从指定时间起播

this.simPlayer.play(playRequest,
  PlayOptions.create()
     // 单位为毫秒,以下示例表示从 1 秒处起播
    .setInitialStartTimeMs(1000);

倍速播放

// 默认值为 1。支持取值:0.5, 1, 1.5, 2, 2.5, 3
this.simPlayer.setSpeed(2)

循环播放

// 循环播放默认关闭
this.simPlayer.play(playRequest,
  PlayOptions.create()
    .setLoop(true));

播放器静音

// 静音
this.simPlayer.setVolume(0);

// 取消静音
this.simPlayer.setVolume(1);

获取视频时长

// 单位为毫秒
let duration =  this.simPlayer.getDuration()

开启视频硬解

this.simPlayer.play(dataSource,
  PlayOptions.create()
    .setEnableHardwareDecode(true));

设置多清晰度

在 Vid 模式下播放视频时,视频点播服务会根据配置下发一个或多个清晰度的播放地址。播放器触发 onFetchVideoModel 回调后,您可调用 getVideoList 方法获取包含所有清晰度信息的数组,基于该数组实现清晰度列表的展示和清晰度切换逻辑。

设置起播清晰度

构造 Vid 播放源时,若指定起播分辨率,则采用该分辨率;否则,使用清晰度列表的首个分辨率。若指定分辨率不存在,则采用最接近的分辨率。

let dataSource =  new VidSource(videoDetail.vid, videoDetail.playAuthToken, Resolution.resolution_360p)
this.simPlayer.play(dataSource);

获取清晰度列表

播放器触发 onFetchVideoModel 回调后,调用 getVideoList 方法获取包含所有清晰度信息的数组。

.onFetchVideoModel((sourceID, videoModel) => {
    let videoList = this.simPlayer.getVideoList();
    for (let videoInfo of videoList) {
      // 清晰度字段,见下面清晰度枚举
      console.info("definition is" + videoInfo.definition)
    }
})

播放中切换清晰度

获取清晰度列表后,传入要切换清晰度在列表中的 index。

this.simPlayer.switchVideo(index);

清晰度枚举

Resolution 枚举如下表所示:

key

视频清晰度

resolution_360p

360p

resolution_480p

480p

resolution_540p

540p

resolution_720p

720p

resolution_1080p

1080p

resolution_2k

2k

resolution_4k

4k

常见问题

如何处理 License 相关错误?

当 License 过期或其他错误发生时,播放器会报错 -30001,无法正常使用。此时建议切换至鸿蒙系统播放器进行播放。系统播放器效果较差,因此建议及时更新 License,避免过期。

监听 License 错误

this.playEventObserver = this.simPlayer.subscribeObserverByPlayRequest(this.dataSource, 'FeedItemView')
  .onError((sourceID, error) => {
      // license 校验失败
      if (error.codec == TTPlayerErrorCode.LICENSE_FAIL) {
      }
  })

方案 1:使用播放器 SDK 封装的系统播放器

VodEnv.addLicenseFile(this.license)

.....
// addLicenseFile 后,检查 license,如不可用设置使用系统播放器播放。
if (!VodEnv.isLicenseAvailable()) {
  VodEnv.setUseOwnPlayer(false)
}

使用系统播放器时,视频拉伸变形铺满视图。您需根据视频宽高比自行调整 SimVideoView 宽高。

build() {
  Stack() {
    // 构造视图控件并传入播放器和播放源
    SimVideoView({
      playRequest: this.dataSource,
      simPlayer: this.simPlayer,
    })
      .width(this.playerWidth + 'px')
      .height(this.playerHeight + 'px')
  }
  .width('100%')
  .height('100%')
}

this.playEventObserver = this.simPlayer.subscribeObserverByPlayRequest(this.dataSource, 'FeedItemView')
.onVideoSizeChange((sourceID, width, height) => {
    // 获取屏幕宽高比
    let displaySc = display.getDefaultDisplaySync().width / display.getDefaultDisplaySync().height
    // 获取视频宽高比
    let videoSc = width / height;
    if (videoSc > displaySc) {
      // 视图宽填满屏幕,高等比例适配留黑边
      this.playerWidth = display.getDefaultDisplaySync().width;
      this.playerHeight = this.playerWidth * height / width;
    } else {
      // 视图高填满屏幕,宽等比例适配留黑边
      this.playerHeight = display.getDefaultDisplaySync().height;
      this.playerWidth = this.playerHeight * width / height;
    }
})

方案 2:自行封装鸿蒙系统播放器

VodEnv.addLicenseFile(this.license)

.....
// addLicenseFile 后,检查 license,如不可用,使用自己封装的系统播放器。
if (!VodEnv.isLicenseAvailable()) {
  // 接入方自行封装鸿蒙系统播放器
}

详见以下鸿蒙官方文档: