bricks/aidocs/videoplayer.md
2025-10-05 06:39:58 +08:00

398 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `bricks.VideoPlayer` 与 `bricks.Iptv` 技术文档
---
## 概述
本文档介绍基于 `bricks` 框架实现的两个核心类:
- **`bricks.VideoPlayer`**一个功能完整的自定义视频播放器组件支持多种视频格式MP4、HLS `.m3u8`、DASH `.mpd`),并提供播放控制、音量调节、倍速播放、音轨切换和全屏等功能。
- **`bricks.Iptv`**:一个用于 IPTV 频道播放的高级组件,集成 `VideoPlayer`,可动态加载频道数据,并上报播放状态。
该组件依赖外部库:
- [hls.js](https://github.com/video-dev/hls.js) 用于播放 HLS 流(`.m3u8`
- [dash.js](https://github.com/Dash-Industry-Forum/dash.js) 用于播放 DASH 流(`.mpd`
### 外部依赖引入建议
```html
<!-- 在页面中引入 -->
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
```
---
## 1. `bricks.VideoPlayer`
### 类定义
```js
bricks.VideoPlayer = class extends bricks.VBox
```
继承自 `bricks.VBox`,表示这是一个容器型 UI 组件,内部包含视频元素及控制栏。
---
### 构造函数:`constructor(opts)`
#### 参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `opts.url` | `String` | 是 | 视频源地址,支持 `.mp4`, `.m3u8`, `.mpd` 或普通流媒体 URL |
| `opts.autoplay` | `Boolean` | 否 | 是否自动播放,默认为 `false` |
#### 示例
```js
const player = new bricks.VideoPlayer({
url: 'https://example.com/stream.m3u8',
autoplay: true
});
```
---
### DOM 结构
创建如下 HTML 结构:
```html
<div class="video-container">
<video class="video-element"></video>
<div class="controls">
<div class="progress-container">
<input type="range" class="progress-bar" value="0" step="0.0001" />
</div>
<div class="controls-bottom">
<button class="play-pause"></button>
<div class="volume-container">
<button class="mute">🔊</button>
<input type="range" class="volume" min="0" max="1" step="0.01" value="1" />
</div>
<span class="time">00:00 / 00:00</span>
<div class="speed-container">
<select class="playback-speed">
<option value="0.5">0.5x</option>
<option value="0.75">0.75x</option>
<option value="1" selected>1x</option>
<option value="1.25">1.25x</option>
<option value="1.5">1.5x</option>
<option value="2">2x</option>
</select>
</div>
<div class="audio-tracks">
<select class="audio-track-select"></select>
</div>
<button class="fullscreen"></button>
</div>
</div>
</div>
```
---
### 属性
| 属性 | 类型 | 描述 |
|------|------|------|
| `this.video` | `HTMLVideoElement` | 内部 `<video>` 元素引用 |
| `this.hls` | `Hls``null` | hls.js 实例,仅当播放 `.m3u8` 时创建 |
| `this.dashPlayer` | `dashjs.MediaPlayer``null` | dash.js 播放器实例,仅当播放 `.mpd` 时创建 |
| `this.controls` | `Element` | 控制栏 DOM 引用 |
| `this.playPauseBtn` | `Element` | 播放/暂停按钮 |
| `this.muteBtn` | `Element` | 静音按钮 |
| `this.volumeInput` | `Element` | 音量滑块 |
| `this.progressBar` | `Element` | 进度条 |
| `this.timeDisplay` | `Element` | 时间显示文本 |
| `this.speedSelect` | `Element` | 倍速选择下拉框 |
| `this.audioTrackSelect` | `Element` | 音轨选择下拉框 |
| `this.fullscreenBtn` | `Element` | 全屏按钮 |
---
### 方法
#### `init()`
初始化播放器,在 DOM 加载完成后调用。负责加载视频、绑定事件、更新 UI 并根据 `autoplay` 设置开始播放。
#### `destroy()`
销毁当前播放器实例,释放资源:
- 销毁 Hls 或 Dash 播放器
- 清空 video 的 `src`
- 防止内存泄漏
#### `loadVideo(src)`
动态加载指定视频源。
##### 支持类型:
| 格式 | 判断方式 | 使用技术 |
|------|----------|---------|
| `.m3u8` 或含 `m3u8` 字符串 | `endsWith('.m3u8') || includes('m3u8')` | `hls.js` |
| `.mpd` 或含 `mpd` 字符串 | `endsWith('.mpd') || includes('mpd')` | `dash.js` |
| 其他(如 `.mp4` | 默认情况 | 原生 `<video>` |
> ⚠️ 调用前会先执行 `destroy()`,确保旧播放器被清理。
#### `onLoaded()`
视频元信息加载完成后的回调,用于刷新 UI 和音轨列表。
#### `bindEvents()`
绑定所有用户交互事件和视频事件,包括:
| 事件目标 | 事件类型 | 功能 |
|--------|--------|------|
| `.play-pause` | `click` | 切换播放/暂停 |
| `.mute` | `click` | 切换静音 |
| `.volume` | `input` | 调节音量 |
| `.progress-bar` | `input` | 拖动进度条跳转时间 |
| `.playback-speed` | `change` | 更改播放速度 |
| `.audio-track-select` | `change` | 切换音轨 |
| `.fullscreen` | `click` | 进入/退出全屏 |
| `video` | `play/pause` | 更新播放按钮图标 |
| `video` | `timeupdate` | 更新进度条和时间显示 |
| `video` | `durationchange` | 更新总时长 |
| `video` | `volumechange` | 同步静音按钮状态 |
| `video` | `loadedmetadata` | 加载音轨信息 |
| `video` | `seeking` | 更新进度条位置 |
#### `updateUI()`
统一刷新所有控件状态。
#### `updatePlayPauseUI()`
根据播放状态更新播放按钮图标:
- 暂停 → `▶`
- 播放中 → `❚❚`
#### `updateMuteUI()`
根据是否静音或音量为 0 来更新静音按钮图标:
- 静音 → `🔇`
- 非静音 → `🔊`
#### `updateProgress()`
更新进度条和时间显示:
- 显示当前时间和总时间(格式化为 `mm:ss``hh:mm:ss`
- 进度条值为 `(currentTime / duration)`
#### `updateAudioTracks()`
`video.audioTracks` 中读取可用音轨,并填充到下拉菜单中。默认选中已启用的轨道。
若无音轨,则显示“无音轨”选项且禁用。
#### `formatTime(seconds)` → `String`
将秒数转换为可读时间字符串。
##### 示例输出:
- `65``"1:05"`
- `3665``"1:01:05"`
---
### 控制行为特性
- **自动隐藏控制栏**点击任意位置显示控制栏4 秒后自动隐藏。
- `show_controls()`:显示控制栏
- `hide_controls()`:隐藏控制栏
- **全屏切换**:兼容 Chrome/Firefox/Safari/Edge 的全屏 API。
- 图标在全屏状态下变为返回窗口图标SVG 箭头)
- **响应式设计建议**CSS 类名可用于样式定制(见下文)
---
## 2. `bricks.Iptv`
### 类定义
```js
bricks.Iptv = class extends bricks.VBox
```
专用于播放 IPTV 频道的组件,自动获取频道信息并使用 `VideoPlayer` 播放。
---
### 构造函数:`constructor(opts)`
#### 参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `iptv_data_url` | `String` | 是 | 获取频道信息的接口地址 |
| `playok_url` | `String` | 否 | 上报“播放成功”的接口 |
| `playfailed_url` | `String` | 否 | 上报“播放失败”的接口 |
> 接口应返回 JSON 数据,至少包含字段:`url`, `tv_name`, `id`
#### 示例
```js
const iptv = new bricks.Iptv({
iptv_data_url: '/api/channel?id=123',
playok_url: '/api/report/playok',
playfailed_url: '/api/report/playfailed'
});
```
---
### 属性
| 属性 | 类型 | 描述 |
|------|------|------|
| `this.user_data` | `Object` | 存储从服务器获取的频道数据 |
| `this.deviceid` | `String` | 设备唯一标识(通过 `bricks.deviceid('iptv')` 生成) |
| `this.video` | `bricks.VideoPlayer` | 内嵌的视频播放器实例 |
| `this.title_w` | `bricks.Text` | 显示频道名称的文本组件 |
---
### 方法
#### `build_subwidgets()`
异步方法,首次构建子组件:
1. 若未加载 `user_data`,则通过 HTTP 请求获取
2. 创建 `VideoPlayer` 播放器并传入 `user_data.url`
3. 添加标题和播放器到界面
4. 绑定播放成功/失败事件以进行状态上报
#### `report_play_ok()` → `Promise<void>`
播放开始后触发,向 `playok_url` 发送设备 ID 和频道 ID。
#### `report_play_failed()` → `Promise<void>`
播放出错时触发,上报失败记录。
> 注意:这两个方法仅在对应 URL 存在时才发送请求。
#### `setValue(data)`
外部更新频道的方法。可用于切换频道而不重新创建组件。
##### 参数
- `data`: 包含新频道信息的对象,结构同 `user_data`
##### 示例
```js
iptv.setValue({
id: 'cctv5',
tv_name: 'CCTV-5 体育频道',
url: 'https://live.example.com/cctv5.m3u8'
});
```
---
## 事件系统Event Binding
`bricks` 框架支持事件绑定机制:
| 自定义事件 | 触发条件 | 用途 |
|-----------|----------|------|
| `domon` | 组件挂载到 DOM 后 | 执行 `init()` 初始化 |
| `domoff` | 组件从 DOM 卸载前 | 执行 `destroy()` 回收资源 |
| `click` | 用户点击组件区域 | 显示控制栏 |
| `play_ok` | 视频开始播放(由 `VideoPlayer` 抛出) | 上报播放成功 |
| `play_failed` | 播放出错(由 `VideoPlayer` 抛出) | 上报播放失败 |
> 注:`play_ok` 和 `play_failed` 需结合业务逻辑手动抛出(当前代码中暂未体现具体抛出点,可能需进一步扩展)
---
## 注册组件Factory Registration
以下语句将组件注册至 `bricks.Factory`,便于通过配置或模板动态创建:
```js
bricks.Factory.register('Iptv', bricks.Iptv);
bricks.Factory.register('VideoPlayer', bricks.VideoPlayer);
bricks.Factory.register('Video', bricks.VideoPlayer); // 别名支持
```
这意味着你可以这样使用:
```js
bricks.Factory.create('VideoPlayer', { url: '...' });
bricks.Factory.create('Iptv', { iptv_data_url: '...' });
```
---
## CSS 类名参考(供样式开发)
| 类名 | 用途 |
|------|------|
| `.video-container` | 播放器最外层容器 |
| `.video-element` | `<video>` 元素 |
| `.controls` | 控制栏整体 |
| `.progress-container`, `.progress-bar` | 进度条容器与滑块 |
| `.controls-bottom` | 底部按钮行 |
| `.play-pause`, `.mute`, `.fullscreen` | 各功能按钮 |
| `.volume`, `.playback-speed`, `.audio-track-select` | 输入控件 |
| `.time` | 时间显示区域 |
> 建议添加 CSS 以美化外观例如半透明背景、hover 效果等。
---
## 使用示例
### 示例 1直接播放视频
```js
const player = new bricks.VideoPlayer({
url: 'https://example.com/video.mp4',
autoplay: true
});
document.body.appendChild(player.dom_element);
```
### 示例 2播放 HLS 直播流
```js
const player = new bricks.VideoPlayer({
url: 'https://live.example.com/stream.m3u8',
autoplay: true
});
container.add_widget(player);
```
### 示例 3使用 IPTV 组件
```js
const iptv = new bricks.Iptv({
iptv_data_url: '/api/get_channel?id=101',
playok_url: '/log/play_start',
playfailed_url: '/log/play_error'
});
document.getElementById('app').appendChild(iptv.dom_element);
```
---
## 已知限制与注意事项
1. **浏览器兼容性**
- HLS 播放依赖 `hls.js`,不支持 iOS Safari 原生 HLS但通常仍可回退
- DASH 需要 MSEMedia Source Extensions支持
2. **跨域问题**
- 视频源必须允许 CORS否则无法加载元数据或音轨
3. **移动端体验**
- 自动隐藏控制栏的时间40帧 ≈ 0.67秒)可能偏短,建议调整
- 移动端建议禁用鼠标 hover 行为,改为点击切换显示
4. **错误处理待完善**
- 当前未监听 `error` 事件来触发 `play_failed`,建议补充:
```js
this.video.addEventListener('error', () => {
this.fire('play_failed'); // 触发事件
});
```
- 可增加重试机制或备用源切换逻辑
5. **性能优化**
- 多次切换视频源时频繁重建播放器,可考虑缓存策略优化
---
## 总结
`bricks.VideoPlayer` 是一个轻量级、多功能、跨平台的视频播放组件,适用于点播与直播场景;
`bricks.Iptv` 在其基础上封装了频道管理和状态上报能力,适合构建智能电视或 Web 端 IPTV 应用。
两者结合可快速搭建现代化流媒体播放界面,具备良好的扩展性和维护性。
---
> ✅ 文档版本v1.0
> 📅 最后更新2025-04-05