Потоковая передача локального видео в формате jpg на холст html

Я пытаюсь записать прямой эфир видео mjpg на холст html.

Следующее: http://camelive.info/ содержит список общедоступных веб-камер с видео в формате mjpeg, но они кажутся пишу теги ‹ frameset > с элементами фрейма, и я не могу понять, как это работает на скрипке.

В идеальном решении есть любой живой mjpg (в идеале ссылка?), Который транслируется на холсте html в скрипке.

Любые полезные ресурсы приветствуются, я хотел бы сделать это без включения внешних библиотек (разрешен jquery)

Изменить: Связано: Как сделать снимок из потока MJPEG в HTML

Редактировать: у меня тоже есть локальный mjpg, как в примере. Решение может использовать локальный поток


person mattyd    schedule 21.03.2016    source источник
comment
Не уверен, что это поможет, но вы должны проверить этот пример   -  person Bhavik    schedule 21.03.2016
comment
Глядя на это сейчас, я думаю, что это правильная идея. Я попытаюсь на мгновение подключить предварительную скрипку   -  person mattyd    schedule 21.03.2016
comment
По спецификациям нельзя. Некоторые браузеры с ошибками, такие как Chrome, позволят вам это сделать, но это ошибка. Canvas drawImage рисует только первый кадр анимированного «img».   -  person Kaiido    schedule 22.03.2016
comment
Да, в итоге я обновил image src новым изображением с добавленной строкой даты (кеширование браузера), а затем повторно отрендерил холст   -  person mattyd    schedule 22.03.2016


Ответы (2)


Согласно спецификациям о методе CanvasRenderingContext2D drawImage,

В частности, когда объект CanvasImageSource представляет анимированное изображение в HTMLImageElement, пользовательский агент должен использовать изображение анимации по умолчанию (то, которое определяет формат, должно использоваться когда анимация не поддерживается или отключена) или, если такого изображения нет, первый кадр анимации при рендеринге изображения для CanvasRenderingContext2D API.

Это относится к файлам .gif, SMIL-анимациям .svg и .mjpeg. Поэтому, как только вы получили данные, на холсте должен быть отрисован только один кадр.

Обратите внимание, что в Chrome есть ошибка, и учитывайте ее только для .gif изображения, но когда-нибудь они могут это исправить.

Одно из решений, как вы сами заметили, состоит в том, чтобы получить другой свежий кадр с помощью хака очистки кеша ('your.url/?' + new Date().getTime();), но вы потеряете все преимущества формата mjpeg (частичное содержимое кадра) и не можете быть уверены, когда произойдет обновление .

Таким образом, лучшим решением, если это применимо, было бы использование формата видео. Каждый кадр видео можно нарисовать на холсте.


Редактировать 2018


Третье решение пришло мне в голову два года спустя:

Пользовательские агенты не привязаны к тому, чтобы хранить в памяти одно и то же изображение по умолчанию для всех 2DContexts в документе.
В то время как для других форматов мы все еще немного застряли, для потоков MJPEG, которые не имеют хорошо определенное изображение по умолчанию, мы фактически попадаем в первый кадр анимации.

Таким образом, рисуя <img>, содержащий наш поток MJPEG, на двух разных холстах в разное время, мы теоретически можем получить два разных кадра одного и того же потока MJPEG, которые будут отрисованы на холстах.

Вот доказательство концепции, проверенное только на Firefox 62.

var ctx_stream = stream.getContext('2d');
var ctx_direct = direct.getContext('2d');
img.onload = function() {
   stream.width = direct.width = this.naturalWidth;
   stream.height = direct.height = this.naturalHeight;
   // onload should fire multiple times
   // but it seems it's not at every frames
   // so we'll disable t and use an interval instead
   this.onload = null;
   setInterval(draw, 500);
};
function draw() {
  // create a *new* 2DContext
  var ctx_off = stream.cloneNode().getContext('2d');
  ctx_off.drawImage(img, 0,0);
  // and draw it back to our visible one
  ctx_stream.drawImage(ctx_off.canvas, 0,0);
  
  // draw the img directly on 'direct'
  ctx_direct.drawImage(img, 0,0);
}
  
  
img.src = "http://webcam.st-malo.com/axis-cgi/mjpg/video.cgi?resolution=704x576&dummy=1491717369754";
canvas,img{
  max-height: 75vh;
}
Using a new offcreen canvas every frame: <br><canvas id="stream"></canvas><br>
The original image: <br><img id="img"><br>
Drawing directly the &lt;img> (if this works your browser doesn't follow the specs): <br><canvas id="direct"></canvas><br>

Таким образом, хотя это решение, очевидно, повлияет на производительность (мы создаем совершенно новый элемент холста и его 2DContext в каждом кадре), оно все же, вероятно, лучше, чем переполнение сети. И все это в любом случае должно легко собираться мусором.

person Kaiido    schedule 22.03.2016
comment
Привет, Кайидо. Новая дата для URL-адреса img была лучшим решением. !! - person mattyd; 30.03.2016
comment
@Kaiido Гениальный ответ! Большое спасибо за это решение! Будьте здоровы! - person MM PP; 01.09.2018

Многие существующие IP-камеры mjpeg фактически отправляют отдельные файлы jpeg с предопределенной частотой кадров, которые при частом обновлении выглядят как видео.

Вам нужно проверить API производителя вашей камеры на предмет правильного URL-адреса для получения потока изображения, например, с камерой Foscam. Я сделал следующее раньше, и она отлично работает:

<img id='videostream' src="http://123.456.789.233:8080/videostream.cgi">

Очевидно, вам нужно будет получить правильный IP-адрес и номер порта камеры (если он существует).

ОБНОВЛЕНИЕ. Это не означает, что у вас не может быть других доступных методов потоковой передачи видео в реальном времени, это всего лишь самый простой из известных мне способов получения видео в реальном времени с IP-камеры.

ОБНОВЛЕНИЕ 2. Также у некоторых камер есть имя пользователя и пароль, поэтому вам, вероятно, придется добавить их к URL-адресу videostream.cgi?user=your_user&password=your_password

Надеюсь это поможет.

person dev7    schedule 21.03.2016
comment
@mattyd, в зависимости от API вашей камеры, может автоматически обновлять изображение при использовании videostream.cgi, в частности, у Foscam также есть snapshot.cgi, который возвращает одно изображение, и тогда вам придется использовать вызов setTimeout, чтобы обновить его вручную. - person dev7; 21.03.2016