Files
EasyPlayerJs/html-demo/demo.html

568 lines
22 KiB
HTML
Raw Normal View History

2024-08-01 16:32:01 +08:00
<!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="如 357">
</div>
<div class="form-group col-12">
<label for="videoBufferDelay">达到延迟重播(s)</label>
<input type="text" class="form-control" id="videoBufferDelay" value="3"
placeholder="如 357">
</div>
<div class="form-group col-12">
<label for="fullscreenWatermarkConfig">水印</label>
<input type="text" class="form-control" id="fullscreenWatermarkConfig" value="EasyPlayer.js"
placeholder="如357">
</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>