快速上手
本指南将带你从零开始,在 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 负载过高。
