作为 Web 前端工程师,视频播放是高频且核心的业务场景之一,涉及原生 API、播放器封装、兼容性、性能优化、高级功能 等多个维度。以下从「基础技术层」「核心实现方案」「进阶功能」「性能与兼容」四个层面,系统拆解视频播放的技术体系和落地方式。
一、核心基础技术:Web 视频播放的底层支撑
首先要明确 Web 端视频播放的核心技术底座,所有播放器都是基于这些基础能力封装而来。
1. HTML5 原生<video>标签(最基础)
HTML5 推出的<video>标签是 Web 视频播放的基石,无需插件(如 Flash),原生支持视频渲染,是所有前端视频播放的起点。
-
核心属性(必掌握):
属性 作用 src视频资源地址(支持本地 / 远程 URL,或通过 <source>指定多格式)controls显示浏览器原生控制栏(播放 / 暂停、进度、音量、全屏等) autoplay自动播放(需满足浏览器静音策略: muted+autoplay才会生效)muted静音播放 loop循环播放 poster视频封面图(播放前显示) preload预加载策略: none(不预加载)/metadata(仅预加载元信息)/auto(全量)playsinline移动端内联播放(避免自动全屏,适配 H5 页面) -
最简实现示例:
<video
id="videoPlayer"
src="./video.mp4"
controls
poster="./cover.jpg"
playsinline
width="640"<!-- 降级提示:浏览器不支持video标签时显示 --> 您的浏览器不支持HTML5视频播放,请升级浏览器
2. 视频编码与格式(兼容性关键)
前端必须关注视频格式,不同浏览器 / 设备对编码的支持差异极大,核心兼容方案是「多格式适配」。
-
主流格式对比:
格式 编码 浏览器支持 适用场景 MP4 H.264/AAC 所有现代浏览器(IE9+) 通用场景(PC / 移动端) WebM VP9/Opus Chrome/Firefox/Edge 开源免费,体积更小(无版权) Ogg Theora/Vorbis Firefox/Chrome(几乎不用) 小众场景 -
多格式适配实现 (通过
<source>标签):
注:
type属性中指定codecs能让浏览器更快判断是否支持该格式,提升加载效率。
3. Media API(原生 JS 控制)
<video>标签暴露了完整的 JavaScript API,用于自定义播放逻辑(替代原生控制栏),核心 API 分为「属性、方法、事件」三类。
(1)核心方法(主动控制)
const video = document.getElementById('videoPlayer');
// 播放/暂停
video.play(); // 返回Promise(需处理异步,如自动播放失败)
video.pause();
// 跳转进度
video.currentTime = 60; // 跳转到60秒处
// 音量控制(0-1)
video.volume = 0.5;
// 全屏(需兼容)
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.webkitRequestFullscreen) { // 移动端webkit内核
video.webkitRequestFullscreen();
}
(2)核心事件(监听状态)
// 播放状态变化(播放/暂停)
video.addEventListener('play', () => console.log('开始播放'));
video.addEventListener('pause', () => console.log('暂停播放'));
// 进度更新(每秒触发4-6次)
video.addEventListener('timeupdate', () => {
console.log('当前进度:', video.currentTime, '/', video.duration);
});
// 加载完成(元信息加载完毕,可获取duration)
video.addEventListener('loadedmetadata', () => {
console.log('视频时长:', video.duration);
});
// 播放结束
video.addEventListener('ended', () => {
console.log('播放完成');
// 循环播放:重新播放
video.play();
});
// 加载失败
video.addEventListener('error', () => {
console.log('播放失败:', video.error);
});
二、实际业务场景:核心实现方案
原生<video>仅满足基础播放,实际业务中需解决「自定义控制栏、倍速播放、断点续播、流媒体播放」等问题,以下是高频场景的实现方式。
场景 1:自定义视频控制栏(替代原生 controls)
原生控制栏样式不可定制,业务中通常隐藏原生控件,自己实现 UI + 逻辑。
<!-- 容器:视频 + 自定义控制栏 -->
<div class="video-container" style="position: relative; width: 640px;">
<video
id="customVideo"
src="./video.mp4"
playsinline
style="width: 100%;"
></video>
<!-- 自定义控制栏(默认隐藏,hover显示) -->
<div class="video-controls" style="position: absolute; bottom: 0; left: 0; right: 0; background: rgba(0,0,0,0.5); color: #fff; padding: 10px; display: none;">
<button id="playBtn">播放/暂停</button>
<input id="progressBar" type="range" min="0" max="100" value="0">
<button id="fullscreenBtn">全屏</button>
<select id="speedSelect">
<option value="0.5">0.5倍</option>
<option value="1" selected>1倍</option>
<option value="1.5">1.5倍</option>
<option value="2">2倍</option>
</select>
</div>
</div>
<script>
const video = document.getElementById('customVideo');
const controls = document.querySelector('.video-controls');
const playBtn = document.getElementById('playBtn');
const progressBar = document.getElementById('progressBar');
const fullscreenBtn = document.getElementById('fullscreenBtn');
const speedSelect = document.getElementById('speedSelect');
// 1. 显示/隐藏控制栏
video.addEventListener('mouseenter', () => controls.style.display = 'block');
video.addEventListener('mouseleave', () => controls.style.display = 'none');
// 2. 播放/暂停逻辑
playBtn.addEventListener('click', async () => {
if (video.paused) {
try {
await video.play(); // 处理自动播放权限问题
} catch (e) {
alert('播放失败,请手动点击播放');
}
} else {
video.pause();
}
});
// 3. 进度条同步与控制
// 进度更新时同步进度条
video.addEventListener('timeupdate', () => {
const progress = (video.currentTime / video.duration) * 100;
progressBar.value = progress;
});
// 拖动进度条跳转播放位置
progressBar.addEventListener('input', () => {
const pos = (progressBar.value / 100) * video.duration;
video.currentTime = pos;
});
// 4. 倍速播放
speedSelect.addEventListener('change', () => {
video.playbackRate = speedSelect.value; // 原生支持0.5-2倍速
});
// 5. 全屏控制
fullscreenBtn.addEventListener('click', () => {
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen();
}
});
</script>
场景 2:断点续播(记住上次播放位置)
利用localStorage存储播放进度,下次打开时自动跳转。
const video = document.getElementById('customVideo');
const VIDEO_KEY = 'video_progress_' + video.src; // 唯一标识
// 页面加载时恢复进度
window.addEventListener('load', () => {
const savedProgress = localStorage.getItem(VIDEO_KEY);
if (savedProgress) {
video.currentTime = Number(savedProgress);
}
});
// 进度更新时保存(节流,避免频繁存储)
let timer = null;
video.addEventListener('timeupdate', () => {
clearTimeout(timer);
timer = setTimeout(() => {
localStorage.setItem(VIDEO_KEY, video.currentTime);
}, 1000);
});
// 播放结束时清空进度(可选)
video.addEventListener('ended', () => {
localStorage.removeItem(VIDEO_KEY);
});
场景 3:流媒体播放(HLS/FLV,大文件 / 直播)
普通 MP4 是「完整文件播放」,直播 / 大视频需流媒体(边下载边播放),前端主流方案:
- HLS(HTTP Live Streaming):苹果推出,基于 TS 切片,移动端兼容好(M3U8 格式)。
- FLV:基于 HTTP 的流式传输,适合直播,体积小。
实现方式:原生<video>不支持 HLS/FLV,需借助第三方库(如hls.js、flv.js)。
(1)HLS 播放(hls.js)
<video id="hlsVideo" controls playsinline></video>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
const video = document.getElementById('hlsVideo');
const hlsUrl = 'https://example.com/stream.m3u8'; // HLS地址
if (Hls.isSupported()) { // 检测浏览器是否支持
const hls = new Hls();
hls.loadSource(hlsUrl);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play(); // 解析完成后播放
});
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// 移动端Safari原生支持HLS,无需库
video.src = hlsUrl;
video.addEventListener('loadedmetadata', () => {
video.play();
});
}
</script>
(2)FLV 播放(flv.js)
<video id="flvVideo" controls playsinline></video>
<script src="https://cdn.jsdelivr.net/npm/flv.js@latest/dist/flv.min.js"></script>
<script>
const video = document.getElementById('flvVideo');
const flvUrl = 'https://example.com/stream.flv'; // FLV地址
if (flvjs.isSupported()) {
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: flvUrl
});
flvPlayer.attachMediaElement(video);
flvPlayer.load();
flvPlayer.play();
}
</script>
场景 4:视频封面优化(预加载 / 懒加载)
-
封面加载时机 :
poster属性是静态封面,若需动态封面(如视频第一帧),可在视频加载后截取:video.addEventListener('loadeddata', () => {
// 视频加载第一帧后,隐藏poster,显示视频帧
video.poster = '';
}); -
懒加载:非首屏视频延迟加载,减少首屏资源消耗:
<video
id="lazyVideo"
data-src="./video.mp4"
controls
playsinline
<script> // 监听滚动,进入视口后加载 const lazyVideo = document.getElementById('lazyVideo'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { lazyVideo.src = lazyVideo.dataset.src; observer.unobserve(lazyVideo); } }); }); observer.observe(lazyVideo); </script>
三、进阶功能:提升用户体验
1. 倍速播放(原生支持)
// 设置倍速(0.5/1/1.5/2是主流)
video.playbackRate = 1.5;
// 获取当前倍速
console.log(video.playbackRate);
2. 画中画(Picture-in-Picture)
PC 端 Chrome/Firefox、移动端部分浏览器支持,实现悬浮小窗播放:
const pipBtn = document.getElementById('pipBtn');
// 检测是否支持画中画
if ('pictureInPictureEnabled' in document) {
pipBtn.addEventListener('click', async () => {
if (video !== document.pictureInPictureElement) {
await video.requestPictureInPicture();
} else {
await document.exitPictureInPicture();
}
});
} else {
pipBtn.disabled = true; // 不支持则禁用按钮
}
3. 预加载优化
通过preload属性控制预加载策略,结合canplay事件触发播放:
// 仅预加载元信息,用户点击播放后再加载视频
video.preload = 'metadata';
// 当视频可播放(加载足够数据)时提示
video.addEventListener('canplay', () => {
console.log('视频可开始播放');
});
四、性能与兼容性:避坑指南
1. 兼容性问题
| 问题场景 | 解决方案 |
|---|---|
| 移动端自动播放失败 | 加muted属性 + 用户交互后(如 click)再播放;避免纯自动播放 |
| iOS 视频自动全屏 | 加playsinline属性;X5 内核需额外配置:x5-video-player-type="h5" |
| 不同浏览器格式兼容 | 提供 MP4(H.264)+ WebM 双格式;优先 MP4 |
| 全屏 API 兼容 | 封装兼容函数(requestFullscreen/webkitRequestFullscreen/mozRequestFullscreen) |
2. 性能优化
- 视频压缩:使用 H.265 编码(比 H.264 体积小 50%),或适配不同分辨率(480p/720p/1080p);
- 懒加载:非首屏视频延迟加载,减少初始加载时间;
- 节流监听 :
timeupdate事件节流(如 1 秒一次),避免频繁 DOM 操作; - 资源 CDN:视频文件部署到 CDN,开启 Gzip/Brotli 压缩,提升加载速度;
- 预加载控制 :根据网络状态调整
preload(弱网设为none)。
3. 错误处理
video.addEventListener('error', () => {
const error = video.error;
switch (error.code) {
case MediaError.MEDIA_ERR_ABORTED: // 用户终止加载
console.log('视频加载被终止');
break;
case MediaError.MEDIA_ERR_NETWORK: // 网络错误
console.log('网络异常,视频加载失败');
// 重试逻辑:刷新视频src
setTimeout(() => {
video.src = video.src;
video.load();
}, 3000);
break;
case MediaError.MEDIA_ERR_DECODE: // 解码失败(格式不支持)
console.log('视频格式不支持,解码失败');
break;
case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: // 资源地址无效
console.log('视频地址无效');
break;
}
});
五、成熟播放器库(避免重复造轮子)
如果业务需求复杂(如弹幕、倍速、清晰度切换、直播连麦),直接使用成熟库更高效:
| 库名 | 特点 | 适用场景 |
|---|---|---|
| Video.js | 开源、跨浏览器、支持 HLS/FLV(需插件)、自定义插件丰富 | 通用场景(点播 / 简单直播) |
| Plyr | 轻量、美观、易定制、支持 HTML5/HLS | 轻量级自定义播放器 |
| TCPlayer | 腾讯云出品,支持 FLV/HLS/MP4、直播 / 点播、弹幕、画质切换 | 国内业务(适配 X5 内核) |
| AliPlayer | 阿里云出品,功能全,支持加密播放、直播回放 | 阿里云生态业务 |
为什么要使用hls和flv?
在 Web 端视频场景中选择 HLS 或 FLV,核心是解决原生<video>标签的局限性,适配不同业务场景的需求(如直播 / 点播、低延迟 / 兼容性),同时兼顾性能、兼容性和用户体验。
一、先明确:原生<video>的短板(为什么需要 HLS/FLV)
Web 原生<video>标签仅支持 MP4、WebM 等静态封装格式,无法满足复杂视频场景的核心需求:
- 直播场景:MP4 是完整文件,无法 "实时流式播放",而直播需要边推流边播放;
- 自适应码率:不同网络(4G/5G/WiFi)下,MP4 无法动态切换清晰度,易出现卡顿 / 加载慢;
- 低延迟需求:原生 MP4 播放需先缓冲部分数据,直播延迟可达数十秒,无法满足电商直播、赛事等低延迟场景;
- 大文件点播:GB 级的长视频(如电影)若用 MP4,首次加载需等待大量缓冲,用户体验差。
HLS 和 FLV 正是为解决这些痛点而生 ------ 本质是适配流媒体传输的协议 / 格式,让 Web 端能高效、灵活地播放视频。
二、使用 HLS 的核心原因(适配 "通用、兼容、自适应" 场景)
HLS(HTTP Live Streaming)是目前最主流的流媒体协议,核心价值体现在:
1. 跨端兼容性拉满(Web / 移动端 / 智能设备)
- 原生支持:Safari(桌面 + iOS)、Android 原生浏览器直接支持 HLS(m3u8),无需额外插件;
- 全端适配:非 Safari 浏览器(Chrome/Firefox)可通过
hls.js解析,覆盖 99% 以上的 Web 场景; - 设备兼容:智能电视、机顶盒、游戏机等终端均支持 HLS,是跨端视频的 "通用解"。
2. 自适应码率(ABR)------ 解决 "网络波动导致的卡顿"
HLS 将视频切割为 2~10 秒的 TS 小切片,并生成包含不同码率(360p/720p/1080p)的 m3u8 索引文件:
- 播放器可实时检测网络速度(如通过切片下载耗时),自动切换对应码率;
- 弱网时降级为低清晰度(如 360p)保证播放流畅,网络恢复后切回高清,无需用户手动操作。
3. 适配 "点播 + 非低延迟直播" 的通用场景
- 点播:大文件视频切片后,支持 "边下载边播放",首次加载仅需下载首个切片(2~5 秒),无需等待完整文件;
- 直播:虽然原生 HLS 延迟 10~30 秒,但通过 "低延迟 HLS(LL-HLS)" 可将延迟降至 3~5 秒,满足大多数直播场景(如教育直播、新闻直播)。
4. 基于 HTTP 传输 ------ 部署 / 运维成本低
HLS 基于标准 HTTP/HTTPS 协议,无需搭建专用流媒体服务器(如 RTMP):
- 可直接部署到 CDN(阿里云 / 腾讯云等均支持 HLS 加速),降低带宽成本;
- 穿透防火墙 / 代理:HTTP 是通用协议,避免 RTMP 等专用协议被拦截的问题;
- 断点续传:切片传输天然支持断点续传,播放中断后恢复无需重新加载全部数据。
三、使用 FLV 的核心原因(适配 "低延迟、高性能直播" 场景)
FLV(Flash Video)虽因 Flash 衰落一度式微,但基于flv.js(纯 JS 解析)重生,核心价值是低延迟 + 高性能:
1. 极致低延迟(1~3 秒)------ 秒杀原生 HLS
FLV 采用 "流式传输"(无切片,连续字节流),结合 HTTP-FLV/WS-FLV 协议:
- 直播延迟可控制在 1~3 秒,是电商直播、直播带货、赛事直播的首选(这类场景对互动性要求极高,延迟 > 5 秒会影响用户体验);
- 对比:原生 HLS 延迟 10~30 秒,即使 LL-HLS 也仅能降到 3~5 秒,FLV 在低延迟场景无可替代。
2. 解析性能高 ------ 轻量且高效
FLV 格式结构简单,flv.js解析时无需复杂的切片管理,CPU / 内存占用低于 HLS:
- 适合移动端 / 低配设备:在中低端手机上播放 FLV 直播,卡顿概率低于 HLS;
- 实时性强:流数据到达后可立即解析播放,无需等待切片完整,进一步降低延迟。
3. 兼容 RTMP 推流生态
直播行业早期以 RTMP 协议为主(主播推流、服务端转码),FLV 可直接对接 RTMP 生态:
- 服务端将 RTMP 流转换为 HTTP-FLV 流,无需额外转码为 HLS 切片,降低服务器压力;
- 成熟的开源方案(如 SRS/FFmpeg)支持 RTMP→FLV 的实时转换,部署成本低。
四、HLS vs FLV:什么时候选哪个?
| 业务场景 | 优先选 HLS | 优先选 FLV |
|---|---|---|
| 点播(电影 / 剧集 / 课程) | ✅ 自适应码率 + 跨端兼容 | ❌ 无切片,大文件加载慢 |
| 低延迟直播(电商 / 赛事) | ❌ 延迟高(LL-HLS 也仅 3~5 秒) | ✅ 1~3 秒延迟,互动性强 |
| 通用直播(教育 / 新闻) | ✅ 兼容性好,无需极致低延迟 | ❌ 移动端部分浏览器兼容略差 |
| 跨端适配(PC + 移动端 + TV) | ✅ 全端支持,无需额外适配 | ❌ TV / 部分 iOS 浏览器兼容差 |
| 弱网环境 | ✅ 自动降级码率,播放更稳定 | ❌ 无自适应码率,易卡顿 |
如何实现直播?
| 方案 | 延迟 | 兼容性 | 适合场景 | 核心依赖 |
|---|---|---|---|---|
| FLV(推荐) | 1~3 秒(低) | 大部分浏览器 | 电商直播、赛事、带货 | flv.js |
| HLS | 10~30 秒 | 全端兼容 | 教育直播、新闻直播 | hls.js |
| 直播方案 | 后端给的 URL 示例 | 核心特点 |
|---|---|---|
| FLV | https://live.example.com/room/666.flv |
后缀是.flv,基于 HTTP-FLV 协议 |
| HLS | https://live.example.com/room/666.m3u8 |
后缀是.m3u8,切片索引文件 |
优先选 FLV(直播核心需求是低延迟)
第二步:FLV 直播前端实现
前置准备
-
先安装依赖:flv.js 是纯 JS 写的 FLV 解析库,无需后端配合,前端直接用
# npm安装(推荐) npm install flv.js --save # 或直接引入CDN(不想装npm的话) <script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.min.js"></script> -
找一个测试用的 FLV 直播流(开发中后端给的也是可直接播放的直播流 URL 地址 ):
http://pullhls3.a.yximgs.com/upic/2024/01/01/12/BMjAyNDAxMDEwOTUzNDFfNzg5Nzc2MDlfMzcwNzY0ODk0MF8xXzM=_HD.flv
核心代码(HTML+JS)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>FLV直播播放</title>
<!-- 样式:简单做个播放器容器 -->
<style>
#live-player {
width: 800px;
height: 450px;
border: 1px solid #ccc;
margin: 20px auto;
background: #000;
}
.control {
text-align: center;
margin: 10px 0;
}
button {
padding: 8px 16px;
margin: 0 5px;
cursor: pointer;
}
</style>
</head>
<body>
<!-- 1. 视频播放容器 -->
<video id="live-player" controls autoplay muted></video>
<!-- 2. 控制按钮(播放/暂停/重连) -->
<div class="control">
<button id="play-btn">播放</button>
<button id="pause-btn">暂停</button>
<button id="reconnect-btn">重新连接</button>
</div>
<!-- 引入flv.js(CDN方式,不用npm的话) -->
<script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.min.js"></script>
<script>
// 核心变量
const videoElement = document.getElementById('live-player');
let flvPlayer = null; // FLV播放器实例
// 你的直播流地址(替换成自己的!)
const liveFlvUrl = 'http://pullhls3.a.yximgs.com/upic/2024/01/01/12/BMjAyNDAxMDEwOTUzNDFfNzg5Nzc2MDlfMzcwNzY0ODk0MF8xXzM=_HD.flv';
// 初始化FLV播放器
function initFlvPlayer() {
// 先判断浏览器是否支持
if (flvjs.isSupported()) {
// 创建播放器实例
flvPlayer = flvjs.createPlayer({
type: 'flv', // 流类型
url: liveFlvUrl, // 直播流地址
isLive: true, // 标记为直播(关键!优化直播播放逻辑)
hasAudio: true, // 有音频
hasVideo: true, // 有视频
enableStashBuffer: false // 关闭缓存(降低直播延迟)
});
// 将播放器挂载到video标签
flvPlayer.attachMediaElement(videoElement);
// 加载流
flvPlayer.load();
// 自动播放(注意:浏览器要求需用户交互后才能播放音频,所以先静音)
flvPlayer.play().catch(err => {
console.log('自动播放失败(浏览器限制),点击播放器后可播放', err);
});
// 监听错误(关键!断流后自动重连)
flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => {
console.error('直播出错:', errType, errDetail);
// 销毁错误的播放器
if (flvPlayer) {
flvPlayer.destroy();
flvPlayer = null;
}
// 3秒后自动重连
setTimeout(() => {
initFlvPlayer();
}, 3000);
});
// 监听播放状态
flvPlayer.on(flvjs.Events.PLAYING, () => {
console.log('直播播放中');
});
} else {
alert('你的浏览器不支持FLV直播,请更换Chrome/Firefox!');
}
}
// 按钮事件绑定
document.getElementById('play-btn').addEventListener('click', () => {
if (flvPlayer) flvPlayer.play();
videoElement.muted = false; // 取消静音
});
document.getElementById('pause-btn').addEventListener('click', () => {
if (flvPlayer) flvPlayer.pause();
});
document.getElementById('reconnect-btn').addEventListener('click', () => {
if (flvPlayer) {
flvPlayer.destroy();
flvPlayer = null;
}
initFlvPlayer();
});
// 页面加载时初始化
window.onload = () => {
initFlvPlayer();
};
// 页面关闭时销毁播放器(避免内存泄漏)
window.onbeforeunload = () => {
if (flvPlayer) {
flvPlayer.destroy();
flvPlayer = null;
}
};
</script>
</body>
</html>
代码说明(重点)
isLive: true:必须设为 true,告诉播放器这是直播,优化缓存逻辑,降低延迟;enableStashBuffer: false:关闭缓存,直播流来了就播,进一步降低延迟;- 错误监听 + 自动重连:直播最容易断流(网络波动、服务端推流中断),必须加这个逻辑 ;
- 静音自动播放:浏览器规定 "非用户交互的自动播放只能静音",所以先静音,用户点击播放按钮后再取消静音。
第三步:HLS 直播方案(兼容优先时用)
如果你的直播对延迟要求不高(比如教育直播),用 HLS 更兼容(比如 iOS Safari 原生支持),代码几乎和 FLV 一样,只是换库:
第四步:前端必避的坑(踩过的都懂!)
- 跨域问题:直播流地址必须配置 CORS(跨域允许),否则前端会报 "No Access-Control-Allow-Origin" 错误,让后端 / CDN 配置即可;
- 自动播放限制:所有浏览器都禁止 "无用户交互的有声自动播放",所以必须先静音,用户点击后再开声音;
- 移动端适配 :
- 移动端要加
<meta name="viewport" content="width=device-width, initial-scale=1">; - 全屏播放用
videoElement.requestFullscreen()(兼容:webkitEnterFullscreen for iOS);
- 移动端要加
- 断流重连:一定要加错误监听和自动重连,直播流不可能 100% 稳定;
- HTTPS 问题:如果你的网页是 HTTPS,直播流也必须是 HTTPS(浏览器禁止混合内容),否则会加载失败。