mirror of
https://github.com/hevin-lee/EasyPlayerJs.git
synced 2026-06-04 13:49:18 +00:00
568 lines
22 KiB
HTML
568 lines
22 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>EasyPlayer.js播放器</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||
<script src="./js/easyplayer-pro.js"></script>
|
||
<script src="./demo.js"></script>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="container">
|
||
<div>
|
||
<h5 class="text-lowercase text-bold">EasyPlayer.js播放器</h5>
|
||
</div>
|
||
<div class="mt-2">
|
||
<div class="row">
|
||
<div class="col-md-8">
|
||
<div id="video" style="background-color: black;aspect-ratio: 16 / 9;"></div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<p class="text-uppercase fw-bold">配置信息</p>
|
||
<div class="decoding row border-bottom mb-2 px-3">
|
||
<div class="form-check col">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="useMSE" checked>
|
||
<label class="form-check-label" for="useMSE">MSE(硬解)</label>
|
||
</div>
|
||
<div class="form-check col">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="useWCS">
|
||
<label class="form-check-label" for="useWCS">WCS(硬解)</label>
|
||
</div>
|
||
<div class="form-check col">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="useSIMD">
|
||
<label class="form-check-label" for="useSIMD">WASM(软解)</label>
|
||
</div>
|
||
</div>
|
||
<div class="buffer row mb-2 border-bottom px-3">
|
||
<div class="form-check col-6">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="networkDelayTimeoutReplay"
|
||
checked>
|
||
<label class="form-check-label" for="networkDelayTimeoutReplay">校时追帧</label>
|
||
</div>
|
||
<div class="form-check col-6">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="replayUseLastFrameShow"
|
||
checked>
|
||
<label class="form-check-label" for="replayUseLastFrameShow">重播使用上一帧</label>
|
||
</div>
|
||
<div class="form-check col">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="websocket1006ErrorReplay"
|
||
checked>
|
||
<label class="form-check-label" for="websocket1006ErrorReplay">WebSocket重连</label>
|
||
</div>
|
||
<div class="form-check col">
|
||
<input class="form-check-input" type="checkbox" role="switch" id="hasAudio" checked>
|
||
<label class="form-check-label" for="hasAudio">渲染音频</label>
|
||
</div>
|
||
</div>
|
||
<div class="mb-2 border-bottom">
|
||
<div class="form-group col-12 mb-2">
|
||
<label for="heartTimeout">超出时间无数据重连(s)</label>
|
||
<input type="text" class="form-control" id="heartTimeout" value="7" placeholder="如 3,5,7">
|
||
</div>
|
||
<div class="form-group col-12">
|
||
<label for="videoBufferDelay">达到延迟重播(s)</label>
|
||
<input type="text" class="form-control" id="videoBufferDelay" value="3"
|
||
placeholder="如 3,5,7">
|
||
</div>
|
||
<div class="form-group col-12">
|
||
<label for="fullscreenWatermarkConfig">水印</label>
|
||
<input type="text" class="form-control" id="fullscreenWatermarkConfig" value="EasyPlayer.js"
|
||
placeholder="如:3,5,7">
|
||
</div>
|
||
<div class="form-group col-12">
|
||
<label for="background">封面</label>
|
||
<input type="text" class="form-control" id="background" value=""
|
||
placeholder="如:https://xxx.png">
|
||
</div>
|
||
<div class="form-group col-12">
|
||
<label for="playHref">URL</label>
|
||
<input type="text" class="form-control" id="playHref"
|
||
value=""
|
||
placeholder="如:http://,https://,ws://,webrtc://">
|
||
</div>
|
||
</div>
|
||
<div class="mb-2 border-bottom">
|
||
<div>
|
||
<button type="button" class="btn btn-primary" id="play">播放</button>
|
||
<button type="button" class="btn btn-warning text-white" id="rePlay">重播</button>
|
||
<button type="button" class="btn btn-danger" id="destroy">销毁</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="mt-3">
|
||
<h5>介绍:</h5>
|
||
<div>1. 支持ws-flv, http-flv, hls, webrtc </div>
|
||
<div class="text-warning">2. WebRTC使用方式:webrtc://xxx </div>
|
||
<div>3. 使用时出现跨域请下载文件到本地调试</div>
|
||
<div>4. 当浏览器不支持 MSE硬解 时,会自动切换成 WASM软解</div>
|
||
<div>5. 关闭音频渲染可以节省性能</div>
|
||
<div>6. 支持 电子放大; </div>
|
||
<div>7. 支持 水印(动态水印、幽灵水印);</div>
|
||
<div>8. 支持 显示上一个视频最后一帧;</div>
|
||
<div>9. 支持 播放器快照截图;</div>
|
||
<div>10.支持 视频录制(WebM格式(音频+视频)、MP4格式(视频),FLV格式(音频+视频));</div>
|
||
<div>11.支持 超时、断网重连、异常暂停播放等;</div>
|
||
</div>
|
||
<div class="mt-3">
|
||
<h5>属性配置</h5>
|
||
<table class="table table-bordered">
|
||
<thead class="thead-light">
|
||
<tr>
|
||
<th>属性</th>
|
||
<th>说明</th>
|
||
<th>类型</th>
|
||
<th>默认值</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>container</td>
|
||
<td>播放器容器</td>
|
||
<td>-</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td>decoder</td>
|
||
<td>wasm解码地址</td>
|
||
<td>String</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td>isResize</td>
|
||
<td>是否拉伸</td>
|
||
<td>Boolean</td>
|
||
<td>true</td>
|
||
</tr>
|
||
<tr>
|
||
<td>loadingText</td>
|
||
<td>加载显示的文字</td>
|
||
<td>String</td>
|
||
<td>加载中</td>
|
||
</tr>
|
||
<tr>
|
||
<td>videoBuffer</td>
|
||
<td>设置最小缓冲时长,单位秒,播放器会自动消除延迟</td>
|
||
<td>Number</td>
|
||
<td>1</td>
|
||
</tr>
|
||
<tr>
|
||
<td>hasAudio</td>
|
||
<td>是否解析音频</td>
|
||
<td>Boolean</td>
|
||
<td>true</td>
|
||
</tr>
|
||
<tr>
|
||
<td>useMSE</td>
|
||
<td>MSE模式</td>
|
||
<td>Boolean</td>
|
||
<td>false</td>
|
||
</tr>
|
||
<tr>
|
||
<td>useWCS</td>
|
||
<td>WCS模式</td>
|
||
<td>Boolean</td>
|
||
<td>false</td>
|
||
</tr>
|
||
<tr>
|
||
<td>useSIMD</td>
|
||
<td>强制使用wasm模式</td>
|
||
<td>Boolean</td>
|
||
<td>false</td>
|
||
</tr>
|
||
<tr>
|
||
<td>background</td>
|
||
<td>视频封面图片</td>
|
||
<td>String</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td>qualityConfig</td>
|
||
<td>配置清晰度</td>
|
||
<td>Array</td>
|
||
<td>['普清', '高清', '超清', '4K', '8K']</td>
|
||
</tr>
|
||
<tr>
|
||
<td>defaultStreamQuality</td>
|
||
<td>默认显示的清晰度,如果不设置,会显示第一个清晰度</td>
|
||
<td>String</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td>isNotMute</td>
|
||
<td>是否渲染音频</td>
|
||
<td>Boolean</td>
|
||
<td>false</td>
|
||
</tr>
|
||
<tr>
|
||
<td>recordType</td>
|
||
<td>视频录制默认mp4格式</td>
|
||
<td>String</td>
|
||
<td>mp4, flv</td>
|
||
</tr>
|
||
<tr>
|
||
<td>playbackForwardMaxRateDecodeIFrame</td>
|
||
<td>录像倍数</td>
|
||
<td>Number</td>
|
||
<td>-</td>
|
||
</tr>
|
||
<tr>
|
||
<td>debug</td>
|
||
<td>控制台日志打印</td>
|
||
<td>Boolean</td>
|
||
<td>false</td>
|
||
</tr>
|
||
<tr>
|
||
<td>debugLevel</td>
|
||
<td>打印日志级别默认warn</td>
|
||
<td>String</td>
|
||
<td>debug, warn</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<h5>调用方法和事件回调</h5>
|
||
<table class="table table-bordered">
|
||
<thead class="thead-light">
|
||
<tr>
|
||
<th>方法/事件</th>
|
||
<th>说明</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>play</td>
|
||
<td>播放</td>
|
||
</tr>
|
||
<tr>
|
||
<td>playback</td>
|
||
<td>播放录像</td>
|
||
</tr>
|
||
<tr>
|
||
<td>pause</td>
|
||
<td>暂停播放</td>
|
||
</tr>
|
||
<tr>
|
||
<td>isPause</td>
|
||
<td>返回是否暂停中状态</td>
|
||
</tr>
|
||
<tr>
|
||
<td>setBufferTime</td>
|
||
<td>设置最大缓冲时长</td>
|
||
</tr>
|
||
<tr>
|
||
<td>setVolume</td>
|
||
<td>设置音量</td>
|
||
</tr>
|
||
<tr>
|
||
<td>getVolume</td>
|
||
<td>获取音量</td>
|
||
</tr>
|
||
<tr>
|
||
<td>exitFullscreen</td>
|
||
<td>退出全屏(取消全屏)播放视频</td>
|
||
</tr>
|
||
<tr>
|
||
<td>mute</td>
|
||
<td>静音</td>
|
||
</tr>
|
||
<tr>
|
||
<td>cancelMute</td>
|
||
<td>取消静音</td>
|
||
</tr>
|
||
<tr>
|
||
<td>isMute</td>
|
||
<td>返回是否静音</td>
|
||
</tr>
|
||
<tr>
|
||
<td>screenshot</td>
|
||
<td>获取快照</td>
|
||
</tr>
|
||
<tr>
|
||
<td>setFullscreen</td>
|
||
<td>全屏</td>
|
||
</tr>
|
||
<tr>
|
||
<td>setStreamQuality</td>
|
||
<td>设置分辨率,必须是qualityConfig里面的数据</td>
|
||
</tr>
|
||
<tr>
|
||
<td>forward</td>
|
||
<td>设置录像倍数</td>
|
||
</tr>
|
||
<tr>
|
||
<td>setPlaybackStartTime</td>
|
||
<td>设置录像跳转时间/s</td>
|
||
</tr>
|
||
<tr>
|
||
<td>getVideoInfo</td>
|
||
<td>获取视频信息</td>
|
||
</tr>
|
||
<tr>
|
||
<td>getAudioInfo</td>
|
||
<td>获取音频信息</td>
|
||
</tr>
|
||
<tr>
|
||
<td>destroy</td>
|
||
<td>关闭视频,释放底层资源</td>
|
||
</tr>
|
||
<tr>
|
||
<td>play</td>
|
||
<td>播放事件</td>
|
||
</tr>
|
||
<tr>
|
||
<td>pause</td>
|
||
<td>暂停事件</td>
|
||
</tr>
|
||
<tr>
|
||
<td>videoInfo</td>
|
||
<td>视频信息</td>
|
||
</tr>
|
||
<tr>
|
||
<td>audioInfo</td>
|
||
<td>音频信息</td>
|
||
</tr>
|
||
<tr>
|
||
<td>mute</td>
|
||
<td>音频事件</td>
|
||
</tr>
|
||
<tr>
|
||
<td>error</td>
|
||
<td>播放异常</td>
|
||
</tr>
|
||
<tr>
|
||
<td>kBps</td>
|
||
<td>当前网速,单位KB 每秒1次</td>
|
||
</tr>
|
||
<tr>
|
||
<td>recordEnd</td>
|
||
<td>录制结束的事件</td>
|
||
</tr>
|
||
<tr>
|
||
<td>recordStart</td>
|
||
<td>录制开始的事件</td>
|
||
</tr>
|
||
<tr>
|
||
<td>fullscreen</td>
|
||
<td>当前是否全屏</td>
|
||
</tr>
|
||
<tr>
|
||
<td>streamQualityChange</td>
|
||
<td>清晰度回调</td>
|
||
</tr>
|
||
<tr>
|
||
<td>playbackSeek</td>
|
||
<td>录像时间轴跳转回调</td>
|
||
</tr>
|
||
<tr>
|
||
<td>playbackPreRateChange</td>
|
||
<td>录像倍数的回调</td>
|
||
</tr>
|
||
<tr>
|
||
<td>currentPts</td>
|
||
<td>监听当前渲染帧的时间戳(流里面的)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
|
||
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
|
||
crossorigin="anonymous"></script>
|
||
<script>
|
||
var easypro;
|
||
var $player = document.getElementById('play');
|
||
var $destroy = document.getElementById('destroy');
|
||
var $rePlay = document.getElementById('rePlay');
|
||
var $playHref = document.getElementById('playHref');
|
||
var $container = document.querySelector('#video');
|
||
var $videoBufferDelay = document.querySelector('#videoBufferDelay');
|
||
var $useMSE = document.querySelector('#useMSE');
|
||
var $useWCS = document.querySelector('#useWCS');
|
||
var $useSIMD = document.querySelector('#useSIMD');
|
||
var $hasAudio = document.querySelector('#hasAudio');
|
||
var $isNakedFlow = document.querySelector('#isNakedFlow');
|
||
var $websocket1006ErrorReplay = document.querySelector('#websocket1006ErrorReplay');
|
||
var $networkDelayTimeoutReplay = document.querySelector('#networkDelayTimeoutReplay');
|
||
var $heartTimeout = document.querySelector('#heartTimeout');
|
||
var $replayUseLastFrameShow = document.querySelector('#replayUseLastFrameShow');
|
||
var $fullscreenWatermarkConfig = document.querySelector('#fullscreenWatermarkConfig');
|
||
var $background = document.querySelector('#background');
|
||
function create(options) {
|
||
options = options || {}
|
||
|
||
easypro = new EasyPlayerPro({
|
||
container: $container,
|
||
videoBuffer: 0.2, // 缓存时长
|
||
videoBufferDelay: Number($videoBufferDelay.value), // 1000s
|
||
decoder: './js/decoder-pro.js',
|
||
isResize: false,
|
||
text: "",
|
||
loadingText: "加载中", debug: true,
|
||
debugLevel: "debug",
|
||
useMSE: $useMSE.checked === true,
|
||
useSIMD: $useSIMD.checked === true,
|
||
useWCS: $useWCS.checked === true,
|
||
hasAudio: $hasAudio.checked === true,
|
||
websocket1006ErrorReplay: $websocket1006ErrorReplay.checked === true,
|
||
networkDelayTimeoutReplay: $networkDelayTimeoutReplay.checked === true,
|
||
useMThreading: true,
|
||
showBandwidth: true, // 显示网速
|
||
showPerformance: true, // 显示性能
|
||
operateBtns: {
|
||
fullscreen: true,
|
||
screenshot: true,
|
||
play: true,
|
||
audio: true,
|
||
ptz: true,
|
||
quality: true,
|
||
performance: true,
|
||
screenshotFn: screenshotFn,
|
||
},
|
||
background: $background.value,
|
||
timeout: 10,
|
||
qualityConfig: ['普清', '高清', '超清', '4K', '8K'],
|
||
forceNoOffscreen: true,
|
||
isNotMute: false,
|
||
heartTimeout: Number($heartTimeout.value),
|
||
ptzClickType: 'mouseDownAndUp',
|
||
ptzZoomShow: true,
|
||
ptzMoreArrowShow: true,
|
||
ptzApertureShow: true,
|
||
ptzFocusShow: true,
|
||
pauseAndNextPlayUseLastFrameShow: $replayUseLastFrameShow.checked === true,
|
||
heartTimeoutReplayUseLastFrameShow: $replayUseLastFrameShow.checked === true,
|
||
replayUseLastFrameShow: $replayUseLastFrameShow.checked === true, // 重播使用上一帧显示
|
||
fullscreenWatermarkConfig: {
|
||
text: $fullscreenWatermarkConfig.value,
|
||
}
|
||
});
|
||
}
|
||
|
||
const screenshotFn = () => {
|
||
if (easypro) {
|
||
easypro.screenshotWatermark({
|
||
text: {
|
||
content: `${$fullscreenWatermarkConfig.value}`,
|
||
fontSize: '46',
|
||
color: 'rgba(100,100,100,.6)',
|
||
},
|
||
opacity: 0.8,
|
||
right: 20,
|
||
top: 50,
|
||
});
|
||
}
|
||
};
|
||
|
||
create();
|
||
|
||
|
||
easypro.on('streamQualityChange', (value) => {
|
||
console.log('streamQualityChange', value);
|
||
})
|
||
|
||
easypro.on('timeUpdate', (value) => {
|
||
// console.log('timeUpdate', value);
|
||
})
|
||
|
||
easypro.on('stats', (stats) => {
|
||
// console.log('stats', stats);
|
||
})
|
||
|
||
easypro.on('error', (errorType, message) => {
|
||
console.error('error', errorType, message);
|
||
})
|
||
|
||
easypro.on('crashLog', (info) => {
|
||
console.error('crashLog', info);
|
||
})
|
||
|
||
easypro.on('playFailedAndPaused', (reason, lastFrameInfo, msg) => {
|
||
console.error('playFailedAndPaused', reason, lastFrameInfo, msg);
|
||
});
|
||
|
||
|
||
function play() {
|
||
var href = $playHref.value;
|
||
if (href) {
|
||
easypro.play(href);
|
||
} else {
|
||
easypro.showErrorMessageTips('播放地址不能为空');
|
||
}
|
||
}
|
||
|
||
|
||
function replay(options) {
|
||
if (easypro) {
|
||
easypro.destroy().then(() => {
|
||
create(options);
|
||
play();
|
||
});
|
||
} else {
|
||
create();
|
||
play();
|
||
}
|
||
}
|
||
|
||
$player.addEventListener('click', function () {
|
||
play();
|
||
}, false)
|
||
|
||
|
||
$destroy.addEventListener('click', function () {
|
||
if (easypro) {
|
||
easypro.destroy().then(() => {
|
||
create();
|
||
});
|
||
} else {
|
||
create();
|
||
}
|
||
|
||
})
|
||
|
||
$useMSE.addEventListener('change', function () {
|
||
replay();
|
||
})
|
||
|
||
$useSIMD.addEventListener('change', function () {
|
||
replay();
|
||
})
|
||
|
||
$useWCS.addEventListener('change', function () {
|
||
replay();
|
||
})
|
||
|
||
$hasAudio.addEventListener('change', function () {
|
||
replay();
|
||
})
|
||
|
||
|
||
$websocket1006ErrorReplay.addEventListener('change', function () {
|
||
replay();
|
||
})
|
||
|
||
$rePlay.addEventListener('click', function () {
|
||
replay();
|
||
})
|
||
$background.addEventListener('change', function () {
|
||
if (easypro) {
|
||
easypro.destroy().then(() => {
|
||
create();
|
||
});
|
||
} else {
|
||
create();
|
||
}
|
||
})
|
||
|
||
$networkDelayTimeoutReplay.addEventListener('change', function () {
|
||
replay();
|
||
})
|
||
</script>
|
||
</body>
|
||
|
||
</html> |