如何检测 mjpeg 流何时停止 javascript
How to detect when mjpeg stream stops with javascript
我有一个正在收听 mjpeg 视频流的 html/javascript 客户端:
myImg = document.getElementById('my-image');
myImg.src = 'http://myserver.com/camera.mjpeg';
工作正常,但如果视频流由于某种原因终止,视频源将“冻结”在最后接收到的图像上,我没有机会向用户显示错误。我看到 this post 提供的解决方案(在流旁边创建一个长 运行 ajax 请求)仅在某些时候有效。我希望有一个更受支持的方法,比如通过 disconnect
事件或其他方法。
即使接收到数据的事件也总比没有好。至少这样我可以判断帧通过是否已经有一段时间了。使用 addEventListener('load')
仅适用于第一帧。
有什么想法吗?
更新:
根据评论,我尝试了以下方法,none 有效:
myImg.addEventListener('error', event => { ... });
myImg.addEventListener('stalled', event => { ... });
myImg.addEventListener('suspend', event => { ... });
这样的东西行得通吗?
function hasLoaded(myImg) {
return myImg.complete && myImg.naturalHeight !== 0;
}
这在 mjpeg
的正常实现中很常见,例如
<video src="http://myserver.com/camera.mjpeg" controls>
Your browser does not support the <code>video</code> element.
</video>
mjpeg 是一系列图像,最终无论出于何种原因它都不会获取下一个图像,从而断开连接。 (这有时是因为源被缓存,导致浏览器每次都使用上一张图片)。我不认为这是一个错误,更多的东西可以用 mjpeg 流来编程。
你可以做一个简单的解决方案,设置刷新率并设置 src 每 ~500 毫秒(或更短时间取决于你的网络 connection/resources)连续刷新连接。
setInterval(function() {
var myImg = document.getElementById('myImg');
myImg.src = 'http://myserver.com/camera.mjpeg?rand=' + Math.random();
}, 5000);
添加随机数是为了防止在服务器发送 headers.
时浏览器端缓存
或者您可以创建 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。
正在关注 Beau Bouchard 的回答。
setInterval 计时器工作正常,但它往往会最大化主动客户端侦听。 (如果您的 mjpeg 流直接来自网络摄像机)。可能会在 mjpeg 服务器上创建一个重新流式传输服务器,以允许更多客户端能够收听它)短池虽然往往会占用大量资源。
也尝试了重新播放 Api。将图像加载回 img 标签时,确实会出现抖动效果,这很可能是因为块是随机进入的,并且不会随着时间的推移而平滑?
最后,我使用了onload img标签事件。每当加载 img 时都会触发。然后一个时间间隔检查img标签是否停止加载来判断mjpeg流是否停止。
在 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>
满足同样的要求,测试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>
我有一个正在收听 mjpeg 视频流的 html/javascript 客户端:
myImg = document.getElementById('my-image');
myImg.src = 'http://myserver.com/camera.mjpeg';
工作正常,但如果视频流由于某种原因终止,视频源将“冻结”在最后接收到的图像上,我没有机会向用户显示错误。我看到 this post 提供的解决方案(在流旁边创建一个长 运行 ajax 请求)仅在某些时候有效。我希望有一个更受支持的方法,比如通过 disconnect
事件或其他方法。
即使接收到数据的事件也总比没有好。至少这样我可以判断帧通过是否已经有一段时间了。使用 addEventListener('load')
仅适用于第一帧。
有什么想法吗?
更新:
根据评论,我尝试了以下方法,none 有效:
myImg.addEventListener('error', event => { ... });
myImg.addEventListener('stalled', event => { ... });
myImg.addEventListener('suspend', event => { ... });
这样的东西行得通吗?
function hasLoaded(myImg) {
return myImg.complete && myImg.naturalHeight !== 0;
}
这在 mjpeg
的正常实现中很常见,例如
<video src="http://myserver.com/camera.mjpeg" controls>
Your browser does not support the <code>video</code> element.
</video>
mjpeg 是一系列图像,最终无论出于何种原因它都不会获取下一个图像,从而断开连接。 (这有时是因为源被缓存,导致浏览器每次都使用上一张图片)。我不认为这是一个错误,更多的东西可以用 mjpeg 流来编程。
你可以做一个简单的解决方案,设置刷新率并设置 src 每 ~500 毫秒(或更短时间取决于你的网络 connection/resources)连续刷新连接。
setInterval(function() {
var myImg = document.getElementById('myImg');
myImg.src = 'http://myserver.com/camera.mjpeg?rand=' + Math.random();
}, 5000);
添加随机数是为了防止在服务器发送 headers.
时浏览器端缓存或者您可以创建 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。
正在关注 Beau Bouchard 的回答。
setInterval 计时器工作正常,但它往往会最大化主动客户端侦听。 (如果您的 mjpeg 流直接来自网络摄像机)。可能会在 mjpeg 服务器上创建一个重新流式传输服务器,以允许更多客户端能够收听它)短池虽然往往会占用大量资源。
也尝试了重新播放 Api。将图像加载回 img 标签时,确实会出现抖动效果,这很可能是因为块是随机进入的,并且不会随着时间的推移而平滑?
最后,我使用了onload img标签事件。每当加载 img 时都会触发。然后一个时间间隔检查img标签是否停止加载来判断mjpeg流是否停止。
在 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>
满足同样的要求,测试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>