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

时间:2009-05-29 22:52:30

标签: javascript jquery ajax

我有一台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实际加载所请求的图像(通常它什么都不显示)。

4 个答案:

答案 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”)。这样你仍然可以获得状态响应,而无需抓取图像本身。因此响应将是空的(不应该搞砸你)。此外,响应应该更快。