【问题标题】:Dynamically Preloading/Displaying Webcam Snapshots on a Web Page Using AJAX使用 AJAX 在网页上动态预加载/显示网络摄像头快照
【发布时间】:2009-05-29 22:52:30
【问题描述】:

我有一台 IP 摄像机,可以将实时视频流式传输到我的网站。问题是,它是由 ActiveX 控件驱动的。更糟糕的是,这个控件是无符号的。为了向使用 IE 以外的浏览器或(理所当然地)不愿更改其安全设置的人们提供更安全的替代方案,我正在利用内置快照脚本的相机,该脚本提供 640x480 实时 JPEG 图像。计划是使用 Javascript 每约 500 毫秒更新一次屏幕上的实时图像,而无需重新加载整个页面。

我尝试使用 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;
}

这工作得很好,但很难确定相机何时被禁用,我需要这样做才能优雅地降级。在这种情况下,内部快照脚本设置为返回 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 实际加载请求的图像(通常它不显示任何内容)。

【问题讨论】:

  • 根本就没有调用回调吗?或者它只是不起作用?
  • 检查问题的最后一段。

标签: javascript jquery ajax


【解决方案1】:

发布第二个答案,因为第一个确实不正确。我无法测试此解决方案(因为我无权访问您的网络摄像头脚本),但我建议您尝试清理来自摄像头的响应 - 因为您显然无法处理原始图像数据,请尝试添加 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 使用状态代码而不会像疯了一样打破。

【讨论】:

  • 不走运 :( 一切都在 Internet Explorer 中完美运行。我可能会尝试编写一个代理来包装 CGI 脚本并将图像作为 base-64 编码在 XML 中返回。真是个 PITA。
  • 确实,多么痛苦,恐怕我没有想法 - 显然可能存在与 javascript 无关的潜在问题。网络摄像头没有实现完整的 HTTP(翻白眼)这一事实可能无济于事。
  • 不知道实现完整 HTTP 是什么意思。它很好地实现了它。无论如何,我可以很容易地编写一个代理来返回我想要的任何 HTTP。不幸的是,这仍然不能解决问题。
【解决方案2】:
img.onerror = function(){
    alert('offline');
}

【讨论】:

  • 谢谢埃里克。我真的需要评估状态码,因为它也可能是 304。我需要对这些做出不同的反应。另外,如上所述,onload 事件是不可靠的。它并不总是火。我不想做一个 setInterval 来使更新频率取决于连接速度,所以我在加载事件(调用被调用者)中做了一个超时。如果 onload 由于任何原因从未触发,则更新停止。你能看出我的 AJAX 方法在 Firefox 中失败的原因吗?
  • 是否会像添加另一个 QS 值这样强制它获取它。自从您使用 Ajax 调用调用它后,它可能会将其视为已缓存? var src = (xhr.status == 200) ? url + "&foo=bar" : '../i/cam-oos.jpg';
  • 我的错,我误解了你的评论。我会尝试这样做,但在 Firefox 中根本不会触发“完成”回调。一次都没有。甚至可以尝试,这不是消除了预加载的全部意义吗?如果我不需要预加载,我就直接设置图像标签的 SRC。再次感谢您帮助我!我被难住了,这甚至都不好笑。
【解决方案3】:

好吧,我最终在非 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 一样优雅地降级 as。虽然我可以重新编写代理以使用 HttpWebRequest 并返回正确的状态码等。我只是想要尽可能简单的方法,因为我厌倦了处理这个!

谢谢大家!

【讨论】:

    【解决方案4】:

    我相信 jquery 会尝试解释来自服务器的响应。我相信一些浏览器对响应解释更宽容,所以限制性更强的浏览器会失败,因为图像不能被视为 HTML!

    解决方案是使用 HEAD 请求类型而不是 GET(类型:“HEAD”)。这样,您仍将获得状态响应,而无需获取图像本身。因此响应将是空的(不应该把你搞砸)。此外,响应速度应该更快。

    【讨论】:

    • 使用 HEAD 的响应速度更快,但它是 404!
    • 网络摄像头脚本是自定义 HTTP 实现吗?
    • 不,它内置在网络摄像机的内部服务器中,我无法修改它。我可以编写自己的代理,但这并不能解决任何问题。
    猜你喜欢
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多