最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to detect when mjpeg stream stops with javascript - Stack Overflow

programmeradmin5浏览0评论

I have a html/javascript client that is listening to a mjpeg video stream:

myImg = document.getElementById('my-image');
myImg.src = '.mjpeg';

Works fine but if the video stream dies for whatever reason the video feed "freezes" on the last received image and I have no opportunity to display an error to the user. I've see this post that offers a solution (creating a long running ajax request alongside the stream) that only works some of the time. I was hoping there would be a more supported method like through a disconnect event or something.

Even an event for when data is received would be better than nothing. At least that way I could tell if it's been a while since a frame came through. Using addEventListener('load') only works on the very first frame.

Any ideas?

Update:

Based on ments I have tried the following approaches, none of which has worked:

myImg.addEventListener('error', event => { ... });
myImg.addEventListener('stalled', event => { ... });
myImg.addEventListener('suspend', event => { ... });

I have a html/javascript client that is listening to a mjpeg video stream:

myImg = document.getElementById('my-image');
myImg.src = 'http://myserver./camera.mjpeg';

Works fine but if the video stream dies for whatever reason the video feed "freezes" on the last received image and I have no opportunity to display an error to the user. I've see this post that offers a solution (creating a long running ajax request alongside the stream) that only works some of the time. I was hoping there would be a more supported method like through a disconnect event or something.

Even an event for when data is received would be better than nothing. At least that way I could tell if it's been a while since a frame came through. Using addEventListener('load') only works on the very first frame.

Any ideas?

Update:

Based on ments I have tried the following approaches, none of which has worked:

myImg.addEventListener('error', event => { ... });
myImg.addEventListener('stalled', event => { ... });
myImg.addEventListener('suspend', event => { ... });
Share Improve this question edited May 4, 2021 at 13:27 d512 asked Apr 21, 2021 at 22:30 d512d512 34.3k30 gold badges89 silver badges119 bronze badges 8
  • Does it emit an error event? myImg.addEventListener("error", () => {...});? – zero298 Commented Apr 21, 2021 at 22:34
  • @zero298 Unfortunately it does not – d512 Commented Apr 22, 2021 at 3:15
  • could your try to listen on stalled and suspend event one of them may work with your case – Joseph Commented Apr 30, 2021 at 16:50
  • @Joseph Thanks for the suggestion, unfortunately neither event seemed to fire. I tried myImg.addEventListener('stalled', event => { ... }); and myImg.addEventListener('suspend', event => { ... }); – d512 Commented Apr 30, 2021 at 20:52
  • 1 Have you ever tried to put in a video attribute <video> instead of the <img> ? Because there are several callback options when it is <video> – Hudson Moreira da Cunha Commented Apr 30, 2021 at 21:06
 |  Show 3 more ments

5 Answers 5

Reset to default 2

This is mon with a normal implementation of a mjpeg, for example

   <video src="http://myserver./camera.mjpeg" controls>
      Your browser does not support the <code>video</code> element.
   </video>

the mjpeg is a series of images and eventually it will not get the next one for whatever reason, breaking the connection. (this is sometimes because the source is cached, causing the browser to use the last image every time). I don't consider this an error, more something to program around with mjpeg streams.

A simple solution you can do, set a refresh rate and set the src continuously refreshing the connection every ~500ms (or less depending on your network connection/resources).

setInterval(function() {
    var myImg = document.getElementById('myImg');
    myImg.src = 'http://myserver./camera.mjpeg?rand=' + Math.random();
}, 5000);

The random number is added to prevent browser side caching in the event the server sends those headers.

Or you can create a ReadableStream, and keep reading a blob of bytes directly into the source of the image. There is a robust example in this repo, from this other question.

In Safari document.readyState will change from interactive to plete.

For example put this before the image loads:

  <script>
    console.log('Initial ready state', document.readyState);
    document.onreadystatechange = function() {
      console.log('Ready state changed to:', document.readyState);
    }
  </script>

And the output will be:

Initial ready state – "loading"
Ready state changed to: – "interactive"

// When the connection disconnects:
Ready state changed to: – "plete"

In google chrome the readyState doesn't stay on interactive, but it looks like chrome is better at reconnecting, so might not be an issue for you.

Edit: One way to make use of this is to drop the image in an iframe, you'll continually get load events in safari (this does not work in chrome).

iframe = document.createElement('iframe')
iframe.onload = console.log
iframe.src = "http://10.0.0.119:8080/stream"
document.body.append(iframe)

Edit2: Another technique -- use image.decode to detect when the connection is down and reload the image:

    <img id="stream" src="http://10.0.0.119:8080/stream"></img>
    <script>
      let image = document.getElementById('stream');

      async function check() {
        while (true) {
          try {
            await image.decode();
          } catch {
            let src = image.src;
            image.src = "";
            image.src = src;
          }
      
          await new Promise((resolve) => setTimeout(resolve, 5000));
        }
      }
      
      check();
    </script>

Would something like this work?

function hasLoaded(myImg) {
  return myImg.plete && myImg.naturalHeight !== 0;
}

Following Beau Bouchard answers.

  1. The setInterval timer, works fine but it tends to max out active client listening. ( if ur mjpeg stream are ing directly from an IP Camera). Could possibly create a restreaming server the mjpeg server to allow more clients to be able to be listening to it) Short pooling though does tend to be very resource heavy.

  2. Tried the Restream Api as well. When loading the image back into the img tag, you do get a jittery effect, most likely because the chunks are ing in randomly and not smooth out via time?

  3. In the end, i use the onload img tag event. This triggers whenever an img is loaded. Then a time interval to check if the img tag has stop loading to determine if the mjpeg stream has stop.

Met the same requirement, test on Image onload event and works!!

If FFMPEG feed FFSERVER stop, although the MJPEG in a still image,

After couple times error count, mjpeg FAIL! detected.

<!DOCTYPE HTML>
<HTML>
 <HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <TITLE> mjpeg detect </TITLE>
<script type="text/javascript" language="JavaScript" src="/js/jquery.js"></script>
<script type="text/javascript" language="JavaScript">
//------------------------------------------------------------------------------
// localhost/tool/mjpeg.htm
// document.ready
$(function(){
    setTimeout("mjpegRefresh()", 10000);
});

var mTmjpegRefresh, mBmjpegStatus=0, mNmjpegError=0;
var mjpegRefresh = function()
{
    clearTimeout(mTmjpegRefresh);
    mBmjpegStatus=0;
    $('#myMJPEG').attr('src', "http://192.168.1.17:8090/live.mjpeg?rand=" + Math.random()); 
    console.log("mjpeg refresh: ", Math.round( (new Date()).getTime()/1000)) ;
    mTmjpegRefresh = setTimeout("mjpegRefresh()", 10000);
    mTmjpegStatusCheck = setTimeout("mjpegStatusCheck()", 5000);
}

var mjpegOnload = function()
{
    console.log("mjpeg Onload");
    mBmjpegStatus=1;
}

var mTmjpegStatusCheck;
var mjpegStatusCheck = function()
{
    clearTimeout(mTmjpegStatusCheck);
    if(mBmjpegStatus>0)
    {
        mNmjpegError=0;
    }
    else
    {
        mNmjpegError++;
    }
    if(mNmjpegError>5)
    {
        console.log("mjpeg FAIL!");
    }
    mTmjpegStatusCheck = setTimeout("mjpegStatusCheck()", 5000);
}
//------------------------------------------------------------------------------
</script>
 </HEAD>

 <BODY>

<img src="http://192.168.1.17:8090/live.mjpeg" width="720" height="404" id="myMJPEG" onload="mjpegOnload()">

 </BODY>
</HTML>

发布评论

评论列表(0)

  1. 暂无评论