Динамическая предварительная загрузка / отображение снимков веб-камеры на веб-странице с помощью AJAX - PullRequest
0 голосов
/ 30 мая 2009

У меня есть IP-камера, которая транслирует видео в реальном времени на мой веб-сайт. Проблема в том, что он питается от элемента управления ActiveX. Еще хуже, этот элемент управления не подписан. Чтобы предоставить более безопасную альтернативу людям, использующим браузеры, отличные от IE, или (по праву) не желающие изменять свои настройки безопасности, я подключаюсь к встроенным в снимок сценариям моментальных снимков камер, которые подают живое изображение JPEG размером 640x480. План состоял в том, чтобы обновлять изображение в реальном времени на экране каждые ~ 500 мсек, используя Javascript, без необходимости перезагружать всю страницу.

Я пытался использовать объект Image () для предварительной загрузки изображения и обновления атрибута SRC элемента изображения при запуске onload:

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. Кроме того, событие загрузки не было надежным на 100%.

Поэтому я использую функцию jQuery (версия 1.2.6) ajax для выполнения запроса GET по URL-адресу, а при обратном вызове 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 голосов
/ 03 июня 2009

Что ж, в итоге я использовал схему URI данных (подсказка Эрику Паскарелло) для браузеров без IE. Я написал обработчик 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 и вернуть правильные коды состояния и т. Д. Я просто хотел найти самый простой выход из возможных, потому что мне надоело с этим сталкиваться!

Спасибо всем!

0 голосов
/ 31 мая 2009

Отправка второго ответа, потому что первый был просто действительно неправильным. Я не могу протестировать это решение (поскольку у меня нет доступа к сценарию вашей веб-камеры), но я бы посоветовал попытаться очистить ответ от камеры - поскольку вы, очевидно, не можете обрабатывать необработанные данные изображения, попробуйте добавить 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 использовать коды состояния без сбоев, как сумасшедший.

0 голосов
/ 02 июня 2009
img.onerror = function(){
    alert('offline');
}
0 голосов
/ 30 мая 2009

Я полагаю, что jquery попытается интерпретировать ответ от сервера. Я полагаю, что некоторые браузеры более терпимы к интерпретации ответов, поэтому более строгие браузеры не будут работать, потому что изображение не может быть отображено как HTML!

Решением этой проблемы будет использование типа запроса HEAD вместо GET (тип: "HEAD"). Таким образом, вы все равно будете получать ответы о состоянии, не захватывая само изображение. Поэтому ответ будет пустым (и не должен вас испортить). Кроме того, ответ должен быть намного быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...