Вывод видео с нескольких web-камер на одной странице

Вывод видео с нескольких web-камер на одной странице

Как-то раз я приуныл, делать ничего не хотелось, и тут я вспомнил, что в детстве мне сильно хотелось иметь пульт видео наблюдения, как у какого-то злодея из кино, который сидит в темной комнате и хохочет, наблюдая за беспомощными людишками, которые пытаются найти выход. Ну и освежив свои детские воспоминания, я решил воплотить их в жизнь, ну ту часть с пультом наблюдения, без людишек. И тут моим другом стал шагающий семимильными шагами HTML5, а если точнее Stream API. Так как я раньше уже использовал getUserMedia для захвата звука с микрофона, я подумал, что с видео тоже не будет никаких проблем, но они все же вылезли на свет. Т.е. проблем с самим захватом видео-потока не было, а вот с одновременным выводом данных с нескольких источников на одной странице оказалось не все так просто, как хотелось.

Итак, начнем с самого начала, а именно с захвата и вывода видео с одного источника. Для этого мы будем использовать ф-ю getUserMedia, которая поддерживается во всех нормальных браузерах старших версий (Stream API), ну разумеется кроме IE.

Пояснения

  • Все примеры кода ниже будут писаться на angularjs, ибо сейчас пишу на нем.
  • Все скрипты будут написаны для работы с браузерами Chrome и Opera, ниже будет написано почему.

getUserMedia

  • constraints — тут мы указываем, к какому типу данных мы хотим получить доступ. Его мы рассмотрим ниже более подробно;
  • successCallback — функция возвращает объект LocalMediaStream, это и есть наш поток с камеры;
  • errorCallback — функция отрабатывает, если при попытке захвата потока происходит ошибка или если пользователь отказался предоставить доступ к своему устройству.
  1. Мы создаем элемент video;
  2. При помощи ф-и createObjectURL из объекта LocalMediaStream мы создаем URL элемент типа Blob, который передаем в качестве источника в элемент video;
  3. Разрешаем авто-воспроизведение;
  4. Вставляем наш созданный элемент на страницу.

MediaStreamTrack

Конечно же, в попытках решить свою проблему, я обратился за помощью к объекту MediaStreamTrack, который представляет собой интерфейс для работы с потоками со всех мультимедийных устройств, до которых браузер смог добраться. MediaStreamTrack пока довольно-таки редкий зверь и встречается в последних версиях Chrome, Opera и Firefox. Так зачем же он нам нужен? А затем, чтобы получить информацию об источниках данных.

В общем, мы нащупали путеводную нить для решения нашей задачи. Только я почувствовал радость от сбывающейся мечты, как я понял, что не могу получить все источники разом для их вывода. После истерического поиска решения было установлено, что в Chrome и Opere объект MediaStreamTrack имеет ф-ю getSources, которая и является нашим спасением. Как видно из названия, эта ф-я возвращает объект, который содержит в себе информацию обо всех источниках аудио и видео.

Ну так найдем наши камеры:

  • id — уникальный идентификатор источника, генерируется браузером;
  • kind — тип, к которому относится источник (audio или video);
  • label — метка устройства (источника), в моём случае там было USB Video Device;
  • facing — как я понял, параметр имеет значение только для мобильных платформ и указывает на переднюю и заднюю камеру (Принимает два значения User — фронт-камера и environment — задняя камера).

Решение

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

  1. При загрузке страницы при помощи ф-и MediaStreamTrack.getSources мы определяем все источники видео сигнала;
  2. Выводим список источников на страницу. Делаем мы это для того, что нам все-таки придется давать разрешение на доступ к каждой камере. Этого можно избежать в том случае, если страница работает через https
  3. При нажатии на какой-либо источник из списка, мы перехватываем данные с него при помощи GetUserMedia, создаем элемент video для него и выводим. (Если выбираем один и тот же источник несколько раз, то просто будет делаться копия потока)

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

  • mandatory — тут указываются обязательные ограничения для нашего видео и, если они не могут быть выполнены, то будет вызвано исключение.
  • optional — это не обязательные параметры, которые при возможности будут применены к потоку (т.е. если мы тут укажем, что на выходе мы хотим иметь видео сигнал с частотой кадров не 30, а 60, и наша камера обеспечивает такой поток, то мы получим то, что хотим, а если камера не удовлетворяет условиям, то видео будет выводиться с частотой 30 кадров, что будет соответствовать значению параметра minFrameRate в блоке mandatory).
  • frameRate — частота кадров
  • aspectRatio — соотношение сторон
  • minWidth — минимальная ширина
  • minHeight — минимальная высота
  • sourceId — уникальный идентификатор источника
  • width
  • height

Приводить код html — шаблона я не буду. Все можно посмотреть на демке и на github.

На этом все, спасибо за внимание, и надеюсь, что эта статья будет кому-нибудь полезна.

📎📎📎📎📎📎📎📎📎📎