📜 ⬆️ ⬇️

Creating a video broadcast on JS

Good day, dear habrachititel.
Today I will tell you how you can organize live broadcast of images from a webcam using HTML5 / JS and NodeJS, as well as PHP.

The article has a fairly large amount of code. Also, this article focuses more on beginner web developers than on professionals.

Client part

First you need to create an element of the type “video” to which the stream from navigator.getUserMedia will be copied, and also the canvas from which the image will be taken to send:

<video autoplay id="vid" style="display:none;"></video> <canvas id="canvas" width="640" height="480" style="border:1px solid #d3d3d3;"></canvas><br> 

')
Next, you need to send the stream from getUserMedia to video:

 var video = document.querySelector("#vid"), canvas = document.querySelector('#canvas'), ctx = canvas.getContext('2d'), localMediaStream = null, onCameraFail = function (e) { console.log('Camera did not work.', e); //   ,     }; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; window.URL = window.URL || window.webkitURL; navigator.getUserMedia({video: true}, function(stream) { video.src = window.URL.createObjectURL(stream); localMediaStream = stream; }, onCameraFail); 


Well, at this stage the video stream is cloned into the “video” tag, which by the way is not visible. Now we need to make the image constantly copied to canvas. To do this, set the timer, calling the copy procedure, and, accordingly, the copy procedure itself.

 cameraInterval = setInterval(function(){ snapshot();}, 1); function snapshot(){ if(localMediaStream){ ctx.drawImage(video, 0, 0); } } 


Well, now you can look at yourself, but the data is not sent anywhere. To send data, you need to make sure that what is happening is synchronous and that the user agrees to broadcast, so we will add a couple of buttons to enable and disable the stream.

 <button onclick="startBroadcasting()">Start Broadcasting</button> <button onclick="stopBroadcasting()">Stop Broadcasting</button> 


And write the procedure for sending data to the server.
But what kind of data? To solve this problem, you can use base64 compression of everything that is on the canvas, and, accordingly, send this string to the server.

 var isBroadcasting = false, broadcastingTimer; function sendSnapshot(){ if(localMediaStream && !isBroadcasting){ isBroadcasting = true; $.post("/", { p: "new", text: ctx.canvas.toDataURL("image/webp", quality); // quality -  (float) }, function(result){ console.log(result); //  ,  -    isBroadcasting = false; } ); } } //         function startBroadcasting(){ broadcastingTimer = setInterval(sendSnapshot, 1); } function stopBroadcasting(){ clearInterval(broadcastingTimer); } 


With the client part of the broadcast is over.

Server side (Node JS)

For such an application does not require any sophistication or server frameworks. The server is created using the http.createServer function.
The main thing here is to add a handler in case a post request arrives.

 var qs = require('querystring'); var imageData = ""; var myId = 1; /*   */ if(req.method == "POST"){ var fullBody = ""; req.on('data', function(chunk){ fullBody += chunk.toString(); }); req.on('end', function(){ res.writeHead(200, {'Content-Type': 'text/html'}); var POST = qs.parse(fullBody); if(POST["p"] == "new"){ //   imageData = POST["text"]; myId += 1; res.write(imageData); }else if(POST["p"] == "ajax"){ if(myId > parseInt(POST["last"])){ if(typeof(imageData) != "undefined"){ res.write(document.body.innerHTML = ('<img src=" + '"' + imageData + '"' + "/>');" + "\n"); res.write("last_message_id = " + myId + ";"); } } } res.end(); }); }else{ /*    ,   . */} 


Similarly with php:

Php code
 if($_GET['p'] == "ajax"){ Header("Cache-Control: no-cache, must-revalidate"); Header("Pragma: no-cache"); Header("Content-Type: text/javascript; charset=windows-1251"); $file = file("monitor_id.txt"); $id = $file[0]; if($id > $_GET['last']){ $text_file = file("monitor_command.txt"); $count = count($text_file); $last = $id; echo "var main = $('#main'); \n"; for($i = 0; $i < 1; $i++){ $s = $text_file[$i]; while(strpos($s, chr(92)) !== false){ $s = str_replace(chr(92), "", $s); } echo $s; } echo "\n"; echo "last_message_id = $id;"; } }elseif((isset($_GET['p']) && $_GET['p'] == "new") || (isset($_POST['p']))){ $file = file("monitor_id.txt"); $id = $file[0]; $fh = fopen("monitor_command.txt", "w+"); $get_text = $_POST['text']; $gt = $get_text; while(strpos($get_text, "\r\n") !== false){ $get_text = str_replace("\r\n", "</br>", $get_text); } fwrite($fh, "document.body.innerHTML = ('<img src=".'"'.".$get_text.'"'."/>);\n"); fclose($fh); $fhn = fopen("monitor_id.txt", "w+"); fwrite($fhn, $id + 1); fclose($fhn); echo $get_text; } 



Client part (view broadcast)

Oddly enough, the client part is very simple, it only requires the execution of the code coming from the server.
 var last_message_id = 0, load_in_process = false; function Load() { if(!load_in_process) { load_in_process = true; $.post("/", { p: "ajax", last: last_message_id, version: version }, function (result) { eval(result); load_in_process = false; }); } } var loadInterval = setInterval(Load, 1); 


Conclusion

Today we wrote a simple service for organizing one-way video broadcasts via html5 / js. It is worth noting that so far this solution does not work very quickly due to the lack of normal compression, as well as the fact that all image processing operations can be performed only on the client, and as a result the frame rate decreases and begins to be observed. hangs.

But this rather simple example is only proof that html5 is no longer so far from flash, and that the implementation of many things becomes possible.

Thanks for attention!

Source: https://habr.com/ru/post/172419/


All Articles