Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering MJpeg stream in html5

I'm trying to render MJpeg stream in HTML5 using the img tag. When I'm running the following, everything works great, meaning, the video starts to play until the video ends:

<img src="http://[some ip]:[port]/mjpg">

My question is how can I get the stream frame by frame. For each frame, I want to get it, do something (ajax call to the server) and then display the frame as an image.

Thanks.

like image 746
Lior Ohana Avatar asked Oct 13 '13 15:10

Lior Ohana


2 Answers

You can do this without repeatedly making Http requests. Only one will suffice. You can use the fetch api to create a ReadableStream, access it's Reader and keep reading from the stream.

Once you have the reader keep reading chunks from the stream recursively. Look for the SOI ( 0xFF 0xD8) in the byte stream which signals the end of the header and the beginning of the JPEG frame. The header will contain the length of the JPEG in bytes to be read. Read that many bytes from the chunk and any successive chunks and store it into a Uint8Array. Once you've successfully read the frame convert it into a blob, create a UrlObject out of it and assign it to the src property of your img object.

Keep doing this till the connection is closed.

Shameless plug. Here's a link to a working sample on github.

like image 175
arun tom Avatar answered Sep 23 '22 23:09

arun tom


If the camera exposes raw JPEG images (not .MJPEG extension) you'll have to reaload it manually (if the extension is .MJPEG the browser will do everything, just put the correct src). If you have .MJPEG and want to use the raw .JPEG check your camera documentation. Most cameras expose both the .MJPEG and raw .JPEG streams (just on different URLs).

Unfortunately you won't be able to easily get the image through ajax, but you could change the src of the image periodically.

You can use Date.getTime() and add it to the querystring to force the browser to reload the image, and repeat each time the image loads.

If you use jQuery the code will look something like this:

camera.html

<!DOCTYPE html>
<html>

<head>
    <title>ipCam</title>
</head>

<body>
    <h1>ipCam</h1>
    <img id="motionjpeg" src="http://user:[email protected]:8080/" />
    <script src="motionjpeg.js"></script>
    <script>
        //Using jQuery for simplicity

        $(document).ready(function() {
            motionjpeg("#motionjpeg"); // Use the function on the image
        });
    </script>
</body>

</html>

motionjpeg.js

function motionjpeg(id) {
    var image = $(id), src;

    if (!image.length) return;

    src = image.attr("src");
    if (src.indexOf("?") < 0) {
        image.attr("src", src + "?"); // must have querystring
    }

    image.on("load", function() {
        // this cause the load event to be called "recursively"
        this.src = this.src.replace(/\?[^\n]*$/, "?") +
            (new Date()).getTime(); // 'this' refers to the image
    });
}

Note that my example will play the MotionJPEG on page load, but won't allow play/pause/stop functionalities

like image 4
Zorgatone Avatar answered Sep 24 '22 23:09

Zorgatone