【问题标题】:How to detect when mjpeg stream stops with javascript如何检测 mjpeg 流何时停止使用 javascript
【发布时间】:2021-04-21 22:30:21
【问题描述】:

我有一个正在监听 mjpeg 视频流的 html/javascript 客户端:

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

工作正常,但如果视频流因任何原因而死,视频源“冻结”在最后接收到的图像上,我没有机会向用户显示错误。我看到this post 提供了一个解决方案(在流旁边创建一个长时间运行的ajax 请求),它只在某些时候有效。我希望有一种更受支持的方法,例如通过disconnect 事件或其他方式。

即使是接收数据时的事件也总比没有好。至少这样我就可以判断它是否已经有一段时间了,因为框架出现了。使用addEventListener('load') 仅适用于第一帧。

有什么想法吗?

更新:

基于 cmets 我尝试了以下方法,但都没有奏效:

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

【问题讨论】:

  • 它会发出error 事件吗? myImg.addEventListener("error", () => {...});?
  • @zero298 不幸的是它没有
  • 您是否可以尝试收听stalledsuspend 事件其中之一可能适用于您的情况
  • @Joseph 感谢您的建议,不幸的是,这两个事件似乎都没有触发。我试过myImg.addEventListener('stalled', event => { ... });myImg.addEventListener('suspend', event => { ... });
  • 您是否尝试过放入视频属性 的时候有几个回调选项

标签: javascript mjpeg


【解决方案1】:

这在mjpeg 的正常实现中很常见,例如

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

mjpeg 是一系列图像,最终无论出于何种原因它都无法获取下一个图像,从而中断了连接。 (这有时是因为源被缓存了,导致浏览器每次都使用最后一张图片)。我不认为这是一个错误,更多的是使用 mjpeg 流进行编程。

您可以做一个简单的解决方案,设置刷新率并设置 src 每隔约 500 毫秒(或更少,具体取决于您的网络连接/资源)不断刷新连接。

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

添加随机数是为了防止在服务器发送这些标头时浏览器端缓存。

或者您可以创建一个ReadableStream,并继续将一个字节块直接读取到图像源中。 this repo 中有一个可靠的示例,来自 this other question

【讨论】:

    【解决方案2】:

    这样的东西有用吗?

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

    【讨论】:

    • 我不这么认为。 complete 属性保持不变,truenaturalHeight 即使在 Feed 停止后也保持不变。
    【解决方案3】:

    按照 Beau Bouchard 的回答。

    1. setInterval 计时器可以正常工作,但它往往会最大化活跃的客户端监听。 (如果您的 mjpeg 流直接来自 IP 摄像机)。可能会在 mjpeg 服务器上创建一个重新流式传输服务器,以允许更多客户端能够收听它)虽然短池确实往往会占用大量资源。

    2. 也尝试了 Restream Api。将图像加载回 img 标签时,确实会出现抖动效果,这很可能是因为块是随机进入的,并且不会随着时间的推移而平滑?

    3. 最后,我使用了 onload img 标签事件。每当加载 img 时都会触发。然后是检查img标签是否停止加载的时间间隔,以确定mjpeg流是否停止。

    【讨论】:

    • 请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。
    【解决方案4】:

    在 Safari 中 document.readyState 将从交互变为完成。

    例如在图片加载之前放置这个:

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

    输出将是:

    Initial ready state – "loading"
    Ready state changed to: – "interactive"
    
    // When the connection disconnects:
    Ready state changed to: – "complete"
    

    在 google chrome 中,readyState 不会保持交互状态,但看起来 chrome 更擅长重新连接,因此对您来说可能不是问题。

    编辑:使用此功能的一种方法是将图像放入 iframe 中,您将在 safari 中不断收到加载事件(这在 chrome 中不起作用)。

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

    Edit2:另一种技术——使用image.decode 检测连接何时断开并重新加载图像:

        <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>
    

    【讨论】:

      【解决方案5】:

      满足同样的要求,在 Image onload 事件上测试并且可以工作!!

      如果 FFMPEG feed FFSERVER 停止,虽然 MJPEG 在静止图像中,

      经过几次错误计数后,检测到mjpeg FAIL!

      <!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>
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-21
        • 2020-04-29
        • 2013-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-09
        • 1970-01-01
        相关资源
        最近更新 更多