目录
快速开始
安装依赖
pnpm add hls.js @ffmpeg/ffmpeg @ffmpeg/util antd @ant-design/icons
启动服务
npx next dev -p 3004
# 访问 http://localhost:3004/h265-hls-player
快速测试
播放器内置了公共测试流,点击标签即可一键加载:
| 测试流 | 地址 | 说明 |
|--------|------|------|
| Mux Test | https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8 | Mux 官方测试流 |
| Apple Sample | https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8 | Apple 官方 HLS 样例 |
技术架构
整体链路
┌─────────────┐ HLS (.m3u8) ┌──────────────────────────────┐
│ 摄像头 │ ──────────────────► │ 浏览器 │
│ (H.265) │ │ │
│ 海康/大华 │ │ ┌────────────────────────┐ │
│ 宇视/华为 │ │ │ 自动能力检测 │ │
└─────────────┘ │ │ │ │
│ │ ├─ WebCodecs (优先) │ │
│ │ │ H.265 硬件直解 │ │
│ │ │ Chrome 107+ │ │
│ │ ├─ Native HLS │ │
│ │ │ Safari 16.4+ │ │
│ │ └─ FFmpeg.wasm (兜底) │ │
│ │ H.265→H.264 软件 │ │
│ └────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ MediaSource Extension │ │
│ │ → HTML5 <video> │ │
│ └────────────────────────┘ │
└──────────────────────────────┘
三层解码策略
| 优先级 | 解码方式 | 触发浏览器 | 实时性 | 商用 | |:------:|---------|-----------|:------:|:----:| | 🥇 1 | WebCodecs (硬件解码) | Chrome 107+ (Win/macOS + HEVC 硬件) | ✅ 实时 | ✅ 免费 | | 🥈 2 | Native HLS (原生支持) | Safari 16.4+ | ✅ 实时 | ✅ 免费 | | 🥉 3 | FFmpeg.wasm (软件转码) | 所有现代浏览器 | ⚠️ 见限制 | ✅ LGPL |
浏览器自动检测并选择最优解码路径,无需手动配置。
组件清单
| 文件 | 说明 |
|------|------|
| components/H265HlsPlayer.tsx | 核心播放器组件 |
| pages/h265-hls-player.tsx | 独立演示页面 |
| pages/h265-player.tsx | H.265 文件转码播放器 |
| pages/hls-stream.tsx | 通用 HLS 流播放器 |
部署指南
Next.js 配置
播放器需要 SharedArrayBuffer 支持,必须在 next.config.js 中添加 COOP/COEP 响应头:
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
{ key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' },
],
},
];
},
};
重启开发服务器后生效(
npm run dev)。
生产环境 CORS
流媒体服务器必须返回正确的 CORS 头:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Range, Content-Type
HTTPS 要求
FFmpeg.wasm 的 SharedArrayBuffer 需要 HTTPS 或 localhost,生产环境必须使用 HTTPS。
API 参考
H265HlsPlayer
import H265HlsPlayer from '@/components/H265HlsPlayer';
// 基础用法
<H265HlsPlayer />
// 传入默认 URL
<H265HlsPlayer defaultUrl="https://your-camera/stream.m3u8" />
属性
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| defaultUrl | string | '' | 默认加载的 HLS URL |
回调
<H265HlsPlayer
onStreamLoaded={(url) => console.log('Stream loaded:', url)}
onError={(err) => console.error('Stream error:', err)}
/>
next.config.js 配置(完整版)
/** @type {import('next').NextConfig} */
module.exports = {
async headers() {
return [
{
// 匹配所有页面
source: '/(.*)',
headers: [
// COEP: 启用跨域隔离,SharedArrayBuffer 才可用
{ key: 'Cross-Origin-Embedder-Policy', value: 'require-corp' },
// COOP: 防止跨域窗口通信问题
{ key: 'Cross-Origin-Opener-Policy', value: 'same-origin' },
// CORS: HLS 流跨域访问
{ key: 'Access-Control-Allow-Origin', value: '*' },
{ key: 'Access-Control-Allow-Methods', value: 'GET, OPTIONS' },
{ key: 'Access-Control-Allow-Headers', value: 'Range, Content-Type' },
],
},
];
},
};
许可说明
| 组件 | 许可 | 商用 | 链接 | |------|------|:----:|------| | FFmpeg.wasm | LGPL 2.1+ | ✅ | https://github.com/ffmpegwasm/ffmpeg.wasm | | hls.js | BSD 2-Clause | ✅ | https://github.com/video-dev/hls.js | | WebCodecs API | W3C | ✅ | https://www.w3.org/TR/webcodecs/ | | H.264 解码器 (浏览器内置) | MPEG LA | ✅ | 仅解码器免费,不含编码器 |
完整许可链
FFmpeg.wasm 核心 (LGPL 2.1+) ──免费──► ffmpeg.wasm-core.wasm
│
▼ libx264 (GPL) ──► 仅用户本地使用,分发无需 GPL
│
▼
最终输出 H.264 (浏览器解码器免费)
说明:ffmpeg.wasm 自带的 libx264 是 GPL 版本,但最终产物 H.264 视频流通过浏览器的 MPEG LA 免费解码器播放,不构成 GPL 分发。个人项目和 SaaS 内部使用完全合规。商业产品如需更严格合规,可使用 LGPL 版或换用 VP9 编码器。
已知限制
FFmpeg.wasm 软件解码性能
| 分辨率 | 帧率 | 推荐等级 | 说明 | |--------|------|:--------:|------| | 720p | 25fps | ✅ 推荐 | 软件解码基本流畅 | | 1080p | 25fps | ⚠️ 可用 | 可能需要降低帧率或画质 | | 4MP+ | 25fps | ❌ 不推荐 | 超出软件解码能力 | | 4K | - | ❌ 不可用 | 无实用价值 |
解决建议:搭配服务端转码(见 RTSP 摄像头方案).
浏览器兼容性
| 浏览器 | H.265 HLS 支持 | 推荐程度 | |--------|--------------|:--------:| | Chrome 107+ (Win + HEVC 硬件) | ✅ WebCodecs | ⭐⭐⭐⭐⭐ | | Safari 16.4+ | ✅ Native HLS | ⭐⭐⭐⭐⭐ | | Chrome (无 HEVC 扩展) | ⚠️ FFmpeg.wasm | ⭐⭐⭐ | | Firefox | ⚠️ FFmpeg.wasm | ⭐⭐ | | Edge (Chromium) | ⚠️ FFmpeg.wasm | ⭐⭐⭐ | | 移动端浏览器 | ⚠️ 表现不一 | ⚠️ |
FAQ
Q: 摄像头只输出 RTSP,不支持 HLS,怎么处理?
需要服务端将 RTSP 转换为 HLS。推荐使用 go2rtc(MIT 协议,商用免费):
# 单流转发
go2rtc --static "cam1:rtsp://user:pass@192.168.1.100:554/1"
# Docker 快速部署
docker run -it --rm \
-p 1984:1984 \
-v ./go2rtc.yaml:/config/go2rtc.yaml \
alexxit/go2rtc
# 浏览器访问
http://localhost:1984/live/cam1.m3u8
go2rtc.yaml 配置示例:
streams:
cam1:
- rtsp://admin:admin123@192.168.1.100:554/1
cam2:
- rtsp://admin:admin123@192.168.1.101:554/1
Q: 支持多少个摄像头同时播放?
取决于设备性能。实测参考:
- 4 通道 720p 同时播放:普通 PC 可行
- 4 通道 1080p 同时播放:建议 RTX 3060+ 或使用 go2rtc 服务端转码
- 多画面监控墙:推荐 go2rtc + HLS,降低浏览器负担
Q: 画面延迟有多高?
| 方案 | 理论延迟 | 说明 | |------|:--------:|------| | WebCodecs (硬件) | 100-500ms | 最优 | | Native HLS (Safari) | 1-3s | 取决于 HLS 切片大小 | | FFmpeg.wasm + MSE | 3-10s | 依赖转码速度 | | 服务端 go2rtc HLS | 1-5s | 取决于服务端配置 |
低延迟需求:使用 go2rtc 的 WebRTC 模式,可达 200-500ms。
Q: 如何集成到现有项目?
// 1. 复制组件到你的项目
// 2. 安装依赖
pnpm add hls.js @ffmpeg/ffmpeg @ffmpeg/util
// 3. 添加 next.config.js COEP/COOP 配置(见上文)
// 4. 页面中使用
import H265HlsPlayer from '@/components/H265HlsPlayer';
export default function CameraPage() {
return (
<div>
<H265HlsPlayer defaultUrl="https://your-camera/stream.m3u8" />
</div>
);
}
Q: 画面出现花屏或卡顿怎么办?
- FFmpeg.wasm 模式下:降低摄像头编码的分辨率或帧率
- 网络问题:检查网络带宽是否充足
- 浏览器兼容性:Chrome 切换到 Safari 或使用 go2rtc 服务端方案
- 摄像头码率过高:建议摄像头码率设置在 2-4 Mbps
Q: 可以在微信小程序中使用吗?
❌ 不可以。小程序 webview 不支持 FFmpeg.wasm 和 WebCodecs API。
替代方案:
- 使用摄像头厂商的微信小程序 SDK
- 或使用 go2rtc → WebRTC → 微信小程序 webview(需要企业认证)
更新日志
| 版本 | 日期 | 变更 | |------|------|------| | v1.0 | 2024-02-13 | 初始版本,支持 WebCodecs / Native HLS / FFmpeg.wasm 三层解码 |