parent
c3f5f11d11
commit
5532b45bbb
@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Stream Web App</title>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.streams {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background: #ddd;
|
||||
}
|
||||
.streams img {
|
||||
margin: 50px;
|
||||
outline: 1px solid #000;
|
||||
}
|
||||
.stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Stream Web App</h1>
|
||||
<button onclick="connect()">Connect</button>
|
||||
<input type="text" placeholder="Enter the WebSocket URL" />
|
||||
<div class="streams">
|
||||
<img class="stream-1" src="" alt="Original Stream">
|
||||
<img class="stream-2" src="" alt="Masked Stream">
|
||||
</div>
|
||||
<div class="stats">
|
||||
<h4>Messages received: <label class="message-count">0</label></h4>
|
||||
<h4>FPS: <label class="fps">0</label></h4>
|
||||
</div>
|
||||
<script>
|
||||
let websocketUrl = 'ws://localhost:9001';
|
||||
let ws;
|
||||
const input = document.querySelector('input');
|
||||
input.value = websocketUrl;
|
||||
const messageCountElement = document.querySelector('.message-count');
|
||||
const fpsElement = document.querySelector('.fps');
|
||||
|
||||
let frameTimestamps = [];
|
||||
let lastFpsUpdateTime = 0;
|
||||
|
||||
const connect = () => {
|
||||
websocketUrl = input.value;
|
||||
console.log('Connecting to the server...', websocketUrl);
|
||||
ws = new WebSocket(websocketUrl);
|
||||
ws.onopen = () => {
|
||||
console.log('Connected to the server');
|
||||
requestFrame();
|
||||
};
|
||||
ws.onmessage = (message) => {
|
||||
messageCountElement.textContent = Number(messageCountElement.textContent) + 1;
|
||||
handleMessage(message.data);
|
||||
};
|
||||
ws.onclose = () => {
|
||||
console.log('Disconnected from the server');
|
||||
};
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
};
|
||||
};
|
||||
|
||||
const handleMessage = async (blob) => {
|
||||
try {
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
const dataView = new DataView(arrayBuffer);
|
||||
const type = dataView.getUint8(0);
|
||||
const size = dataView.getUint32(1, true); // true for little-endian
|
||||
const imageData = arrayBuffer.slice(5, 5 + size);
|
||||
const imageBlob = new Blob([imageData], { type: 'image/jpeg' });
|
||||
const imageUrl = URL.createObjectURL(imageBlob);
|
||||
const streamElement = document.querySelector(type === 0 ? '.stream-1' : '.stream-2');
|
||||
streamElement.onload = () => {
|
||||
URL.revokeObjectURL(streamElement.src); // Clean up the old object URL
|
||||
};
|
||||
streamElement.src = imageUrl;
|
||||
|
||||
updateFPS();
|
||||
// requestFrame();
|
||||
} catch (error) {
|
||||
console.error('Error processing message:', error);
|
||||
// requestFrame();
|
||||
}
|
||||
};
|
||||
|
||||
// const requestFrame = () => {
|
||||
// if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
// ws.send('Next frame');
|
||||
// }
|
||||
// };
|
||||
|
||||
const updateFPS = () => {
|
||||
const now = performance.now();
|
||||
frameTimestamps.push(now);
|
||||
|
||||
// Keep only the last 30 frame timestamps
|
||||
if (frameTimestamps.length > 30) {
|
||||
frameTimestamps.shift();
|
||||
}
|
||||
|
||||
// Update FPS
|
||||
if (now - lastFpsUpdateTime > 100) {
|
||||
const timeElapsed = (frameTimestamps[frameTimestamps.length - 1] - frameTimestamps[0]) / 1000; // in seconds
|
||||
const fps = (frameTimestamps.length - 1) / timeElapsed;
|
||||
fpsElement.textContent = fps.toFixed(2);
|
||||
lastFpsUpdateTime = now;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in new issue