docs: 告知草原指南1x与2x播放缓冲优化
这个提交包含在:
父节点
98740244ca
当前提交
f852024d4a
@ -0,0 +1,122 @@
|
|||||||
|
# 草原指南 4K 原片播放缓冲优化通知
|
||||||
|
|
||||||
|
> 日期:2026-07-16
|
||||||
|
>
|
||||||
|
> 前端仓库:`mmg/hl-ui`
|
||||||
|
>
|
||||||
|
> 影响页面:草原指南 H5 详情/播放页
|
||||||
|
>
|
||||||
|
> 本次后端接口、字段和 OSS 地址均无变化
|
||||||
|
|
||||||
|
## 1. 问题与诊断结论
|
||||||
|
|
||||||
|
草原指南详情直接播放后端返回的 OSS 原始 MP4。正式环境真实 4K 样本的媒体参数为:
|
||||||
|
|
||||||
|
- 文件约 `451.74 MiB`,时长约 `95` 秒。
|
||||||
|
- 分辨率 `3812 × 2160`,`60 fps`。
|
||||||
|
- H.264 Main Profile,Level `5.2`。
|
||||||
|
- 平均码率约 `40.20 Mbps`。
|
||||||
|
- `1x` 播放时短时峰值约 `72.98 Mbps`。
|
||||||
|
- `2x` 播放时平均网络消耗约 `80.40 Mbps`;短时峰值约 `142.17 Mbps`。
|
||||||
|
|
||||||
|
正式 OSS 已支持 HTTP Range,请求返回 `206 Partial Content`。同一诊断环境连续读取 OSS Range 的平均速度约 `230.52 Mbps`,高于该视频 `2x` 播放的短时峰值。因此目前没有证据表明 Java 服务或 OSS Range 能力是主要瓶颈;但该结果不代表每个用户到 OSS 的实时链路都能达到相同速度。
|
||||||
|
|
||||||
|
现已确认 `1x` 也会偶发卡顿。结合 `1x` 接近 `73 Mbps` 的短时峰值,更可能是用户链路瞬时波动与浏览器前向缓冲较浅共同造成:即使平均网速高于视频平均码率,只要短时间下载速度低于瞬时消耗速度,缓冲仍可能耗尽。因此首次 `1x` 播放和卡顿恢复也必须执行缓冲水位保护,不能只处理 `2x`。
|
||||||
|
|
||||||
|
此外,`4K 60 fps` 在 `2x` 下相当于设备需要承担接近 `120 fps` 的解码节奏。部分设备即使网络充足,也可能因硬件解码能力不足出现掉帧;前端需要把“等待网络缓冲”和“设备解码掉帧”分别记录。
|
||||||
|
|
||||||
|
## 2. 前端处理要求
|
||||||
|
|
||||||
|
### 2.1 保持原生 Range 播放
|
||||||
|
|
||||||
|
- 继续直接使用接口返回的 `videoUrl` 作为 `<video src>`。
|
||||||
|
- 设置 `preload="auto"`,允许浏览器提前加载媒体数据。
|
||||||
|
- 不要使用 `fetch`/`axios` 把完整 MP4 下载为 Blob 后再播放,避免一次性占用数百 MiB 内存并破坏原生 Range 调度。
|
||||||
|
- 不要改写 OSS 域名,不转成 HLS/M3U8,不接直播播放器。
|
||||||
|
- 本轮不降低码率、不转码、不新增清晰度档位。
|
||||||
|
|
||||||
|
### 2.2 计算真实前向缓冲
|
||||||
|
|
||||||
|
不能只读取 `video.buffered.end(video.buffered.length - 1)`。应找到包含 `currentTime` 的 buffered 区间,再计算:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function getBufferAhead(video) {
|
||||||
|
const currentTime = video.currentTime
|
||||||
|
|
||||||
|
for (let index = 0; index < video.buffered.length; index += 1) {
|
||||||
|
const start = video.buffered.start(index)
|
||||||
|
const end = video.buffered.end(index)
|
||||||
|
|
||||||
|
if (currentTime >= start && currentTime <= end) {
|
||||||
|
return Math.max(0, end - currentTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 `1x` 与倍速播放缓冲策略
|
||||||
|
|
||||||
|
- 用户首次点击 `1x` 播放时,若前向缓冲不足 `8` 秒,先显示“正在缓冲”;达到 `8` 秒后再开始播放。
|
||||||
|
- `1x` 播放过程中前向缓冲低于 `3` 秒时进入缓冲状态,恢复到 `8~10` 秒后继续播放。
|
||||||
|
- 用户选择 `2x` 时,若前向缓冲不足 `15` 秒,先保持暂停并显示“正在缓冲”,达到 `15` 秒后再以 `2x` 播放。
|
||||||
|
- `2x` 播放过程中前向缓冲低于 `5` 秒时进入缓冲状态,恢复到 `12~15` 秒后继续播放。
|
||||||
|
- 原生播放器触发 `waiting` 或 `stalled` 时,无论当前倍速是多少,都进入统一缓冲流程并按当前 `playbackRate` 对应的恢复水位继续播放。
|
||||||
|
- 用户主动暂停、拖动进度或离开页面时取消自动恢复,避免播放器违背用户操作。
|
||||||
|
- `preload="auto"` 只是浏览器提示,不能单独保证缓冲量;必须以 `video.buffered` 的实际结果作为判断依据。
|
||||||
|
|
||||||
|
阈值是针对当前约 `40 Mbps` 的 4K 原片给出的首轮参数。前端应按播放倍速集中定义为常量,便于根据真机数据调整,不要散落魔法值。
|
||||||
|
|
||||||
|
### 2.4 记录卡顿证据
|
||||||
|
|
||||||
|
至少监听并记录以下事件和状态:
|
||||||
|
|
||||||
|
- 事件:`loadstart`、`loadedmetadata`、`canplay`、`canplaythrough`、`progress`、`waiting`、`stalled`、`playing`、`seeking`、`seeked`、`error`。
|
||||||
|
- 状态:`currentTime`、`playbackRate`、前向缓冲秒数、`readyState`、`networkState`。
|
||||||
|
- 浏览器支持时记录 `getVideoPlaybackQuality()` 的 `droppedVideoFrames` 和 `totalVideoFrames`。
|
||||||
|
|
||||||
|
日志不得记录完整带签名 URL、Token 或其他凭证。建议只记录 `videoId`、事件时间和上述播放指标。
|
||||||
|
|
||||||
|
判断口径:
|
||||||
|
|
||||||
|
- 出现 `waiting`/`stalled`,同时前向缓冲接近 `0`:网络或缓冲调度不足。
|
||||||
|
- 前向缓冲充足、没有 `waiting`,但 `droppedVideoFrames` 持续上升:设备解码能力不足。
|
||||||
|
|
||||||
|
## 3. 接口契约
|
||||||
|
|
||||||
|
播放接口保持不变:
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /admin/grassland-guide/public/videos/{videoId}/play
|
||||||
|
```
|
||||||
|
|
||||||
|
前端继续使用:
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `videoId` | string | 视频业务 ID |
|
||||||
|
| `videoUrl` | string | OSS 原始 MP4 地址,直接交给原生 `<video>` |
|
||||||
|
| `durationSeconds` | integer | 后端从素材解析的时长 |
|
||||||
|
| `effectiveCoverUrl` | string | 生效封面 |
|
||||||
|
|
||||||
|
雪花 ID 必须按字符串处理。本次不增加缓冲、码率或清晰度字段,前端不得等待后端返回这些字段后才处理播放。
|
||||||
|
|
||||||
|
相关接口说明见:
|
||||||
|
|
||||||
|
- [`16_feat_grassland_guide_public_play.md`](./16_feat_grassland_guide_public_play.md)
|
||||||
|
- [`12_feat_grassland_guide_admin_mp_oss.md`](./12_feat_grassland_guide_admin_mp_oss.md)
|
||||||
|
|
||||||
|
## 4. 前端验收清单
|
||||||
|
|
||||||
|
- [ ] `<video>` 使用接口原始 `videoUrl`,并设置 `preload="auto"`。
|
||||||
|
- [ ] 没有将完整 MP4 下载为 Blob。
|
||||||
|
- [ ] 首次 `1x` 播放前按真实 `buffered` 结果预缓冲,播放中有低水位保护。
|
||||||
|
- [ ] `2x` 播放前使用更高的预缓冲与恢复水位。
|
||||||
|
- [ ] `waiting`/`stalled` 在 `1x` 和倍速播放下均进入统一缓冲恢复流程。
|
||||||
|
- [ ] 用户暂停、拖动和离开页面时不会被自动恢复播放。
|
||||||
|
- [ ] 能区分并记录缓冲耗尽与设备解码掉帧。
|
||||||
|
- [ ] 使用正式 4K 样本分别连续验证 `1x` 和 `2x`,记录等待次数、累计等待时长、最小前向缓冲和掉帧数。
|
||||||
|
- [ ] Chrome 桌面端和目标移动设备均完成验证。
|
||||||
|
|
||||||
|
若完成上述缓冲策略后,多个地区和设备仍普遍出现“前向缓冲耗尽”,再单独评估 OSS 前置 CDN Range 缓存或 OSS 传输加速;该基础设施调整会新增费用,不属于本次前端通知范围。
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户