Skip to content

快速上手

本指南将带你从零开始,在 OpenHarmony 应用中集成 Lwlplayer 播放器内核。你将学会如何配置环境、绑定渲染窗口以及实现多路视频流的平滑切换。

引入依赖

在你的 ArkTS 页面中引入 NAPI 动态库及回调接口定义:

typescript
import lwlPlayerNapi, { DGHttpPlayerCallback, DGStreamPlayerCallback } from 'liblwlplayer.so';

核心组件开发

实现渲染控制器

Lwlplayer 使用 XComponent 容器进行底层 Surface 渲染。你需要继承 XComponentController 并重写生命周期方法,将底层的 surfaceId 传递给 NAPI。

typescript
class DgPlayerXComponentController extends XComponentController {
  private isMain: boolean = true

  /**
   * @param isMain 是否为主显示窗口(主窗口支持更多渲染优化)
   */
  constructor(isMain: boolean) {
    super()
    this.isMain = isMain
  }

  onSurfaceCreated(surfaceId: string): void {
    // 关键步骤:绑定 SurfaceId
    lwlPlayerNapi.RendererSetSurfaceId(BigInt(surfaceId), this.isMain)
  }

  onSurfaceChanged(surfaceId: string, rect: SurfaceRect): void {
    // 响应窗口尺寸变化
    lwlPlayerNapi.RendererChangeSurface(BigInt(surfaceId), rect.surfaceWidth, rect.surfaceHeight)
  }

  onSurfaceDestroyed(surfaceId: string): void {
    // 销毁渲染表面
    lwlPlayerNapi.RendererDestroySurface(BigInt(surfaceId))
  }
}

完整业务逻辑示例

以下代码展示了如何在组件生命周期中管理播放器资源,并实现 RTMP 与 HTTP 播放器的切换逻辑。

typescript
@Component
export struct LwlPlayerDemo {
  // 播放地址配置
  @State videoUrl: string = "rtmp://your_live_stream_url"
  @State videoUrlList: string[] = ["http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4"]
  
  // 播放器实例索引 (ptr)
  @State rtmpPtr: number = -1
  @State httpPtr: number = -1

  // 实例化控制器
  mainController = new DgPlayerXComponentController(true); 

  // 1. 生命周期:组件初始化
  aboutToAppear(): void {
    // 初始化全局渲染引擎
    lwlPlayerNapi.InitRenderer()
    
    // 创建播放器实例
    this.rtmpPtr = lwlPlayerNapi.InitStreamPlayer()
    this.httpPtr = lwlPlayerNapi.InitFilePlayer(1) // 1 表示 HTTP 网络类型
    
    // 配置初始音视频源(默认指向 RTMP)
    lwlPlayerNapi.RendererSetSource(this.rtmpPtr);
    lwlPlayerNapi.InitAudioDevice(this.rtmpPtr);
    lwlPlayerNapi.AudioSetSource(this.rtmpPtr);
    
    // 设置状态回调
    lwlPlayerNapi.setCallback(this.rtmpPtr, {
      onStatusChange: (s, m) => console.log(`Status: ${s}, Msg: ${m}`),
      frameSize: (w, h) => lwlPlayerNapi.RendererUpdateFrame(w, h)
    });
  }

  // 2. 生命周期:资源销毁(防止内存泄漏及下次初始化失败)
  aboutToDisappear(): void {
    lwlPlayerNapi.DestroyAudio()
    lwlPlayerNapi.StreamPlayerClose(this.rtmpPtr)
    lwlPlayerNapi.DestroyStreamPlayer(this.rtmpPtr)
    lwlPlayerNapi.DestroyFilePlayer(this.httpPtr)
    lwlPlayerNapi.DestroyRenderer()
  }

  build() {
    Column() {
      // 视频渲染容器
      XComponent({
        id: "LwlVideoNode",
        type: XComponentType.SURFACE,
        controller: this.mainController
      })
      .width("100%")
      .aspectRatio(16 / 9)
      .onLoad(() => {
        // 容器准备就绪后开启直播流
        lwlPlayerNapi.StreamPlayerOpen(this.rtmpPtr, this.videoUrl)
      })

      // 操作按钮
      Row({ space: 10 }) {
        Button("切换至 HTTP 视频").onClick(() => {
          this.switchToHttp()
        })
        
        Button("录制推流").onClick(() => {
          lwlPlayerNapi.AudioRecording() // 开启音频采集
          lwlPlayerNapi.StreamPlayerRecord(this.rtmpPtr, "rtmp://push_url", 1)
        })
      }.margin(20)
    }
  }

  // 播放器切换核心逻辑
  private switchToHttp() {
    // 1. 停止当前 RTMP 播放与音频
    lwlPlayerNapi.StreamPlayerClose(this.rtmpPtr)
    lwlPlayerNapi.AudioStop()
    
    // 2. 重定向渲染源与音频源到 HTTP 实例
    lwlPlayerNapi.RendererSetSource(this.httpPtr)
    lwlPlayerNapi.AudioSetSource(this.httpPtr)
    
    // 3. 启动 HTTP 播放器并添加文件
    lwlPlayerNapi.FilePlayerOpen(this.httpPtr)
    lwlPlayerNapi.FilePlayerAddFile(this.httpPtr, this.videoUrlList[0], 0, 0)
  }
}

关键技术特性说明

多路渲染机制

Lwlplayer 内部支持最多 3 路 XComponent 同步渲染:

  • 主窗口 (Main):享有最高的渲染优先级,适合全屏播放。调用 RendererSetSurfaceId 时第二个参数传入 true
  • 副窗口 (Sub):适合预览、画中画(PIP)等场景。传入 false。系统会自动处理多路 Surface 的分发。

音画同步 (AV Sync)

由于项目基于 OHAudio 驱动,在进行播放器实例切换(例如从直播切换到点播)时,必须严格执行 “停止旧源 -> 切换 Source 指针 -> 开启新源” 的顺序,否则可能导致底层音频上下文冲突。

录制与实时推流

  • 接口StreamPlayerRecord(ptr, url, action)
  • 功能:支持将当前播放器正在渲染的内容实时编码并推送到远程服务器。
  • 采集:配合 AudioRecording() 接口可开启 OHAudio 原始数据采集,实现完美的音视频同步推流。

性能提示

在多路渲染场景下,建议根据硬件性能合理控制视频分辨率,避免因 FFmpeg 多路解码导致系统 CPU 负载过高。

基于 Apache License 2.0 协议发行