Появилась необходимость показывать видео с камеры на сайте в режиме онлайн. Виделось несколько вариантов (дополню вариантами из комментов, если будут):

  • Дать доступ к камере. Просто доступ к камере давать не стоит по соображениям безопасности. Камера ляжет уже при очень небольшой нагрузке.
  • Коммерческая услуга. Мы им доступ к камере и деньги, они нам ссылку для размещения на сайте. Они же решают проблему совместимости камеры и браузеров пользователей, производительности канала и доступности
  • На своих мощностях. Между пользователем и камерой ставится нечто, что отвечает за совместимость с браузерами, производительность и доступность. Проблемы решаем сами.

Этот вариант рассмотрим ниже. Т.к. "flash умер" или "flash вот-вот умрет", вариант с размещением flash плейера на сайте не рассматривался. Тернистый путь поисков решений в интернетах не привел к готовому решению. Пришлось изобрести велосипед.

Подробнее изобретения под катом.

Описание полученного велосипеда подробнее:


  • камера видеонаблюдения отдает поток по протоколу rtsp.
  • ffmpeg берет видео поток с камеры и создает видео для показа через тег video стандарта html5.
  • nginx отдает созданные файлы пользователям
  • видео на странице показываем с помощью hls, точнее вот эта реализация

Подробнее о настройках


На каждый поток с камеры надо запустить ffmpeg для преобразования rtsp в файлы который поймет hls.

ffmpeg и поток со звуком


/usr/bin/ffmpeg   -i  rtsp://<этот путь можно найти через ONVIF Device Manager>    -ar 44100   -acodec aac -ac 1 -strict -2 -crf 18   -c:v copy -preset ultrafast   -flags -global_header   -fflags flush_packets -tune zerolatency -hls_time 1 -hls_list_size 3 -hls_wrap 4 -hls_flags delete_segments -start_number 0   /tmp/www/index1.m3u8
ffmpeg при старте пишет 25 fps при FullHD
Guessed Channel Layout for  Input Stream #0.1 : mono
Input #0, rtsp, from 'rtsp://192.168.X.X:554/user=admin_password=tlJwpbo6_channel=1_stream=0.sdp?':
  Metadata:
    title           : RTSP Session
  Duration: N/A, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: h264 (Baseline), yuv420p, 1920x1080, 25 fps, 9 tbr, 90k tbn, 50 tbc
    Stream #0:1: Audio: pcm_alaw, 8000 Hz, 1 channels, s16, 64 kb/s
Output #0, hls, to '/tmp/www/index1.m3u8':
  Metadata:
    title           : RTSP Session
    encoder         : Lavf56.25.101
    Stream #0:0: Video: h264, yuv420p, 1920x1080, q=2-31, 25 fps, 9 tbr, 90k tbn, 25 tbc
    Stream #0:1: Audio: aac, 44100 Hz, mono, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc56.26.100 aac
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (pcm_alaw (native) -> aac (native))
Видео просто копируется, аудио пришлось перекодировать иначе тишина.
Камера noname.

Как работает:


Берем поток, без перекодирования создаем файлы и список для воспроизведения в папке /tmp/www/.

nginx


Сокращаем стандартный для пакета debian файл default до, например, такого:

/etc/nginx/sites-enabled/default
server {
        listen 80 default_server;
        listen [::]:80 default_server;
        access_log off;
        error_log /dev/null;
        root /tmp/www;
        index index.html;
        server_name _;
        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }
}

Пример страницы с видео:

/tmp/www/index.html
<!DOCTYPE html>
<html>
<head>
<title>Заголовок</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
<video id="video"></video>
<script>
  if(Hls.isSupported()) {
    var video = document.getElementById('video');
    var hls = new Hls();
    hls.loadSource('/index1.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
  });
 }
</script>

Скрипт стоит разместить локально, он не имеет внешних зависимостей. Подробнее о настройках hls.

Как работает:


на странице подключается hls и воспроизводит файлы из списка index1.m3u8. Список и файлы обновляются ffmpeg.

Что получилось:


  • Работает;
  • Самую большую нагрузку создает ffmpeg, на процессоре Atom трехлетней давности;
    • Разрешение камеры Full HD без звука — 1%;
    • Разрешение камеры Full HD со звуком — 5%;

  • Количество процессов nginx — смотреть по нагрузке и доступному каналу. Нагрузку на процессор увидеть не удалось — не очень много надо на просто отдачу небольших файлов.;
  • Сервер с ffmpeg и nginx можно разместить где угодно, не обязательно на хостинге или в месте расположения камер;
  • Отставание от потока зависит от количества файлов в списке и размера(в секундах) файла. Например отставание в 10 секунд не очень влияет на просмотр процесса строительства многоэтажки;
  • Видеофайлы лучше размещать на tmpfs, они имеют небольшие размеры и часто они перезаписываются;
  • Весь сервис стоит поместить в контейнер. Все пакеты стандартные для FROM debian:jessie;
  • По итогам эксплуатации ffmpeg иногда падает, за ним нужно следить и перезапускать если упал.

    Вывод top из контейнера:
    top - 11:05:20 up 6 days, 12:15,  0 users,  load average: 1.29, 1.09, 1.03
    Tasks:  17 total,   1 running,  16 sleeping,   0 stopped,   0 zombie
    %Cpu(s): 38.8 us,  1.0 sy,  0.0 ni, 59.6 id,  0.0 wa,  0.0 hi,  0.5 si,  0.0 st
    KiB Mem:  16359132 total, 16027988 used,   331144 free,   782968 buffers
    KiB Swap:  6369276 total,     3776 used,  6365500 free. 12784916 cached Mem
    
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
      281 root      20   0  341040  29192  19632 S   4.7  0.2  10:08.39 ffmpeg
       16 root      20   0  315888  27944  18984 S   1.0  0.2   2:50.95 ffmpeg
        9 root      20   0   46916  15128   6408 S   0.3  0.1   0:58.04 supervisord
  • Смотреть можно на десктопах и мобильных устройствах с современными браузерами;
  • В обозримом будущем не потребует вмешательства.

Ссылки:


» Реализация hls
» Демо работы hls
» ffmpeg
» nginx
» Дополненный и расширенный текст статьи на моём блоге
Поделиться с друзьями
-->

Комментарии (26)


  1. Rumlin
    31.01.2017 13:37

    Разрешение камеры HD со звуком

    а сколько кадров в секунду?


    1. ErshoFF
      31.01.2017 14:12
      +1

      Забыл упомянуть fps, вот вывод ffmpeg с живого сервера, да здесь и разрешение оказывается FullHD

      Guessed Channel Layout for  Input Stream #0.1 : mono
      Input #0, rtsp, from 'rtsp://192.168.X.X:554/user=admin_password=tlJwpbo6_channel=1_stream=0.sdp?':
        Metadata:
          title           : RTSP Session
        Duration: N/A, start: 0.000000, bitrate: N/A
          Stream #0:0: Video: h264 (Baseline), yuv420p, 1920x1080, 25 fps, 9 tbr, 90k tbn, 50 tbc
          Stream #0:1: Audio: pcm_alaw, 8000 Hz, 1 channels, s16, 64 kb/s
      Output #0, hls, to '/tmp/www/index1.m3u8':
        Metadata:
          title           : RTSP Session
          encoder         : Lavf56.25.101
          Stream #0:0: Video: h264, yuv420p, 1920x1080, q=2-31, 25 fps, 9 tbr, 90k tbn, 25 tbc
          Stream #0:1: Audio: aac, 44100 Hz, mono, fltp, 128 kb/s
          Metadata:
            encoder         : Lavc56.26.100 aac
      Stream mapping:
        Stream #0:0 -> #0:0 (copy)
        Stream #0:1 -> #0:1 (pcm_alaw (native) -> aac (native))
      

      Видео просто копируется, аудио пришлось перекодировать иначе тишина.
      Камера noname/


      1. ErshoFF
        31.01.2017 14:20

        Добавил в статью вывод ffmpeg.


      1. Rumlin
        31.01.2017 14:43

        Тогда понятно почему низкая загрузка. Я подумал это дешевая камера с MJPEG и поток перекодируют в h264 и начал подозревать неладное при упоминании Атома.


        1. ErshoFF
          31.01.2017 14:58

          Цель как раз и была в низкой нагрузке на CPU.

          Перекодирование убивало Atom в ноль.
          В текущем случае похоже идет «перепаковка» не требующая ресурсов процессора.
          Перекодирование звука создает заметную нагрузку.

          Если не нужно разрешение FullHD — возьмите с камеры поток/fps поменьше.


          1. Rumlin
            31.01.2017 22:05

            За камеру FullHD уже уплачено, иначе можно купить дешевле. Поэтому надо дожимать всё.


        1. remzalp
          31.01.2017 17:47

          Я решал аналогичную задачу более суровым методом — в итоге гоню поток MJPG через промежуточный прокси во Flash плэйер.

          Эта статья — просто радость какая-то, потому что проще собственно уже некуда.


          1. ErshoFF
            31.01.2017 17:49

            Спасибо.


  1. bitver
    31.01.2017 13:59

    Было и легко ищется.
    https://habrahabr.ru/post/162237/


    1. ErshoFF
      31.01.2017 14:03
      +1

      Я ждал этого коммента.
      Спасибо, что не обманули ожидания.

      Но почитайте внимательно материал по вашей ссылке и то, что я написал.

      Мой путь проще повторить, на обычной пакетной базе debian.
      Ничего не надо компилировать.
      Всё сопровождение свелось к обеспечению перезапуска ffmpeg, который изредка но падает.
      Работает в любом современном браузере, в т.ч. и на мобильных.
      Не требует flash.


      1. Segmentq
        31.01.2017 14:11

        Повторюсь, есть же motion.


        1. ErshoFF
          31.01.2017 14:14

          Motion видел, пробовал пользоваться, у меня не сложилось с ним.

          Если не трудно оставьте здесь ссылку на инструкцию, как motion приладить к показу на сайте картинки с онлайн камеры. Кому-нибудь это поможет.


          1. LionisIAm
            01.02.2017 10:43

            А как ещё решить вопрос записи по движению? У меня запущен motion, НЕ доволен. Сразу скажу, что камера — китайская самая дешевая, может поэтому и не нравится качество. На выходе что трансляции, что записи — примерно 0,25 фпс.


  1. sriver
    31.01.2017 17:49

    Хороший мануал, спасибо.
    Сделал все по нему, на ПК — все ок, а вот на Андроиде (Chrome) я получаю один кадр — статичную картинку и все, что я могу делать не так?


  1. ErshoFF
    31.01.2017 17:50

    Попробуйте на телефоне посмотреть через последний Firefox.


  1. Avenit
    01.02.2017 00:33

    За 15 минут настроил на Gentoo (некоторые параметры не распознавал, убрал их), работает в Chrome для Windows, сразу начинает трансляцию. А вот из под Safari для IOS пустая страница :(

    Кстати ссылку на плейлист можно скормить VLC, он ее скушает :)


    1. ErshoFF
      01.02.2017 07:29

      На ios нет устройств — проверить не могу, но по описанию должно работать.
      В Chrome на ios работает?


      1. Avenit
        01.02.2017 10:18

        Проверил — не работает.
        Что интересно, если открыть напрямую файл плейлиста — воспроизводит видеопоток.
        Так, что скорее всего проблема в скрипте hls.


        1. ErshoFF
          01.02.2017 10:48

          Тестировать не на чем — не смогу подсказать ничего.

          Внизу статьи ссылка «Демо работы hls» — видео работает?


          1. Avenit
            01.02.2017 16:10

            нет, видео не проигрывается


            1. ErshoFF
              01.02.2017 17:41

              Тогда похоже этот вариант (ffmpeg+hls реализация) не заработает на ios.


              1. Avenit
                02.02.2017 17:18

                ffmpeg как раз работает нормально, файл поток напрямую проигрывается на ios, не играет с веб-страницы!


            1. ErshoFF
              01.02.2017 17:46

              У вас видео+звук или просто видео?


              1. Avenit
                02.02.2017 17:17

                только видео


                1. ErshoFF
                  02.02.2017 23:36

                  hls.js разрабатывается, последнее изменение вчера.
                  Очень вероятно, что скоро допилят до рабочего состояния. Попробуйте последнюю версию с git-hub.

                  У меня тоже (widows+chrome) иногда останавливается картинка+звук. Думал что особенность двух потоков…


  1. Avenit
    01.02.2017 16:17

    Интересно, а как Ivideon работает, там тоже флеша нет.