我有一台IP摄像机,可将实时视频流式传输到我的网站。问题是,它由ActiveX控件提供支持。更糟糕的是,这种控制是无符号的。为了向使用IE以外的浏览器的人提供更安全的替代方案,或者(正当地)不愿意更改其安全设置,我正在使用快照脚本内置的摄像头,该脚本提供640x480的实时JPEG图像。计划是使用Javascript每隔~500ms在屏幕上实时更新图像,而无需重新加载整个页面。
我尝试使用Image()对象预加载图像并在onload触发时更新图像元素的SRC属性:
function updateCam() {
var url = "../snapshot.cgi?t=" + new Date().getTime();
img = new Image();
img.onload = function() {
$("#livePhoto").attr("src", url);
camTimer = setTimeout(updateCam, 500);
}
img.src = url;
}
这种方法运行得很好,但很难确定相机何时被禁用,我需要这样才能优雅地降级。内部快照脚本设置为在这种情况下返回HTTP状态代码204(无内容),当然我无法使用Image对象检测到它。此外,onload事件不是100%可靠。
因此,我使用jQuery(版本1.2.6)ajax
函数对URL执行GET请求,并在complete
回调中评估状态代码并相应地设置URL :
function updateCam() {
var url = "../snapshot.cgi?t=" + new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
complete: function(xhr) {
try {
var src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
$("#livePhoto").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
这很好用。 但仅限于IE!这是我想回答的问题:为什么这不适用于Firefox或Chrome? complete
事件甚至不会在Firefox中触发。它在Chrome中启动,但很少设置SRC实际加载所请求的图像(通常它什么都不显示)。
答案 0 :(得分:0)
发布第二个答案,因为第一个答案真的不对。我无法测试此解决方案(因为我无法访问您的网络摄像头脚本),但我建议尝试清理相机的响应 - 因为您显然无法处理原始图像数据,请尝试添加dataFilter设置如下:
function updateCam() {
var url = "../snapshopt.cgi?t=" + new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
dataFilter : function(data, type) {
return '<div></div>' //so it returns something...
},
complete: function(xhr) {
try {
var src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
$("#live").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
就像我说的那样,我无法对此进行测试 - 但它可能允许jquery使用状态代码而不会像疯了一样破坏。
答案 1 :(得分:0)
img.onerror = function(){
alert('offline');
}
答案 2 :(得分:0)
好吧,我最终对非IE浏览器使用了data URI scheme(对于Eric Pascarello来说)。我写了一个HTTP处理程序(在VB.NET中)来代理IP摄像机,base-64编码图像:
Imports Common
Imports System.IO
Imports System.Net
Public Class LiveCam
Implements IHttpHandler
Private ReadOnly URL As String = "http://12.34.56.78/snapshot.cgi"
Private ReadOnly FAIL As String = Common.MapPath("~/i/cam-oos.jpg")
Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
Dim Data As Byte()
With context.Response
.ContentEncoding = Encoding.UTF8
.ContentType = "text/plain"
.Write("data:image/png;base64,")
Try
Using Client As New WebClient()
Data = Client.DownloadData(URL)
End Using
Catch ex As WebException
Data = File.ReadAllBytes(FAIL)
End Try
.Write(Convert.ToBase64String(Data))
End With
End Sub
End Class
然后我只是进行了一点非IE检测(使用经典document.all检查),以便调用正确的URL /设置正确的SRC:
function updateCam() {
var url = (document.all) ? "../snapshot.cgi?t=" : "../cam.axd?t=";
url += new Date().getTime();
$.ajax({
type: "GET",
url: url,
timeout: 2000,
complete: function(xhr) {
try {
var src;
if(document.all)
src = (xhr.status == 200) ? url : '../i/cam-oos.jpg';
else
src = xhr.responseText;
$("#livePhoto").attr("src", src);
}
catch(e) {
JoshError.log(e);
}
camTimer = setTimeout(updateCam, 500);
}
});
}
非常不幸的是,我不得不采用这种解决方法。我讨厌浏览器检测代码,我讨厌在我的服务器上添加额外的负载。代理不仅会迫使我浪费更多的带宽,而且由于固有的代理缺陷以及base-64编码图像所需的时间,它将无法有效运行。此外,它没有设置为像IE一样优雅地降低 。虽然我可以重新编写代理以使用HttpWebRequest并返回正确的状态代码等等。我只想尽可能最简单的方法,因为我厌倦了处理这个问题!
感谢所有人!
答案 3 :(得分:-1)
我相信jquery会尝试解释服务器的响应。我相信一些浏览器更容忍响应解释,因此更严格的浏览器会失败,因为图像不能被视为HTML!
对此的解决方案是使用HEAD请求类型而不是GET(类型:“HEAD”)。这样你仍然可以获得状态响应,而无需抓取图像本身。因此响应将是空的(不应该搞砸你)。此外,响应应该更快。