30
Июн

Вещание с вэб-камеры на сайте

Написал Максим Крентовский в Деятельность

Определённого рода задачи требуют демонстрации видео на сайте, получаемого посредством вэб-камеры. В общем случае эта задача решается дублированием кода с технической страницы камеры (мы рассматриваем случай использования Ethernet-камеры, способной самостоятельно формировать видео-поток, в случае более дешёвых решений алгоритм немного меняется) на сайт и камера напрямую отдаёт картинку посетителю. К сожалению, мощности камер и ширина каналов, которые они используют, очень часто бывают ограничены, а в случае весьма посещаемого сайта количество посетителей может быть вполне немаленьким.

В этом случае задача обычно решается путем установки потокового сервера на пути между посетителем и камерой. Принцип действия потокового сервера одинаков и в случае видео-вещания и в случае аудио-вещания: выделяются источник вещания, который является поставщиком контента (в нашем случае это камера), и приемники (подключающиеся пользователи). Сам сервер играет роль разветвителя (или ретранслятора) — принимая данные с одного канала, он раздаёт его на множество других каналов. По пути возможны различные преобразования (например, понижение скорости потока за счет снижения качества), впрочем одно то, что на источник можно подавать любой сигнал, гораздо упрощает управление — достаточно одного специализированного места оператора (пульта DJ-я в случае радио) и оставляем на потоковый сервер заботу о посетителях.

Теперь перейдём к вэб-камерам. В общем случае с любой ethernet-камеры можно снять данные двумя методами — в виде серии картинок и потоком видео. Первый случай более общий, но в этом случае видео получается весьма ступенчатым. Второй случай более приятен в созерцании, но не исключена вероятность, что воспроизводится будет лишь при помощи специализированного кодека, что неприятно. Впрочем, AXIS славится своей приверженностью к открытым системам, так что проблем быть не должно.

Другой нюанс заключается в извечном компромиссе сетевого вещания «качество — скорость». Чем выше качество картинки, тем больше требуется канал из расчёта на посетителя и тем больше вероятность, что видео будет притормаживать вследствие использования непрогнозируемых задержек передачи по сети и не рассчитанного на вещание реального времени с возможной потерей пакетов в угоду синхронизации протокола HTTP. С другой стороны, чем хуже картинка, тем меньше требуется полоса пропускания для ее доставки до потребителя, а, следовательно, больше вероятность, что пользователь увидит видео как надо, а не покадровую склейку. Именно между двух зол и придётся балансировать.

Испробованное решение базируется на пакете ffmpeg, в состав которого входит потоковый сервер ffserver. Упрежу сразу, что следует брать наиболее свежую версию ПО, поскольку в дистрибутивах зачастую попадаются не самые новые, а засим не самые стабильны сборки. Конфигурационный файл, по умолчанию располагающийся в /etc/ffserver.conf (для ручной сборки лучше переложить в /usr/local/etc/ffserver.conf) будет выглядеть примерно так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Port 8090
BindAddress 0.0.0.0
MaxClients 300
MaxBandwidth 100000
CustomLog /var/log/ffservser.log

<Feed feed1.ffm>
    File /tmp/feed1.ffm
    FileMaxSize 1024M
    ACL allow 127.0.0.1
</Feed>

<Stream cam.swf>
    Feed feed1.ffm
    Format swf
    VideoSize cif
    VideoBitRate 512
    VideoBufferSize 4000
    VideoQMin 1
    VideoQMax 5
    NoAudio
    PreRoll 0
</Stream>

<Stream cam.asf>
    Feed feed1.ffm
    Format asf
    VideoSize cif
    VideoBitRate 512
    VideoQMin 1
    VideoQMax 12
    VideoGopSize 20
    NoAudio
    StartSendOnKey
    PreRoll 0
</Stream>

<Stream stat.html>
    Format status
</Stream>

<Redirect index.html>
    URL http://www.relabs.ru/
</Redirect>

В данном случае мы используем один источник потока feed1.fmm, доступ к которому ограничен рамками локального хоста. В качестве выходных потоков будут применяться cam.asf для выдачи видео-потока для Windows Media Player и cam.swf для выдачи в виде swf-файла. Последний вариант более универсален, поскольку позволяет проигрывать видео в браузерах на платформах, отличных от Microsoft Windows. Параметрами можно играться для достижения оптимального результата, при этом надо отдавать отчет, что у товарища на другом конце света с хорошим каналом видео может показывать гораздо лучше, нежели у друга из соседнего дома.

Далее, организуем поставку видео-потока. Тут, как уже говорилось, два варианта:

а) с использованием mjpeg (суть — последовательного потока кадров в формате jpeg)

1
2
3
4
5
6
#!/bin/bash
while [ 1 ]
do
    ffmpeg -v 0 -s cif -y -an -r 4 -f mjpeg -sameq -i http://АДРЕС_КАМЕРЫ/mjpg/video.mjpg http://127.0.0.1:8090/feed1.ffm
    sleep 15
done

б) с использованием потока MPEG-4, транслируемого по RTSP

1
2
3
4
5
6
#!/bin/bash
while [ 1 ]
do
    openRTSP -v -c -t rtsp://АДРЕС_КАМЕРЫ/mpeg4/media.amp | /usr/local/bin/ffmpeg -f m4v -i - -an  http://127.0.0.1:8090/feed1.ffm > /dev/null
    sleep 15
done

В обоих случаях для обеспечения непрерывности применяется бесконечный цикл средствами shell, а во втором еще и используется утилита для снятия RTSP-потока OpenRTSP, входящая в состав пакета live555, ориентированного на работу с этим протоколом.

Далее, запускаем один их этих вариантов и проверяем результаты (в этом очень часто хорошо помогает страница статуса сервера http://АДРЕС_СЕРВЕРА:8090/stat.html). В случае успешной настройки можем спокойно приступить к интеграции видео в код сайта.

Код варианта с WMP будет выглядеть как

1
2
3
4
5
6
7
<object width="352" height="280" type="video/x-ms-wmv" id="IFid1" classid="CLSID:6BF52A52-394A-11D3-B153-00C04F79FAA6">
        <param value="1" name="AutoStart"/>
        <param value="none" name="uiMode"/>
        <param value="0" name="Volume"/>
        <param value="http://АДРЕС_СЕРВЕРА:8090/cam.asf" name="URL"/>
    <embed width="352" height="320" autostart="1" src="http://АДРЕС_СЕРВЕРА:8090/cam.asf" videoborder3d="0" showstatusbar="1" showdisplay="0" showtracker="1" showcontrols="0" bgcolor="darkblue" autosize="1" displaysize="4" name="mediaPlayer" id="mediaPlayer" pluginspage="http://microsoft.com/windows/mediaplayer/en/download/" type="application/x-mplayer2"/>
    </object>

Вариант с применением Flash будет выглядеть как

1
2
3
4
5
<div id="splayer">Movie</div>
      <script type="text/javascript">
          var so = new SWFObject('http://АДРЕС_СЕРВЕРА:8090/cam.swf','player','352','288','8');
          so.write('splayer');
      </script>

В этом случае применяется JS-библиотека SWFObject.

Если все прошло успешно — не забываем прописать запуск сервера и поставщика видео в автозапуск и хорошенько проверить систему из разных точек сети.

Источники информации:

  1. Convert Axis webcam stream to Flash (.swf/.flv)
  2. Передача видео с IP-камер D-Link
  3. RTSP source mp4 FLV streaming
7 ком.
  1. nema:

    Пароботало полчаса и выдал /usr/local/bin/ffmpeg — нет такого файла или каталога. И все(( его и правда нет

    google.com Максим Крентовский

    Интересно. А картинку давало?

    nema

    неа. Три разных плейра вставил в html на соседнем компе, везде темнота была. Но цикл с openRTSP исправно крутился, тревожных сообщений не выкидывал. И вдруг встал((

    nema

    параллельно работает аналог на VLC, видеопоток вижу без проблем (ну тока порты вещения, понятно другие)

    nema

    поработало :) ошибся

  2. djlexs:

    У меня вопрос, а какой канал нужен чтобы допустим 100 пользователей с каналом 1мбит каждый. Могли смотреть видео

    google.com Максим Крентовский

    В теории 100 МБитс, на практике лучше держать запас еще 20%, т.е. итого 120 МБитс. Разумеется, это когда все сто пользователей одновременно смотрят. Если они смотрят стохастически — 20-30Мбитс должно хватить.

Максим Крентовский
системный архитектор
E-mail / GTalk: mkrentovskiy@gmail.com
Skype: mkrentovskiy