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

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

自定义预加载

预加载是指在开始播放之前提前下载即将播放视频的头部数据,实现快速起播,提升播放体验。预加载实现成本低,效果显著,适用于各种播放场景。更多介绍,请见预加载规则说明

注意

该功能仅高级版支持。请确保您已购买高级版的 License,详见播放器 License

DirectUrl 模式

  1. 添加预加载任务:预加载与播放使用相同的数据源结构。为保证播放能命中预加载缓存,需确保构造预加载数据源与构造播放数据源时使用的 vidurlcacheKey 一致。示例代码如下:

    // 构造播放源
    let videoInfo = new VideoInfo();
    videoInfo.urls = [url]
    videoInfo.fileHash = fileHash
    
    let dataSource = new VideoModel();
    dataSource.videoInfos = [videoInfo];
    dataSource.vid = vid;
    
    let preloadSize = 800 * 1024; // 预加载大小 800K   
    let startPreloadOffset = 0;   // 预加载的起始位置
    // 构造预加载实例
    let preloadModel = new PreloadVideoModel(dataSource, startPreloadOffset, preloadSize, 
          (type: PreloadTaskEventType, info: string, extraInfo: string) => {
        switch (type) {
          case PreloadTaskEventType.Success:  // 预加载成功
          case PreloadTaskEventType.Failed:   // 预加载失败
          case PreloadTaskEventType.Cancel:   // 预加载取消
            break;
        }
     })
    // 开始预加载
    preloadModel.create();
    
  2. 取消预加载任务:取消未执行和正在下载的任务,已完成的任务不受影响。

    // 取消预加载任务
    preloadModel.cancel();
    

Vid 模式

  1. 添加预加载任务:预加载与播放使用相同的播放源结构。为保证播放能命中预加载缓存,需确保预加载与播放构造的播放源 vidplayAuthTokenresolution 一致。

    let vid = "your vid"; // appServer 下发
    let playAuthToken = "your video id's play auth token"; // appServer 下发
    let source = new VidSource(vid, playAuthToken)
    // 设置分辨率,如不设置起播分辨率,则使用清晰度列表里的第一个起播
    // let source = new VidSource(vid, playAuthToken, Resolution.resolution_360p)
    
    let preloadSize = 800 * 1024; // 预加载大小 800K   
    let startPreloadOffset = 0;   // 预加载的起始位置
    let preloadVid = new PreloadVid(source, startPreloadOffset, preloadSize,
        (type: PreloadTaskEventType, info: string, extraInfo: string) => {
          switch (type) {
              case PreloadTaskEventType.Success:  // 预加载成功
              case PreloadTaskEventType.Failed:   // 预加载失败
              case PreloadTaskEventType.Cancel:   // 预加载取消
                break;
            }
      })
    preloadVid.create();
    
  2. 取消预加载任务:取消未执行和正在下载的任务,已完成的任务不受影响。

    // 取消预加载任务
    preloadVid.cancel();
    

播放私有加密视频

视频点播私有加密方案采用火山引擎自研加密算法,安全级别高,能够便捷、高效、安全地保护您的音视频版权。更多介绍,请见火山引擎私有加密方案。播放器 SDK 支持通过 DirectUrl 模式播放私有加密视频。应用服务端从视频点播服务获取用于解密的密钥 playAuth 并下发给播放器 SDK,即可播放火山引擎私有加密视频。

// 视频源与 vid 必须一一对应
let vid = "your vid";
// 视频 url
let url = "http://www.example.com/h264.mp4";
// 播放源唯一标识,与视频源一一对应,如 url 的 MD5 
let fileHash = getMd5(url);
// 使用服务端签发的临时播放 Token
let playAuth = "l7wZ9Em+A/xxxxxxx";

// 构造播放源
let videoInfo = new VideoInfo();
videoInfo.urls = [url]
videoInfo.fileHash = fileHash
videoInfo.decryptionKey = playAuth

let dataSource = new VideoModel();
dataSource.videoInfos = [videoInfo];
dataSource.vid = vid;

// 播放
this.simPlayer.play(dataSource,
  PlayOptions.create()
    .setEnableMdl(true));

短视频场景预渲染

Feed 流页面

@Entry
@Component
export struct SmallVideoFeed {
  // 2. Feed 流数据
  private data: FeedDataSource = new FeedDataSource();
  // 3. 记录当前显示页面的 index
  @State currentIndex: number = 0

  aboutToAppear(): void {
  }

  build() {
    // 1. 使用 Swiper 实现端视频 Feed 流 
    // Swiper 官网使用说明 https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-swiper-V5
    Swiper() {
      LazyForEach(this.data, (dataSource: DataSource, index: number) => {
        TTPlayerItemView({
          dataSource: dataSource,
          index: index,
          currentIndex: this.currentIndex
        })
          .width('100%')
          .height("100%")
      }, (dataSource: DataSource) => dataSource.getVid())
    }
    .vertical(true)
    .loop(false)
    // 4. cachedCount 可根据业务需求设置
    .cachedCount(1)
    .displayCount(1)
    .width('100%')
    .height('100%')
    .indicator(false)
    .onChange((index) => {
      // 5. 页面上下滑动结束,触发此事件,更新 currentIndex。
      this.currentIndex = index
    })
  }
}

Item 播放页面

@Component
export struct TTPlayerItemView {
  // 1. 当前 View 在 feed 数组里的 index
  index: number = 0
  // 2. Feed 流页面滑动,currentIndex 更新,执行 onIndexChange
  @Watch('onIndexChange') @Prop currentIndex: number = 0
  @State dataSource: DataSource = new DataSource();
  private simPlayer?: ISimPlayer;

  aboutToAppear() {
    this.simPlayer = SimKitService.instance().createSimPlayer();
    if (this.index == 0 && this.currentIndex == 0) {
      // 3. 进入 Feed 流页面的第一个视频,直接开始播放
      this.simPlayer?.play(this.dataSource, PlayOptions.create());
    } else {
      // 4. 滑动到其他页面先进行预渲染,onIndexChange 页面切换完成时再播放
      this.simPlayer?.preRender(this.dataSource, PlayOptions.create());
    }
  }
  
  onIndexChange() {
    // 5. 页面切换完成
    if (this.index === this.currentIndex) {
      // 此 View 是要显示的页面,开始播放
      this.simPlayer?.play(this.dataSource, PlayOptions.create());
    } else {
       // 此 View 不是要显示的页面,停止播放
      this.simPlayer?.stop(this.dataSource?.getVid())
    }
  }

  aboutToDisappear() {
    // 6. 画面退出,释放播放器
    this.simPlayer?.release(this.dataSource?.getVid())
  }

  build() {
    Stack() {
      SimVideoView({
        playRequest: this.dataSource,
        simPlayer: this.simPlayer,
      })
    }
  }
}