网页端视频黑屏:media.php 304与Range冲突已修,根因是H.265/HEVC浏览器解不了 #52

Open
opened 2026-11-05 04:40:21 +00:00 by laoyang · 0 comments
Owner

网页端视频无法播放:H.265/HEVC 编码 + media.php 304/Range 冲突

现象

「网页端的视频好像没法播放。我现在在网页端传了两个视频,
点开之后是黑的,没办法播放。」

排查(逐层排除)

检查项 结果
数据库有视频 ✅ 15 个,mime=video/mp4
文件存在 ✅ OSS 上 1.22MB / 4.39MB
media.php GET ✅ HTTP 200,video/mp4
Range 请求 ✅ HTTP 206,Accept-Ranges: bytes
Attachment::kind() ✅ video
previewable() ✅ YES
data-src 输出 ✅ 正确

两个真因

① media.php 304 与 Range 冲突(已修)

// 原顺序:先判 304,后处理 Range
if ($inm !== '' && $inm === $etag) {
    http_response_code(304);   // ← 304 无响应体
    exit;
}
// ---- Range ----              ← 在这之后

视频第一次播完浏览器缓存了 ETag。拖动进度条或第二次打开时同时发:

Range: bytes=1048576-
If-None-Match: "9ea6694..."

⇒ 命中 304 ⇒ 空响应 ⇒ <video> 拿不到数据 ⇒ 黑屏。

这也解释「有时候能播有时候黑」—— 取决于浏览器有没有带 ETag。

修法:$hasRange 为真时跳过 304 判定。顺手补 Last-Modified(部分浏览器需要它才允许 seek)。

实测验证:

① Range 无 ETag        → HTTP 206,1024 字节       ✅
② Range + If-None-Match → HTTP 206,234105 字节    ✅(原来 304/0 字节)
③ 纯 If-None-Match      → HTTP 304,0 字节         ✅ 缓存仍正常

② 视频本身是 H.265/HEVC(未解决)

拉 OSS 原始文件分析:

前 48 字节: 0000001C667479706D703432...6D6F6F76
major_brand = mp42
编码 = hvc1 → H.265/HEVC
moov box 位置: 32 (faststart ✅)

Chrome / Firefox 无法解码 HEVC。

浏览器 HEVC
Safari ✅ 系统解码器
Chrome Windows ⚠️ 需装微软商店付费扩展
Chrome macOS / Linux ❌
Firefox ❌
Edge ⚠️ 同 Chrome

⚠️ 不存在能解码 HEVC 的前端 JS 库:
hls.js / flv.js / video.js 都只是传输层封装,不提供编解码器。
WebCodecs + WASM 理论可行,但 HEVC 的 WASM 解码器没有合法专利授权,
体积也几十 MB。

当前处理:检测到解码失败时显示明确提示 + 下载按钮,不再给一块黑屏。

这个视频浏览器解不了
它可能是 H.265(HEVC)编码。Chrome、Firefox 不支持这种格式,
但文件本身没坏 —— 下载后用系统播放器可以正常观看。
[ 下载这个视频 ]

彻底解决需:服务端装 ffmpeg 转码成 H.264(约 100MB)。

改动清单

文件 改动
media.php 有 Range 时跳过 304;补 Last-Modified
assets/js/preview.js 视频 error 时显示提示卡片 + 下载入口
assets/css/app.css .pv-video 用 vh 而非 100%;新增 .pv-fallback

验收

  • 带 Range + If-None-Match 返回 206 且有数据
  • 纯 If-None-Match 仍返回 304
  • 用户的实际视频能播放(需 ffmpeg 转码,待决策)
  • 解不了时给出明确提示而非黑屏

为什么单独建单

#51 处理的是行程类型和地址,本单是视频附件播放。两者都涉及 media.php/media 代理,但问题不同:#51 是接口作用域错位,本单是条件请求与Range的协议冲突 + 视频编码不受支持。

# 网页端视频无法播放:H.265/HEVC 编码 + media.php 304/Range 冲突 ## 现象 > 「网页端的视频好像没法播放。我现在在网页端传了两个视频, > 点开之后是黑的,没办法播放。」 ## 排查(逐层排除) | 检查项 | 结果 | |---|---| | 数据库有视频 | ✅ 15 个,mime=video/mp4 | | 文件存在 | ✅ OSS 上 1.22MB / 4.39MB | | `media.php` GET | ✅ HTTP 200,`video/mp4` | | Range 请求 | ✅ HTTP 206,`Accept-Ranges: bytes` | | `Attachment::kind()` | ✅ `video` | | `previewable()` | ✅ YES | | `data-src` 输出 | ✅ 正确 | ## 两个真因 ### ① `media.php` 304 与 Range 冲突(已修) ```php // 原顺序:先判 304,后处理 Range if ($inm !== '' && $inm === $etag) { http_response_code(304); // ← 304 无响应体 exit; } // ---- Range ---- ← 在这之后 ``` 视频第一次播完浏览器缓存了 ETag。**拖动进度条或第二次打开**时同时发: ``` Range: bytes=1048576- If-None-Match: "9ea6694..." ``` ⇒ 命中 304 ⇒ 空响应 ⇒ `<video>` 拿不到数据 ⇒ **黑屏**。 这也解释「有时候能播有时候黑」—— 取决于浏览器有没有带 ETag。 **修法**:`$hasRange` 为真时跳过 304 判定。顺手补 `Last-Modified`(部分浏览器需要它才允许 seek)。 **实测验证**: ``` ① Range 无 ETag → HTTP 206,1024 字节 ✅ ② Range + If-None-Match → HTTP 206,234105 字节 ✅(原来 304/0 字节) ③ 纯 If-None-Match → HTTP 304,0 字节 ✅ 缓存仍正常 ``` ### ② 视频本身是 H.265/HEVC(**未解决**) 拉 OSS 原始文件分析: ``` 前 48 字节: 0000001C667479706D703432...6D6F6F76 major_brand = mp42 编码 = hvc1 → H.265/HEVC moov box 位置: 32 (faststart ✅) ``` **Chrome / Firefox 无法解码 HEVC。** | 浏览器 | HEVC | |---|---| | Safari | ✅ 系统解码器 | | Chrome Windows | ⚠️ 需装微软商店付费扩展 | | Chrome macOS / Linux | ❌ | | Firefox | ❌ | | Edge | ⚠️ 同 Chrome | ⚠️ **不存在能解码 HEVC 的前端 JS 库**: hls.js / flv.js / video.js 都只是传输层封装,不提供编解码器。 WebCodecs + WASM 理论可行,但 HEVC 的 WASM 解码器没有合法专利授权, 体积也几十 MB。 **当前处理**:检测到解码失败时显示明确提示 + 下载按钮,不再给一块黑屏。 ``` 这个视频浏览器解不了 它可能是 H.265(HEVC)编码。Chrome、Firefox 不支持这种格式, 但文件本身没坏 —— 下载后用系统播放器可以正常观看。 [ 下载这个视频 ] ``` **彻底解决需**:服务端装 ffmpeg 转码成 H.264(约 100MB)。 ## 改动清单 | 文件 | 改动 | |---|---| | `media.php` | 有 Range 时跳过 304;补 `Last-Modified` | | `assets/js/preview.js` | 视频 error 时显示提示卡片 + 下载入口 | | `assets/css/app.css` | `.pv-video` 用 `vh` 而非 `100%`;新增 `.pv-fallback` | ## 验收 - [x] 带 Range + If-None-Match 返回 206 且有数据 - [x] 纯 If-None-Match 仍返回 304 - [ ] 用户的实际视频能播放(**需 ffmpeg 转码,待决策**) - [x] 解不了时给出明确提示而非黑屏 --- ### 为什么单独建单 #51 处理的是行程类型和地址,本单是视频附件播放。两者都涉及 media.php/media 代理,但问题不同:#51 是接口作用域错位,本单是条件请求与Range的协议冲突 + 视频编码不受支持。
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: laoyang/FamilyBook#52