Javascript 使用AJAX在网页上动态预加载/显示网络摄像头快照

Javascript 使用AJAX在网页上动态预加载/显示网络摄像头快照,javascript,jquery,ajax,Javascript,Jquery,Ajax,我有一个IP摄像头,可以将实时视频流到我的网站上。问题是,它是由ActiveX控件驱动的。更糟糕的是,此控件没有签名。为了给那些使用IE以外浏览器的人提供一个更安全的选择,或者(理所当然地)不愿意更改他们的安全设置,我正在使用摄像头内置的快照脚本,该脚本提供640x480实时JPEG图像。计划是使用Javascript每隔500毫秒在屏幕上实时更新一次图像,而不必重新加载整个页面 我尝试使用Image()对象预加载图像,并在启动onload时更新Image元素的SRC属性: function u

我有一个IP摄像头,可以将实时视频流到我的网站上。问题是,它是由ActiveX控件驱动的。更糟糕的是,此控件没有签名。为了给那些使用IE以外浏览器的人提供一个更安全的选择,或者(理所当然地)不愿意更改他们的安全设置,我正在使用摄像头内置的快照脚本,该脚本提供640x480实时JPEG图像。计划是使用Javascript每隔500毫秒在屏幕上实时更新一次图像,而不必重新加载整个页面

我尝试使用Image()对象预加载图像,并在启动onload时更新Image元素的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;
}
这工作正常,但很难确定相机何时被禁用,我需要这样做才能优雅地降级。内部快照脚本被设置为在这种情况下返回204(无内容)的HTTP状态代码,当然,我无法使用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实际上很少加载请求的图像(通常不显示任何内容)。

我相信jquery会尝试解释服务器的响应。我相信一些浏览器更能容忍响应解释,所以更严格的浏览器会失败,因为图像不能被视为HTML


解决方案是使用HEAD请求类型而不是GET(类型:“HEAD”)。这样,您仍然可以获得状态响应,而无需抓取图像本身。因此,响应将是空的(不应该把您搞砸)。而且,回复应该快得多。

发布第二个答案,因为第一个答案确实不正确。我无法测试此解决方案(因为我无法访问您的网络摄像头脚本),但我建议尝试清理摄像头的响应-因为您显然无法处理原始图像数据,请尝试添加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);
    }
  });
}
函数updateCam(){
var url=“../snapshopt.cgi?t=“+new Date().getTime();
$.ajax({
键入:“获取”,
url:url,
超时时间:2000,
dataFilter:函数(数据,类型){
return“”//因此它会返回一些内容。。。
},
完成:函数(xhr){
试一试{
var src=(xhr.status==200)?url:“../i/cam oos.jpg”;
$(“#live”).attr(“src”,src);
}
捕获(e){
JoshError.log(e);
}
camTimer=设置超时(updateCam,500);
}
});
}

就像我说的,我还没能测试这个-但它可能允许jquery使用状态码而不会像疯了一样崩溃。

好吧,我最终使用了(Eric Pascarello的帽子提示)来测试非IE浏览器。我编写了一个HTTP处理程序(在VB.NET中)来代理IP摄像头并对图像进行base-64编码:

img.onerror = function(){
    alert('offline');
}
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检测(使用classic 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并返回正确的状态代码,等等。我只是想要尽可能最简单的方法,因为我厌倦了处理这个问题


谢谢大家

使用HEAD给了我更快的响应,但它是404!网络摄像头脚本是自定义HTTP实现吗?不,它内置于IP Cam的内部服务器中,我无法修改它。我可以编写自己的代理,但这解决不了任何问题。回调根本就不会被调用吗?或者它只是不起作用?检查问题的最后一段。运气不好:(在Internet Explorer中,一切都运行得很好。我可能会尝试编写一个代理来包装CGI脚本,并以XML中的base-64编码返回图像。这是一个多么令人头疼的问题啊,我担心我当时没有主意了——显然可能存在一个与javascript无关的潜在问题。这可能是因为至少,网络摄像头没有实现完整的HTTP(转眼)。不确定实现完整HTTP是什么意思。它实现得很好。无论如何,我可以很容易地编写一个代理来返回我想要的任何HTTP。不幸的是,这仍然不能解决问题。谢谢Eric。我确实需要评估状态代码,因为它也可能是304。我需要以不同的方式对这些代码作出反应。另外,一个如前所述,onload事件不可靠。它并不总是触发。我不想设置一个setInterval,以使更新频率取决于连接速度,因此我在load事件(调用被调用方)内执行超时。如果onload由于任何原因从未触发,更新将停止。您能看到我的AJAX方法在Firefox中失败的任何原因吗?是否需要添加另一个QS值来强制它获取它。可能它将它视为缓存,因为您使用AJAX调用调用了它?var src=(xhr.status==200)?url+“&foo=bar”:“../i/cam oos.jpg”;糟糕,我误解了你的评论。我会尝试这样做,但在Fir中根本不会触发“完整”回调