|
|
@ -12,11 +12,20 @@
|
|
|
|
.streams {
|
|
|
|
.streams {
|
|
|
|
display: flex;
|
|
|
|
display: flex;
|
|
|
|
justify-content: center;
|
|
|
|
justify-content: center;
|
|
|
|
background: #ddd;
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.streams img {
|
|
|
|
.streams img {
|
|
|
|
margin: 50px;
|
|
|
|
|
|
|
|
outline: 1px solid #000;
|
|
|
|
outline: 1px solid #000;
|
|
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
|
|
height: 450px;
|
|
|
|
|
|
|
|
background: #ddd;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.stream-2 {
|
|
|
|
|
|
|
|
mix-blend-mode: darken;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.stats {
|
|
|
|
.stats {
|
|
|
|
display: flex;
|
|
|
|
display: flex;
|
|
|
@ -24,21 +33,30 @@
|
|
|
|
width: 100%;
|
|
|
|
width: 100%;
|
|
|
|
margin-top: 20px;
|
|
|
|
margin-top: 20px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.connect-info {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<body>
|
|
|
|
<h1>Stream Web App</h1>
|
|
|
|
<h1>Stream Web App</h1>
|
|
|
|
<button onclick="connect()">Connect</button>
|
|
|
|
<div class="connect-info">
|
|
|
|
<input type="text" placeholder="Enter the WebSocket URL" />
|
|
|
|
<input type="text" placeholder="Enter the WebSocket URL" />
|
|
|
|
<div class="streams">
|
|
|
|
<button onclick="connect()">Connect</button>
|
|
|
|
<img class="stream-1" src="" alt="Original Stream">
|
|
|
|
<button onclick="disconnect()">Disconnect</button>
|
|
|
|
<img class="stream-2" src="" alt="Masked Stream">
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="stats">
|
|
|
|
<div class="stats">
|
|
|
|
<h4>Messages received: <label class="message-count">0</label></h4>
|
|
|
|
<h4>Messages received: <label class="message-count">0</label></h4>
|
|
|
|
<h4>FPS: <label class="fps">0</label></h4>
|
|
|
|
<h4>FPS: <label class="fps">0</label></h4>
|
|
|
|
<h4>Total MB received: <label class="total-mb">0</label></h4>
|
|
|
|
<h4>Total MB received: <label class="total-mb">0</label></h4>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="streams">
|
|
|
|
|
|
|
|
<img class="stream-1" src="" alt="Stream">
|
|
|
|
|
|
|
|
<img class="stream-2" src="" alt="">
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<script>
|
|
|
|
<script>
|
|
|
|
let websocketUrl = 'ws://localhost:9001';
|
|
|
|
let websocketUrl = 'ws://localhost:9001';
|
|
|
|
let ws;
|
|
|
|
let ws;
|
|
|
@ -51,7 +69,16 @@
|
|
|
|
let lastFpsUpdateTime = 0;
|
|
|
|
let lastFpsUpdateTime = 0;
|
|
|
|
let totalBytesReceived = 0;
|
|
|
|
let totalBytesReceived = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const disconnect = () => {
|
|
|
|
|
|
|
|
if (ws) {
|
|
|
|
|
|
|
|
ws.close();
|
|
|
|
|
|
|
|
ws = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const connect = () => {
|
|
|
|
const connect = () => {
|
|
|
|
|
|
|
|
disconnect();
|
|
|
|
|
|
|
|
|
|
|
|
websocketUrl = input.value;
|
|
|
|
websocketUrl = input.value;
|
|
|
|
console.log('Connecting to the server...', websocketUrl);
|
|
|
|
console.log('Connecting to the server...', websocketUrl);
|
|
|
|
ws = new WebSocket(websocketUrl);
|
|
|
|
ws = new WebSocket(websocketUrl);
|
|
|
@ -74,21 +101,34 @@
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const arrayBuffer = await blob.arrayBuffer();
|
|
|
|
const arrayBuffer = await blob.arrayBuffer();
|
|
|
|
const dataView = new DataView(arrayBuffer);
|
|
|
|
const dataView = new DataView(arrayBuffer);
|
|
|
|
const type = dataView.getUint8(0);
|
|
|
|
const originalSize = dataView.getUint32(0, true);
|
|
|
|
const size = dataView.getUint32(1, true);
|
|
|
|
const maskedSize = dataView.getUint32(4, true);
|
|
|
|
const imageData = arrayBuffer.slice(5, 5 + size);
|
|
|
|
|
|
|
|
const imageBlob = new Blob([imageData], { type: 'image/jpeg' });
|
|
|
|
const originalImageData = arrayBuffer.slice(8, 8 + originalSize);
|
|
|
|
const imageUrl = URL.createObjectURL(imageBlob);
|
|
|
|
const maskedImageData = arrayBuffer.slice(8 + originalSize, 8 + originalSize + maskedSize);
|
|
|
|
const streamElement = document.querySelector(type === 0 ? '.stream-1' : '.stream-2');
|
|
|
|
|
|
|
|
streamElement.onload = () => {
|
|
|
|
const originalImageBlob = new Blob([originalImageData], { type: 'image/jpeg' });
|
|
|
|
URL.revokeObjectURL(streamElement.src); // Clean up the old object URL
|
|
|
|
const maskedImageBlob = new Blob([maskedImageData], { type: 'image/jpeg' });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const originalImageUrl = URL.createObjectURL(originalImageBlob);
|
|
|
|
|
|
|
|
const maskedImageUrl = URL.createObjectURL(maskedImageBlob);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const originalStreamElement = document.querySelector('.stream-1');
|
|
|
|
|
|
|
|
const maskedStreamElement = document.querySelector('.stream-2');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
originalStreamElement.onload = () => {
|
|
|
|
|
|
|
|
URL.revokeObjectURL(originalStreamElement.src);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
streamElement.src = imageUrl;
|
|
|
|
maskedStreamElement.onload = () => {
|
|
|
|
|
|
|
|
URL.revokeObjectURL(maskedStreamElement.src);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
originalStreamElement.src = originalImageUrl;
|
|
|
|
|
|
|
|
maskedStreamElement.src = maskedImageUrl;
|
|
|
|
|
|
|
|
|
|
|
|
// Update total MB received
|
|
|
|
// Update total MB received
|
|
|
|
totalBytesReceived += arrayBuffer.byteLength;
|
|
|
|
totalBytesReceived += arrayBuffer.byteLength;
|
|
|
|
totalMBElement.textContent = (totalBytesReceived / (1024 * 1024)).toFixed(2);
|
|
|
|
totalMBElement.textContent = (totalBytesReceived / (1024 * 1024)).toFixed(2);
|
|
|
|
|
|
|
|
|
|
|
|
updateFPS();
|
|
|
|
updateFPS();
|
|
|
|
} catch (error) {
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Error processing message:', error);
|
|
|
|
console.error('Error processing message:', error);
|
|
|
|