# 草原指南 MP4 物理交错修复与测试数据回填

> 日期：2026-07-16
>
> 后端 Issue：[HL #5016](https://git.1814.love:8443/wx/HL/issues/5016)
>
> 后端 PR：[HL #5019](https://git.1814.love:8443/wx/HL/pulls/5019)
>
> 测试分支：`dev-v3`
>
> 影响服务：`hl-user-service`
>
> 本次不修改前端仓库，不新增或修改接口字段

## 1. 问题结论

草原指南真实 4K MP4 在 `1x`、`2x` 播放时出现固定位置反复缓冲。浏览器 Network 中同一文件产生大量被取消并重新发起的 `206 Partial Content` 请求，实际传输量可以超过文件本身体积。

该问题包含两个独立因素：

1. 历史 MP4 虽然已经把 `moov` 移到 `mdat` 前面，但音频、视频 Sample 在 `mdat` 中没有按时间物理交错。播放到同一时间点时，浏览器需要在文件相距很远的位置来回读取音视频数据，造成 Range 请求抖动、取消和重复下载。
2. 原片本身约 `357204588` 字节、`71` 秒，平均码率约 `40.25 Mbps`。2026-07-16 当前诊断链路连续读取 OSS Range 仅约 `0.52–1.44 MB/s`（约 `4.14–11.50 Mbps`），低于 `1x` 所需的约 `5.03 MB/s`，因此修复文件结构后仍可能因实际网络吞吐不足发生正常缓冲。

前端缓存策略不能补足长期吞吐缺口。`preload="auto"` 只能改善起播等待，不能让 `10 Mbps` 链路持续播放 `40 Mbps` 原片。

## 2. 后端修复

草原指南视频上传确认阶段新增 MP4 无损重封装：

- 不重新编码，不改变 H.264/AAC Sample。
- 不降低分辨率、帧率或码率。
- 保持原视频、音频轨的 Sample 数量、Sample 总字节数和时长。
- 将 `ftyp`、`moov` 放在文件前部。
- 以约 2 秒为窗口重新排列音频、视频 Chunk，使相同时间点的数据物理相邻。
- 重封装前后执行媒体指纹校验；不一致时拒绝替换原对象。
- 新对象使用 `.progressive-...mp4` Key，成功后再以 CAS 更新文件记录；旧对象暂不删除，便于回滚。
- 单个 Pod 同时只执行一个重封装任务，并检查临时磁盘空间，避免大文件并发耗尽磁盘。

接口路径和请求体保持不变：

```http
POST /admin/material/upload/confirm
```

前端仍然只提交原有 `materialId`、`description` 和 `tagIds`，不需要增加重封装参数。

## 3. 历史测试数据回填

已对测试环境问题视频执行一次性回填：

| 项目 | 值 |
| --- | --- |
| 草原指南视频 ID | `2076910159484928002` |
| 素材 ID | `2076909130286612482` |
| 文件 ID | `2076909128663379970` |
| 文件大小 | `357204588` 字节 |
| 新时长 | `71` 秒 |
| 新文件标识 | OSS Key 包含 `.progressive-2076909128663379970-` |

回填结果：

- `file_info` 已切换为新 `.progressive-...mp4`，状态为 `ACTIVE / OSS_MP4_READY_V1`。
- `material.oss_url`、自动封面和时长已切换。
- `grassland_guide_video` 自动封面和时长已同步，业务记录仍为 `PUBLISHED`。
- 资源服务 `8082/8182` 与网关 `8080` 的匿名详情、播放接口均返回新地址。
- OSS `HEAD` 返回 `200 video/mp4`、`Content-Length: 357204588`、`Accept-Ranges: bytes`。
- `Range: bytes=0-1048575` 返回 `206` 和正确的 `Content-Range`。

## 4. 部署与验证证据

- 修复提交：`4529da5e97fea21022ca700390a146944608eadc`
- `dev-v3` 合并提交：`65c63a68d903370d07dd80ffea62ac58ccfb31c8`
- `hl-user-service` 测试环境滚动部署任务：`f4d670ba`
- 两实例 `8081/8181` 均启动健康。
- `hl-user-service` 测试：`3226` 个测试，`0` 失败，`0` 错误，`6` 跳过。
- 真实 357 MB 文件无损重封装测试通过；重封装前后轨道 Sample 数、Sample 字节数和时长一致。
- 原文件约 44 秒处的音频、视频数据物理距离约 `185.7 MB`；重封装后缩短到约 `69.7 KB`。

## 5. 仍需处理的基础设施边界

本次后端修复解决“文件内部排列导致重复 Range 请求”的问题，但不能提高用户到 OSS 的实时带宽。

在“不降低码率、不生成低清档”的前提下：

- `1x` 需要链路持续高于约 `40.25 Mbps`，还应预留网络波动余量。
- `2x` 平均需要约 `80.50 Mbps`，短时峰值可能更高。
- 当前测试桶传输加速域名请求返回 `400`，未形成可用的加速播放链路。
- 若目标用户链路长期低于原片码率，只能选择 OSS 前置 CDN/边缘缓存、开通并验证 OSS 传输加速，或让用户在播放前基本下载完整文件；单纯调整浏览器缓冲逻辑无法解决。

接入 CDN 或 OSS 传输加速会改变基础设施和费用，须单独确认后实施。不得为规避该问题把流量代理到 Java 服务，也不得把几百 MB 文件整体读入服务内存。

## 6. 大文件上传确认超时提醒

本次真实文件在测试环境完成下载、重封装、上传共耗时约 `410` 秒，超过当前网关约 `60` 秒的请求超时。

- 服务端任务能够继续完成，但前端可能先收到 `504`。
- 在异步媒体处理改造完成前，前端不得因单次 `504` 立即重复提交或重复上传，应重新查询素材状态。
- 正式发布前应单独改造为异步处理状态机，或提供明确的后台任务查询接口；不建议简单把网关超时提高到数分钟。
