Files
ipchub/demos/wsp/index.html
2024-11-29 08:13:10 +08:00

475 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RTSP player example(based streamedian)</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="sourcesNode"></div>
<div>
<input id="stream_url" value="rtsp://localhost:1554/test/live1" size="36">
<button id="set_new_url">Set</button>
<div class="custom-control custom-switch">
<input type="checkbox" id="continuous_recording">
<label class="custom-control-label" for="customSwitch1">Continuous recording</label>
</div>
<div>
<p style="color:#808080">Enter your rtsp link to the stream, for example: "rtsp://192.168.1.1:554/h264"</p>
</div>
<div>
<span style="color:#808080">Change video file length of the continuous recording</span>
<input id="continuous_file_length" type="range" min="10000" max="200000" value="180000" step="1000" style="width:40%;">
<p id="continuous_file_length_label">180sec.</p>
</div>
<div>
<span style="color:#808080">Change video file length of the event recording</span>
<input id="event_file_length" type="range" min="10000" max="200000" value="180000" step="1000" style="width:40%;">
<p id="event_file_length_label">180sec.</p>
</div>
<div>
<span style="color:#808080">Change buffer duration</span>
<input id="buffer_duration" type="range" min="10" max="200" style="width:40%;">
<p id="buffer_value">120sec.</p>
</div>
<canvas id="video_canvas" width="0" height="0"></canvas>
<video id="test_video" controls autoplay>
<!--<source src="rtsp://192.168.10.205:554/ch01.264" type="application/x-rtsp">-->
<!--<source src="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov" type="application/x-rtsp">-->
</video>
<div class="controls form">
<div>
Playback rate:&nbsp;
<input id="rate" class="input" type="range" min="0.5" max="5.0" value="1.0" step="0.5">
<output for="rate" id="rate_res">live</output>
</div>
<div>
<button id="to_end" class="btn btn-success" disabled>live</button>
<button id="event_recording" class="btn btn-success" disabled>Start recording</button>
</div>
</div>
<div>
<span style="color:#808080">Select a recorded file to playback</span>
<input id="file_input" type="file" accept=".mp4">
</div>
<p><br>Have any suggestions to improve our player? <br>Feel free to leave comments or ideas email: streamedian.player@gmail.com</p>
<p>View HTML5 RTSP video player log</p>
<div id="pllogs" class="logs"></div>
<button class="btn btn-success" onclick="cleanLog(pllogs)">clear</button>
<button class="btn btn-success" onclick="scrollset(pllogs, true)">scroll up</button>
<button class="btn btn-success" onclick="scrollset(pllogs, false)">scroll down</button>
<button id="scrollSetPl" class="btn btn-success" onclick="scrollswitch(pllogs)">Scroll off</button>
<button class="btn btn-success" onclick="statisticRequest('GET_INFO')">Get statistic</button>
<button class="btn btn-success" onclick="statisticRequest('SUBSCRIBE')">Subscribe statistic</button>
<br/><br/>
<b>How to use the player in the global network</b>
<p>
With an empty license file, you can only watch the stream on your computer locally (intranet).<br/>
If you would like to stream into the global network please take a key to activate the license.<br/>
You have personal 1 month validity key in the personal cabinet.<br/>
To activate key, please, use the activation application that is placed:
</p>
<p>
<b>Windows:</b> C:\Program Files\Streamedian\WS RTSP Proxy Server\activation_app<br/>
<b>Mac OS:</b> /Library/Application Support/Streamedian/WS RTSP Proxy Server/activation_app<br/>
<b>Linux (Ubunty, Debian, Centos, Fedora ):</b> /usr/bin/wsp/activation_app<br/>
</p>
<p>For more information go to <a href="https://streamedian.com/docs/">documentation</a></p>
<script src="libde265.js"></script>
<script src="free.player.3.3.js"></script>
<script>
var scrollStatPl = true;
var scrollStatWs = true;
var pllogs = document.getElementById("pllogs");
var wslogs = document.getElementById("wslogs");
// define a new console
var console=(function(oldConsole){
return {
log: function(){
oldConsole.log(newConsole(arguments, "black", "#A9F5A9"));
},
info: function () {
oldConsole.info(newConsole(arguments, "black", "#A9F5A9"));
},
warn: function () {
oldConsole.warn(newConsole(arguments, "black", "#F3F781"));
},
error: function () {
oldConsole.error(newConsole(arguments, "black", "#F5A9A9"));
}
};
}(window.console));
function newConsole(args, textColor, backColor){
let text = '';
let node = document.createElement("div");
for (let arg in args){
text +=' ' + args[arg];
}
node.appendChild(document.createTextNode(text));
node.style.color = textColor;
node.style.backgroundColor = backColor;
pllogs.appendChild(node);
autoscroll(pllogs);
return text;
}
//Then redefine the old console
window.console = console;
function cleanLog(element){
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
function autoscroll(element){
if(scrollStatus(element)){
element.scrollTop = element.scrollHeight;
}
if(element.childElementCount > 1000){
element.removeChild(element.firstChild);
}
}
function scrollset(element, state){
if(state){
element.scrollTop = 0;
scrollChange(element, false);
} else {
element.scrollTop = element.scrollHeight;
scrollChange(element, true);
}
}
function scrollswitch(element){
if(scrollStatus(element)){
scrollChange(element, false);
} else {
scrollChange(element, true);
}
}
function scrollChange(element, status){
if(scrollStatus(element)){
scrollStatPl = false;
document.getElementById("scrollSetPl").innerText = "Scroll on";
} else {
scrollStatPl = true;
document.getElementById("scrollSetPl").innerText = "Scroll off";
}
}
function scrollStatus(element){
if(element.id === "pllogs"){
return scrollStatPl;
} else {
return scrollStatWs;
}
}
</script>
<script>
if (window.Streamedian) {
let errHandler = function(err){
// alert(err.message);
};
let infHandler = function(inf) {
let sourcesNode = document.getElementById("sourcesNode");
let clients = inf.clients;
sourcesNode.innerHTML = "";
for (let client in clients) {
clients[client].forEach((sources) => {
let nodeButton = document.createElement("button");
nodeButton.setAttribute('data', sources.url + ' ' + client);
nodeButton.appendChild(document.createTextNode(sources.description));
nodeButton.onclick = (event)=> {
setPlayerSource(event.target.getAttribute('data'));
};
sourcesNode.appendChild(nodeButton);
});
}
};
var link = document.createElement('a');
let dataHandler = function(data, prefix) {
let blob = new Blob([data], {type: "application/mp4"});
link.href = window.URL.createObjectURL(blob);
link.download = `${prefix}_${formatDate(new Date())}.mp4`;
link.click();
}
let formatHandler = function (format) {
if (html5Player && html5Canvas) {
if (format === 'h265') {
html5Player.setAttribute('hidden', true);
html5Canvas.removeAttribute('hidden');
} else if (format === 'h264') {
html5Player.removeAttribute('hidden');
html5Canvas.setAttribute('hidden', true);
}
}
}
function formatDate(dateObj) {
let month = String(dateObj.getMonth() + 1).padStart(2, '0');
let date = String(dateObj.getDate()).padStart(2, '0');
let hours = String(dateObj.getHours()).padStart(2, '0');
let minutes = String(dateObj.getMinutes()).padStart(2, '0');
let seconds = String(dateObj.getSeconds()).padStart(2, '0');
return`${dateObj.getFullYear()}-${month}-${date} ${hours}:${minutes}:${seconds}`;
}
var playerOptions = {
socket: "ws://localhost:8088/streams/",
redirectNativeMediaErrors : true,
bufferDuration: 30,
errorHandler: errHandler,
infoHandler: infHandler,
dataHandler: dataHandler,
videoFormatHandler: formatHandler,
continuousFileLength: 180000,
eventFileLength: 10000,
canvas: 'video_canvas',
};
var html5Player = document.getElementById("test_video");
var html5Canvas = document.getElementById("video_canvas");
var urlButton = document.getElementById("set_new_url");
var urlEdit = document.getElementById("stream_url");
var bufferRange = document.getElementById("buffer_duration");
var bufferValue = document.getElementById("buffer_value");
var continuousRecording = document.getElementById("continuous_recording");
var eventRecording = document.getElementById("event_recording");
var continuousFileLength = document.getElementById("continuous_file_length");
var continuousFileLengthLabel = document.getElementById("continuous_file_length_label");
var eventFileLength = document.getElementById("event_file_length");
var eventFileLengthLabel = document.getElementById("event_file_length_label");
var player = Streamedian.player('test_video', playerOptions);
var nativePlayer = document.getElementById('test_video');
var range = document.getElementById('rate');
var set_live = document.getElementById('to_end');
var range_out = document.getElementById('rate_res');
var socket;
var keepAliveTimer;
var password = btoa('streamedian');
range.addEventListener('input', function () {
nativePlayer.playbackRate = range.value;
range_out.innerHTML = `x${range.value}`;
});
set_live.addEventListener('click', function () {
range.value = 1.0;
range_out.innerHTML = `live`;
nativePlayer.playbackRate = 1;
nativePlayer.currentTime = nativePlayer.buffered.end(0);
});
// Tab switching and window minimization processing
// for browsers that use the chrome rendering engine.
if (!!window.chrome) {
document.addEventListener('visibilitychange', function() {
if(document.visibilityState === 'hidden') {
nativePlayer.pause()
} else {
nativePlayer.play();
// Automatic jump to buffer end for view live video when returning to the web page.
setTimeout(function() {
nativePlayer.currentTime = nativePlayer.buffered.end(0)
}, 3000); // Delay for a few seconds is required for the player has time to update the timeline.
}
});
}
var updateRangeControls = function(){
bufferRange.value = player.bufferDuration;
bufferValue.innerHTML = bufferRange.value + "sec.";
continuousFileLength.value = player.continuousRecording.fileLength;
continuousFileLengthLabel.innerText = `${continuousFileLength.value / 1000} sec.`;
eventFileLength.value = player.eventRecording.fileLength;
event_file_length_label.innerText = `${eventFileLength.value / 1000} sec.`;
};
bufferRange.addEventListener('input', function(){
var iValue = parseInt(this.value, 10);
player.bufferDuration = iValue;
bufferValue.innerHTML = this.value + "sec.";
});
bufferRange.innerHTML = player.bufferDuration + "sec.";
updateRangeControls();
continuousRecording.addEventListener('change', function(event) {
player.continuousRecording.record(event.target.checked);
continuousFileLength.disabled = event.target.checked;
});
eventRecording.addEventListener('click', function(event) {
let state = !event.target.classList.contains('btn-recording');
player.eventRecording.record(state);
event.target.classList.toggle('btn-success');
event.target.classList.toggle('btn-recording');
event.target.innerText = state ? 'Stop recording': 'Start recording';
eventFileLength.disabled = state;
});
continuousFileLength.addEventListener('input', function(event) {
let milliseconds = parseInt(event.target.value, 10);
player.continuousRecording.fileLength = milliseconds;
continuousFileLengthLabel.innerText = `${milliseconds / 1000} sec.`;
});
eventFileLength.addEventListener('input', function(event) {
let milliseconds = parseInt(event.target.value, 10);
player.eventRecording.fileLength = milliseconds;
eventFileLengthLabel.innerText = `${milliseconds / 1000} sec.`;
});
urlButton.onclick = ()=> {
setPlayerSource(urlEdit.value);
};
function setPlayerSource(newSource) {
player.destroy();
player = null;
html5Player.src = newSource;
// 修改原例子 begn =======>
// 我们直接使用ws来决定播放的路径
// 比如ws://192.168.1.100:1554/streams/test/live1
// 表示要播放服务器上路径为/test/live1
// 如果播放失败,可能是以下情况(1和2发生在升级websocket阶段3发生在rtsp通讯阶段)
// 1. 如果服务器rtsp的验证模式不为NONE则需要登录后获取到token才能访问像这样ws://.../test/live1?token=...
// 2. 可能没有权限,需要联系人对你登录的用户授权
// 3. 可能找不到流媒体
//
// 如果不是使用例子,我们可以这样
// html5Player.src = "rtsp://placehold"
// playerOptions.socket ="ws://localhost:1554/streams/test/live1"
// 知道ws主机后实际上只需要提供流媒体path即可这也更好
//
let rtspUrl = new URL(newSource)
rtspUrl.protocol = "ws"
rtspUrl.pathname = "/streams"+rtspUrl.pathname
playerOptions.socket = rtspUrl.href
// <========= end
player = Streamedian.player("test_video", playerOptions);
player.continuousRecording.record(continuousRecording.checked);
updateRangeControls();
eventRecording.removeAttribute('disabled');
set_live.removeAttribute('disabled');
}
file_input.addEventListener('change', function(event) {
html5Player.src = URL.createObjectURL(event.target.files[0]);
});
window.addEventListener('unload', function() {
player.continuousRecording.record(false);
player.eventRecording.record(false);
});
function statisticRequest(cmd) {
if (socket == undefined || socket.readyState != 1) {
socket = new WebSocket(playerOptions.socket, "statistic");
socket.onmessage = onStatistic;
socket.onopen = function() {
socket.send(`WSP/1.1 ${cmd}\nAuthorization: ${password}\nseq: 1\n\n`);
keepAliveTimer = setInterval(()=>{
socket.send(`WSP/1.1 KEEPALIVE\nAuthorization: ${password}\nseq: 1\n\n`);
}, 30000); // Every 30 seconds
}
socket.onclose = function() {
clearInterval(keepAliveTimer);
}
} else {
socket.send(`WSP/1.1 ${cmd}\nAuthorization: ${password}\nseq: 1\n\n`);
}
}
function onStatistic(msg) {
if (msg.data.length) {
let data = msg.data.split('\r\n\r\n');
if (data.length > 1) {
parseStatistic(JSON.parse(data[1]));
} else {
console.log("------------- Info -------------");
parseSession(JSON.parse(data[0]));
}
}
};
function parseSession(session) {
console.log(`Requested domain: ${session.user.requestedDomain}`);
console.log(`User address: ${session.user.address}`);
console.log(`RTSP address: ${session.rtsp.host}:${session.rtsp.port}`);
console.log(`Session start time: ${new Date(Number(session.connectionTime + '000'))}`);
if (session.disconnectionTime) {
console.log(`Session end time: ${new Date(Number(session.disconnectionTime + '000'))}`);
}
console.log('---');
}
function parseStatistic(data) {
for (let i = 0; i < data.licenses.length; i++) {
let license = data.licenses[i].license;
let sessions = data.licenses[i].sessions;
let sessionNumber = data.licenses[i].sessionNumber;
console.log("------------- Info -------------");
console.log(' License ' + i);
console.log(`Activation Key: ${license.key}`)
console.log(`Expires: ${license.expiresAt}`);
console.log(`License max posible watchers: ${license.maxWatchers}`);
if (license.maxWatchers !== 'unlimited') {
console.log(`Remain watchers: ${license.maxWatchers - sessionNumber}`);
}
console.log('Sessions:');
for (let j = 0; j < sessions.length; j++) {
parseSession(sessions[j]);
}
}
}
function getStatistic() {
statisticRequest('GET_INFO', password);
socket.onmessage = statisticInfoParse;
}
function subscribeStatistic() {
statisticRequest('SUBSCRIBE', password);
}
}
</script>
</body>
</html>