Rendering MJpeg stream in html5

2020-02-01 05:06发布

问题:

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.

回答1:

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:pass@127.0.0.1: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



回答2:

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.



回答3:

If you stream source can't return frames on another address (http://[some ip]:[port]/frame/XXX) then you can use MJPEG stream parser on the server. For example, Paparazzo.js parse stream and return single jpeg. Actually it returns only last frame without saving previous, but it can be changed.

Problem can't be solved only in browser with js without some plugins and server.