HLS.js使用指南与最佳实践
一文搞懂HLS流媒体播放的核心技术,包含完整的代码示例和常见问题解决方案。
阅读更多 →零插件、高性能的网页FLV直播播放方案
FLV.js 是由 Bilibili(B站)开源的一个纯 JavaScript 实现的 FLV 播放器,可以在不使用 Flash 插件的情况下,在支持 MSE(Media Source Extensions)的现代浏览器中播放 FLV 视频流。它的出现解决了 Flash 淘汰后网页端 FLV 直播播放的难题。
在 Flash 时代,RTMP/FLV 是直播的主流方案。但随着 Flash 被各大浏览器淘汰,网页端直播面临转型。FLV.js 的出现让基于 HTTP-FLV 的直播方案得以延续,配合 CDN 的 HTTP 分发,可以实现低延迟、高并发的直播体验。
FLV.js 项目诞生于 Bilibili 前端团队,最初是为了解决 B 站直播业务的播放器问题。2016 年,随着 Flash 的衰落,B 站需要一个纯网页端的直播播放方案,于是发起了这个项目。
FLV.js 于 2016 年正式开源,迅速成为前端直播领域的标杆项目,被大量直播平台和视频网站采用。它的成功推动了 HTTP-FLV 直播方案的普及,也催生了更多基于 MSE 的播放器项目。
FLV.js 的核心工作原理是:通过 HTTP 请求获取 FLV 流数据,在浏览器端用 JavaScript 解析 FLV 封装格式,然后将音视频数据通过 MSE API 喂给浏览器原生的 video 标签进行解码和播放。
FLV.js 对 FLV 文件的解析过程如下:
很多人会混淆 flv.js 和 mpegts.js,其实它们是同一个作者开发的两个不同项目:
| 特性 | flv.js | mpegts.js |
|---|---|---|
| 开发者 | Bilibili | 原 flv.js 作者个人 |
| 支持格式 | FLV | FLV、MPEG-TS |
| 更新状态 | 较慢 | 活跃 |
| 功能 | 基础功能 | 更多新特性 |
| 推荐场景 | 只需要FLV播放 | 需要更多格式和功能 |
下面通过一个完整的示例,演示如何在网页中使用 FLV.js 播放 FLV 视频流。
最简单的方式是通过 CDN 引入:
<script src="https://cdn.jsdelivr.net/npm/flv.js@latest/dist/flv.min.js"></script>
也可以通过 npm 安装:
npm install flv.js --save
在页面中添加一个 video 元素:
<video id="videoElement" controls autoplay muted playsinline></video>
使用 FLV.js 创建播放器实例并加载视频流:
if (flvjs.isSupported()) {
const videoElement = document.getElementById('videoElement');
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'https://example.com/live/stream.flv',
isLive: true
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
}
type:媒体类型,'flv' 或 'mp4'url:视频流地址isLive:是否为直播流cors:是否启用 CORS 跨域withCredentials:是否携带 CookiehasAudio:是否包含音频hasVideo:是否包含视频直播场景下,延迟是一个非常重要的指标。FLV.js 提供了多种配置选项来优化延迟。
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: 'https://example.com/live/stream.flv',
isLive: true
}, {
enableWorker: true,
enableStashBuffer: false,
stashInitialSize: 128,
liveBufferLatencyChasing: true,
liveBufferLatencyMaxLatency: 1.5,
liveBufferLatencyMinRemain: 0.5,
autoCleanupSourceBuffer: true
});
enableWorker: true:启用 Web Worker,避免解析阻塞主线程enableStashBuffer: false:禁用缓存缓冲区,减少延迟stashInitialSize: 128:初始缓存大小(KB),设置较小值liveBufferLatencyChasing: true:启用直播延迟追赶liveBufferLatencyMaxLatency: 1.5:最大延迟 1.5 秒,超过则加速liveBufferLatencyMinRemain: 0.5:最小缓冲 0.5 秒autoCleanupSourceBuffer: true:自动清理缓冲区,避免内存增长FLV.js 提供了丰富的事件系统,可以监听各种状态变化。
flvPlayer.on(flvjs.Events.ERROR, function(errorType, errorDetail, errorInfo) {
console.log('错误:', errorType, errorDetail, errorInfo);
});
flvPlayer.on(flvjs.Events.LOADING_COMPLETE, function() {
console.log('加载完成');
});
flvPlayer.on(flvjs.Events.RECOVERED_EARLY_EOF, function() {
console.log('从意外结束中恢复');
});
flvPlayer.on(flvjs.Events.MEDIA_INFO, function(mediaInfo) {
console.log('媒体信息:', mediaInfo);
});
flvPlayer.on(flvjs.Events.STATISTICS_INFO, function(statInfo) {
console.log('统计信息:', statInfo);
});
完善的错误处理是生产环境必备的功能。FLV.js 的错误分为不同类型,需要针对性处理。
NETWORK_ERROR:网络错误,如连接失败、超时等MEDIA_ERROR:媒体错误,如解码失败、格式不支持等OTHER_ERROR:其他错误flvPlayer.on(flvjs.Events.ERROR, function(errorType, errorDetail, errorInfo) {
console.error('播放器错误:', errorType, errorDetail);
if (errorType === flvjs.ErrorTypes.NETWORK_ERROR) {
if (errorDetail === flvjs.ErrorDetails.NETWORK_STATUS_CODE_INVALID) {
console.log('HTTP状态码错误,可能链接失效');
} else if (errorDetail === flvjs.ErrorDetails.NETWORK_TIMEOUT) {
console.log('网络超时,尝试重连...');
retryPlay();
}
} else if (errorType === flvjs.ErrorTypes.MEDIA_ERROR) {
console.log('媒体错误,尝试恢复...');
flvPlayer.recoverMediaError();
}
});
function retryPlay() {
flvPlayer.unload();
flvPlayer.load();
flvPlayer.play();
}
对于直播场景,网络波动导致断流是常见问题,建议实现自动重连机制:
let retryCount = 0;
const maxRetry = 5;
flvPlayer.on(flvjs.Events.ERROR, function(errorType) {
if (errorType === flvjs.ErrorTypes.NETWORK_ERROR && retryCount < maxRetry) {
retryCount++;
setTimeout(function() {
flvPlayer.unload();
flvPlayer.load();
flvPlayer.play();
}, 2000 * retryCount);
}
});
flvPlayer.on(flvjs.Events.RECOVERED_EARLY_EOF, function() {
retryCount = 0;
});
在初始化前先检测浏览器是否支持,不支持时给出友好提示:
if (flvjs.isSupported()) {
initPlayer();
} else {
alert('您的浏览器不支持FLV播放,请使用Chrome、Firefox或Edge浏览器');
}
页面卸载或切换视频时,务必销毁播放器释放资源:
window.addEventListener('beforeunload', function() {
if (flvPlayer) {
flvPlayer.pause();
flvPlayer.unload();
flvPlayer.detachMediaElement();
flvPlayer.destroy();
flvPlayer = null;
}
});
确保视频服务器配置了正确的 CORS 头,否则 FLV.js 无法加载。需要的响应头包括:
Access-Control-Allow-Origin: *(或指定域名)Access-Control-Allow-Methods: GET, POST, OPTIONSAccess-Control-Expose-Headers: Content-Length直播流暂停后再播放,会从暂停的位置继续,导致延迟累积。建议暂停后再播放时跳转到最新位置:
videoElement.addEventListener('play', function() {
if (flvPlayer && flvPlayer.config.isLive) {
const livePosition = videoElement.buffered.end(0) - 1;
if (videoElement.currentTime < livePosition - 3) {
videoElement.currentTime = livePosition;
}
}
});
FLV.js 是一个优秀的开源 FLV 播放器,为网页端直播提供了高性能、低延迟的解决方案。它的纯 JavaScript 实现无需任何插件,配合 HTTP-FLV 协议,可以达到接近 Flash 时代的低延迟体验。
对于想要快速体验 FLV 播放的用户,可以直接使用我们的 FLV/RTMP 在线播放器,粘贴直播地址即可在浏览器中观看,无需编写任何代码。