add displaying video stream using sse

This commit is contained in:
Sem van der Hoeven
2023-05-31 21:03:40 +02:00
parent bdcdb19d96
commit df8f391c9f
3 changed files with 69 additions and 83 deletions

View File

@@ -18,12 +18,29 @@ var ws;
var api_connected = false; var api_connected = false;
function send_events_to_clients(data) { function send_events_to_clients(data) {
// console.log("sending events to clients"); // console.log("sending events to clients");
sse_clients.forEach((client) => { sse_clients.forEach((client) => {
client.response.write("event: message\n"); client.response.write("event: message\n");
client.response.write("data:" + JSON.stringify(data) + "\n\n") client.response.write("data:" + JSON.stringify(data) + "\n\n");
} });
); }
function send_image_data_to_clients(frameData) {
sse_clients.forEach((client) => {
// Create a Blob from the frame data
const blob = new Blob([frameData], { type: "image/jpeg" });
// Set the SSE event name as 'message'
client.response.write("event: message\n");
// Create an object URL from the Blob
const objectURL = URL.createObjectURL(blob);
// Set the SSE event data as the object URL
client.response.write(
"data: " + JSON.stringify({ image: objectURL }) + "\n\n"
);
});
} }
function handle_sse_client(request, response, next) { function handle_sse_client(request, response, next) {
@@ -50,25 +67,6 @@ function handle_sse_client(request, response, next) {
}); });
} }
const getSizeInBytes = obj => {
let str = null;
if (typeof obj === 'string') {
// If obj is a string, then use it
str = obj;
} else {
// Else, make obj into a string
str = JSON.stringify(obj);
}
// Get the length of the Uint8Array
const bytes = new TextEncoder().encode(str).length;
return bytes;
};
const logSizeInBytes = (description, obj) => {
const bytes = getSizeInBytes(obj);
console.log(`${description} is approximately ${bytes} B`);
};
var connect_to_api = function () { var connect_to_api = function () {
console.log("Connecting to API"); console.log("Connecting to API");
ws = new WebSocket("ws://10.100.0.40:9001/"); ws = new WebSocket("ws://10.100.0.40:9001/");
@@ -80,15 +78,15 @@ var connect_to_api = function () {
ws.on("message", function message(message) { ws.on("message", function message(message) {
try { try {
var msg = JSON.parse(message); var msg = JSON.parse(message);
if (msg.type != "IMAGE") { if (msg.type != "IMAGE") {
send_events_to_clients(msg); send_events_to_clients(msg);
} else { } else {
console.log("got image"); console.log("got image");
} }
} catch (error) { } catch (error) {
console.log("could not parse as json, must be bytes"); console.log("could not parse as json, must be bytes");
send_image_data_to_clients(message);
} }
}); });

View File

@@ -14,7 +14,7 @@
<div class="video"> <div class="video">
<div class="mainvideo"> <div class="mainvideo">
<p>Camera view:</p> <p>Camera view:</p>
<canvas id="msg" width="960" height="720" style="display: inline-block; border: 1px solid blue;"></canvas> <img id="msg" style="border: 1px solid blue; width: 960px;"></img>
<div id="connectedbuttons"> <div id="connectedbuttons">
<div id="connectedstatus"> <div id="connectedstatus">
<p id="connectedlabel">Connected: <%- api_connected %></p> <p id="connectedlabel">Connected: <%- api_connected %></p>
@@ -59,7 +59,7 @@
</body> </body>
<script> <script>
// var update_status = setInterval(update_status, 1000); var update_status = setInterval(update_status, 1000);
assign_button_callbacks(); assign_button_callbacks();
window.onload = function () { window.onload = function () {
const events = new EventSource("/events"); const events = new EventSource("/events");
@@ -69,10 +69,19 @@
} }
events.onmessage = (event) => { events.onmessage = (event) => {
//TODO handling status, failsafe etc console.log("MESSAGE RECEIVED");
const parsedData = JSON.parse(event.data); const eventData = JSON.parse(event.data);
console.log("RECEIVED EVENT");
console.log(parsedData); // Check if the event contains image data
if (eventData.image) {
const imageURL = eventData.image;
// Process the received image URL
// For example, you can set it as the source of an <img> element
const imgElement = document.getElementById('image-element');
imgElement.src = imageURL;
}
// console.log(parsedData);
} }
}; };
@@ -183,51 +192,29 @@
} }
function connect() { function connect() {
console.log("connect"); var received = false;
socket = new WebSocket("ws://10.0.100.40:9001/"); var xhr = new XMLHttpRequest();
let msg = document.getElementById("msg"); xhr.open("GET", "/connect", true);
socket.addEventListener('open', (e) => { xhr.onreadystatechange = function () {
console.log("open"); if (this.status == 200) {
}); console.log(this.responseText);
socket.addEventListener('message', (e) => { if (this.responseText.length > 0) {
let ctx = msg.getContext("2d"); var status = JSON.parse(this.responseText);
let image = new Image(); // console.log(status)
image.src = URL.createObjectURL(e.data); document.getElementById("connectedlabel").innerHTML = "Connected: true";
image.addEventListener("load", (e) => { document.getElementById("connectbutton").disabled = true;
ctx.drawImage(image, 0, 0, msg.width, msg.height); }
}); } else {
}); console.log("error");
document.getElementById("connectedlabel").innerHTML = "Connected: false";
if (!received) {
alert("Could not connect to API!");
received = true;
// ws.on("error", function error(err) { }
// console.log("there was an error"); }
// console.error("error: " + err); };
// received_error = true; xhr.send();
// });
// var received = false;
// var xhr = new XMLHttpRequest();
// xhr.open("GET", "/connect", true);
// xhr.onreadystatechange = function () {
// if (this.status == 200) {
// console.log(this.responseText);
// if (this.responseText.length > 0) {
// var status = JSON.parse(this.responseText);
// // console.log(status)
// document.getElementById("connectedlabel").innerHTML = "Connected: true";
// document.getElementById("connectbutton").disabled = true;
// }
// } else {
// console.log("error");
// document.getElementById("connectedlabel").innerHTML = "Connected: false";
// if (!received)
// {
// alert("Could not connect to API!");
// received = true;
// }
// }
// };
// xhr.send();
} }
// window onload function die elke seconde een request doet om te kijken of er al nieuwe foto is // window onload function die elke seconde een request doet om te kijken of er al nieuwe foto is
// function die elke 100 ms een request doet om de status te updaten // function die elke 100 ms een request doet om de status te updaten

View File

@@ -103,6 +103,7 @@ class ApiListener(Node):
frame = cv2.resize(frame,(640,480)) frame = cv2.resize(frame,(640,480))
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 65] encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 65]
man = cv2.imencode('.jpg', frame, encode_param)[1] man = cv2.imencode('.jpg', frame, encode_param)[1]
self.get_logger().info('Sending video')
self.message_queue.append(man.tobytes()) self.message_queue.append(man.tobytes())
except Exception as e: except Exception as e: