基于 CKPlayer 的轻量级自适应播放器:支持 M3U8/FLV 双格式
如果你需要一个支持 M3U8 和 FLV 双格式、带重试机制、零依赖部署的视频播放器,基于 CKPlayer + 插件化的方案是一个稳定可靠的选择。它自带加载状态提示、错误自动重试、格式自动识别等功能,适合作为资源站的通用播放方案。
在线演示
点击预览实际效果:
👉 CKPlayer 自适应播放器演示
该演示使用开源测试视频流,支持自动重试、加载提示、全屏切换等功能。
为什么选择 CKPlayer?
- 双格式支持:自动识别
.m3u8和.flv,自动加载对应解码器(HLS.js / FLV.js) - 智能重试:播放失败自动重试 3 次,提升弱网环境下的播放成功率
- 加载状态:带旋转加载动画和错误提示,用户体验更完整
- 自适应全屏:CSS 强制 100% 宽高,无边距黑边
- 零依赖部署:单 HTML 文件,所有资源通过 CDN 加载
完整代码
将以下代码保存为 index.html,上传到服务器任意目录即可使用:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<title>自适应播放器</title>
<!-- 插件:同时引入 flv.js 和 hls.js(按需使用) -->
<script src="https://cdn.jsdelivr.net/npm/flv.js/dist/flv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script>
<!-- CKPlayer 核心(通过 CDN 加载) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ckplayer@latest/ckplayer.css">
<script src="https://cdn.jsdelivr.net/npm/ckplayer@latest/ckplayer.js"></script>
<style>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background: #000;
}
.video {
width: 100%;
height: 100%;
background: #000;
}
#loading {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: sans-serif;
font-size: 16px;
text-align: center;
z-index: 100;
}
#error {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: sans-serif;
font-size: 16px;
text-align: center;
display: none;
z-index: 100;
}
.spinner {
border: 3px solid rgba(255, 255, 255, 0.3);
border-top: 3px solid white;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="video"></div>
<div id="loading">
<div class="spinner"></div>
<div>视频加载中...</div>
</div>
<div id="error"></div>
<script>
let retryCount = 0;
const maxRetries = 3;
let player = null;
// 获取 url 参数,默认使用测试流
const url = new URLSearchParams(location.search).get('url') || 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8';
// 自动识别格式
let plug = '';
if (url.toLowerCase().endsWith('.m3u8')) {
plug = 'hls.js';
} else if (url.toLowerCase().endsWith('.flv')) {
plug = 'flv.js';
} else {
showError('❌ 仅支持 .m3u8 或 .flv 格式');
}
function showError(message) {
document.getElementById('loading').style.display = 'none';
document.getElementById('error').innerText = message;
document.getElementById('error').style.display = 'block';
}
function hideLoading() {
document.getElementById('loading').style.display = 'none';
}
function initPlayer() {
if (!plug) return;
try {
var videoObject = {
container: '.video',
variable: 'player',
autoplay: true,
muted: true,
preload: 'auto',
video: url,
// 增强配置
config: {
timeFrequency: 100,
bufferTime: 300,
cache: 2,
errorTime: 30,
timeout: 10000,
loadTime: 5000
},
// 插件配置
setup: plug === 'hls.js' ? [
{
type: 'hls',
config: {
maxBufferLength: 30,
maxMaxBufferLength: 60,
maxBufferSize: 60 * 1000 * 1000,
maxBufferHole: 0.5,
lowBufferWatchdogPeriod: 0.5,
highBufferWatchdogPeriod: 3
}
}
] : [
{
type: 'flv',
config: {
enableStashBuffer: true,
stashInitialSize: 128 * 1024,
isLive: false,
lazyLoad: true,
lazyLoadMaxDuration: 3 * 60,
lazyLoadRecoverDuration: 30,
deferLoadAfterSourceOpen: false,
autoCleanupSourceBuffer: true,
autoCleanupMaxBackwardDuration: 3 * 60,
autoCleanupMinBackwardDuration: 2 * 60
}
}
],
// 事件监听
listener: function(event, type, obj) {
switch(type) {
case 'loadstart':
case 'loadedmetadata':
case 'loadeddata':
case 'canplay':
case 'canplaythrough':
case 'playing':
case 'timeupdate':
// 视频可以播放时立即隐藏加载状态
hideLoading();
break;
case 'error':
console.error('播放错误:', obj);
if (retryCount < maxRetries) {
retryCount++;
setTimeout(() => {
console.log(`重试播放: 第 ${retryCount} 次`);
if (player) {
player.newVideo(url);
} else {
initPlayer();
}
}, 1000);
} else {
showError('❌ 视频加载失败,请重试');
}
break;
case 'ended':
console.log('播放结束');
break;
}
}
};
player = new ckplayer(videoObject);
// 监听全局错误
window.playerError = function() {
console.error('播放器全局错误');
if (retryCount < maxRetries) {
retryCount++;
setTimeout(() => {
console.log(`重试播放: 第 ${retryCount} 次`);
initPlayer();
}, 1000);
} else {
showError('❌ 播放器初始化失败,请重试');
}
};
// 备用方案:3秒后强制隐藏加载状态(如果视频已经开始播放)
setTimeout(() => {
if (document.getElementById('loading').style.display !== 'none') {
console.log('备用方案:强制隐藏加载状态');
hideLoading();
}
}, 3000);
} catch (error) {
console.error('播放器初始化错误:', error);
showError('❌ 播放器初始化失败');
}
}
// 页面加载完成后初始化
if (document.readyState === 'complete') {
initPlayer();
} else {
window.addEventListener('load', initPlayer);
}
</script>
</body>
</html>
使用方法
基础播放(支持 m3u8/flv)
将视频地址通过 URL 参数传入:
https://你的域名.com/player.html?url=https://example.com/video.m3u8
播放 FLV 格式
https://你的域名.com/player.html?url=https://example.com/video.flv
嵌入到博客文章
在其他页面中通过 iframe 嵌入:
<iframe src="https://你的域名.com/player.html?url=视频地址"
width="100%"
height="500"
frameborder="0"
allowfullscreen>
</iframe>
核心特性解析
1. 自动格式识别
通过 URL 后缀自动判断视频类型:
.m3u8→ 启用 HLS.js 解码.flv→ 启用 FLV.js 解码- 其他格式 → 提示错误
2. 智能重试机制
- 错误重试:播放失败自动重试 3 次,间隔 1 秒
- 初始化重试:CKPlayer 初始化失败也会触发重试
- 超时处理:3 秒强制隐藏加载动画,防止卡死
3. 缓冲优化配置
- M3U8:配置
maxBufferLength和maxBufferSize,平衡流畅度和内存占用 - FLV:启用
autoCleanupSourceBuffer自动清理缓存,适合长视频
4. 加载状态反馈
- 旋转动画:CSS3 实现的加载 spinner
- 加载文字:提示"视频加载中..."
- 错误提示:红色文字显示具体错误(格式不支持、加载失败等)
注意事项
- HTTPS 要求:播放页和视频源必须同为 HTTPS,混用会被浏览器拦截
- CORS 限制:视频服务器需允许跨域访问(
Access-Control-Allow-Origin: *) - CDN 可用性:如果 jsdelivr 访问慢,可将 CDN 地址替换为:
https://unpkg.com/ckplayer@latest/ckplayer.js- 或下载到本地
js/目录使用相对路径
总结
这是一个比 ArtPlayer 更健壮的替代方案,特别适合需要自动重试和双格式支持的场景。CKPlayer 的插件化架构让它能同时处理 HLS 和 FLV,而完善的加载状态提示让用户体验更完整。配合单文件部署,适合作为个人资源站的通用播放器。