Часть 1, историческая
Часть 2, технологическая
Вот и настало время финальной части повествования, в которой я расскажу о практическом результате той эпопеи что растянулась на несколько лет.
Приложения реализованные на данный момент
WebRTSP ReStreamer - основное приложение, которое может выступать как в качестве сервера, так и в качестве агента
WebRTSP Record Streamer - приложение предназначенное для работы в качестве агента для отправки видео потока на сервер либо в постоянном режиме, либо по событию движения с ONVIF камеры
WebRTSP Camera Streamer - приложение являющееся модификацией WebRTSP ReStreamer для стриминга видео потока с камеры подключенной к CSI разъему Raspberry PI
Video Monitor - приложение созданное для запуска на Raspberry Pi (с подключенным через HDMI экраном), для отображения в режиме реального времени видео потока получаемого через RTSP, ONVIF или WebRTSP протокол
Что может понадобиться
VPS/VDS с установленным Linux (способный запускать snap пакеты) для использования в качестве сервера. Практика показывает что достаточно самых минимальных конфигураций. Лично я использую самый дешевый VPS (512 мегабайт оперативной памяти, 1 ядро процессора, 10 гигабайт жесткого диска) предоставляемый Ru VDS стоимостью 139 рублей в месяц (или 111 рублей при оплате за год, не сочтите за рекламу)
Raspberry Pi не ниже 3-ей версии (или любое другое Arm64 или Amd64 совместимое устройство способное запускать snap пакеты) для использования в качестве агента
IP камера с поддержкой RTSP или ONVIF протоколов и h264 кодека. Поддержка ONVIF понадобится в случае если необходимо осуществлять запись видео при обнаружении движения в кадре
Немного теории о snap пакетах
Почему я решил использовать snap пакеты для упаковки приложений? Причин несколько:
Однажды и пробовал создавать PPA пакеты для распространения приложений - воспоминания остались не самые радужные. Это боль и большое количество затрачиваемого времени на каждую новую версию. Допускаю что я просто не научился их готовить, но использование snap пакетов показало себя с гораздо лучшей стороны
Snap пакет позволяет реализовывать фоновое выполнение процессов средствами самих snap пакетов без лишних проблем
Все процессы исполняемые в рамках snap пакета по умолчанию изолированы от остальной системы. Приложения имеют доступ только к очень ограниченному списку директорий на диске (часть только для записи, часть только для чтения) и явно определяемому списку аппаратных ресурсов
Программные компоненты включаемые в snap явно определяются разработчиком. При необходимости можно собирать компоненты из исходников, тем самым добавляя недостающие библиотеки либо заменяя их версию
Есть централизованный магазин приложений и достаточно простой набор команд для установки snap пакетов и управления ими
Есть механизм автоматического обновления snap пакетов при появлении новой версии в Snapcraft Store
Возможна публикация нескольких вариантов snap пакета, и разделение на development и release версии snap пакета не является проблемой (на самом деле вариантов гораздо больше, но опущу эти детали для простоты изложения)
Доступна автоматическая сборка и публикация новой версии snap пакета при добавлении коммита в GitHub репозиторий
Несколько полезных команд для работы с snap пакетами (в контексте Debian Linux и его вариантов)
для начала необходимо установить
snapd(но возможно в вашем конкретном случае он уже установлен):sudo apt install snapd. В случае Raspbian/Raspberry Pi OS возможно понадобятся дополнительные действия описанные в https://forum.snapcraft.io/t/installing-snap-on-debianустановка snap пакета:
sudo snap install имя-пакетаустановка development варианта snap пакета:
sudo snap install имя-пакета --edgeзамена release варианта snap пакета на development вариант:
sudo snap refresh имя-пакета --edgeзамена development варианта snap пакета на release вариант:
sudo snap refresh имя-пакета --stableперезапуск фонового процесса (процессов) запущенного в рамках snap пакета:
sudo snap restart имя-пакетавременная остановка фонового процесса (процессов) запущенного в рамках snap пакета:
sudo snap stop имя-пакетазапуск ранее остановленного фонового процесса (процессов) запущенного в рамках snap пакета:
sudo snap start имя-пакетаотключение фонового процесса (процессов) запущенного в рамках snap пакета:
sudo snap disable имя-пакетанепрерывное отображение логов:
sudo snap logs имя-пакета -fотображение x последних строк логов:
sudo snap logs имя-пакета -n=xотображение всех доступных строк логов:
sudo snap logs имя-пакета -n=all
Итак, приступим к практическому применению
Просмотр видео с IP камеры по локальной сети
┌─────────┐ HTTP ┌────────────┐
│ ├─────────────────►│ │ ┌───────────┐
│ │WebRTSP(WebSocket)│ │ RTSP │ │
│ Браузер ├─────────────────►│ ReStreamer ├─────────────────►│ IP камера │
│ │ WebRTC │ │ │ │
│ │◄────────────────►│ │ └───────────┘
└─────────┘ └────────────┘
Устанавливаем ReStreamer:
sudo snap install rtsp-to-webrtsp-
Открываем конфигурационный файл для редактирования:
sudoedit /var/snap/rtsp-to-webrtsp/common/restreamer.confи заменяем его содержимое следующим:streamers: ( { name: "Štrbské pleso" url: "rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream" force-h264-profile-level-id: "42c015" } )Если есть уже настроенная камера - меняем значения
nameна произвольное иurlна RTSP URL камеры. Что касаетсяforce-h264-profile-level-id- это активация того самого трюка, о котором я упоминал в одной из предыдущих частей, и позволяющего обмануть браузер и заставить его воспроизводить не только baseline profile h264 видео потоки Перезапускаем приложение:
sudo snap restart rtsp-to-webrtspОткрываем в браузере
http://127.0.0.1:5080(если приложение установлено на другом хосте, например на Raspberry PI, очевидно что нужно использовать IP адрес этого хоста)Если через несколько секунд видео не начинает отображаться на открытой странице - пишем в комментариях, либо создаем новую тему в GitHub Discussions, либо создаем issue на GitHub
Просмотр видео с IP камеры через интернет
Роутер(NAT/Firewall) ┌───────────┐
┌─┐ │ │
│ │ │ IP камера │
│ │ │ │
│ │ └───────────┘
│ │ ▲
│ │ │ RTSP
┌─────────┐ HTTPS ┌────────────┐ │ │ WebRTSP ┌─────────┴─────────┐
│ ├─────────────────►│ ReStreamer │ │ │(WebSocket)│ │
│ │WebRTSP(WebSocket)│ на │◄─┼─┼───────────┤ ReStreamer(агент) │
│ Браузер ├─────────────────►│ VPS/VDS │ │ │ │ на │
│ │ └────────────┘ │ │ │ Raspberry Pi │
│ │◄─────────────────────────────────┼─┼──────────►│ │
└─────────┘ WebRTC │ │ └───────────────────┘
│ │
└─┘
Устанавливаем ReStreamer на VPS/VDS:
sudo snap install rtsp-to-webrtsp-
Открываем конфигурационный файл для редактирования:
sudoedit /var/snap/rtsp-to-webrtsp/common/restreamer.confи заменяем его содержимое следующим:loopback-only: true streamers: ( { name: "IP Cam" type: "proxy" agent-token: "любая очень длинная строка из случайных символов" } ) users: ( { login: "user", pass: "pass" } ) Перезапускаем приложение:
sudo snap restart rtsp-to-webrtsp-
Запускаем скрипт настройки HTTPS и WSS (используется сервис Let's Encrypt для генерации сертификата):
./enableTLS.sh root@your.server.dns.name:22 you@mail.com Устанавливаем ReStreamer на Raspberry Pi (или другом устройстве) находящемся в одной локальной сети с IP камерой:
sudo snap install rtsp-to-webrtsp-
Открываем конфигурационный файл для редактирования:
sudoedit /var/snap/rtsp-to-webrtsp/common/restreamer.confи заменяем его содержимое следующим:signalling-server: { host: "your.server.dns.name" port: 5555 tls: true uri: "IP Cam" token: "любая очень длинная строка из случайных символов" } streamers: ( { name: "Štrbské pleso" url: "rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream" force-h264-profile-level-id: "42c015" } )где значение
uriдолжно совпадать со значениемnameна стороне сервера, а значениеtokenсоответственно со значениемagent-token Перезапускаем приложение на Raspberry Pi:
sudo snap restart rtsp-to-webrtspОткрываем в браузере
https://your.server.dns.name:5443/!, вводим имя пользователя/пароль, после этого в левом дереве распахиваем элементIP Cam(или с тем именем что было указано в конфигурационном файле на стороне сервера) и кликаем на элементŠtrbské pleso(или имени указанном в конфигурационном файле на стороне Raspberry PIЕсли через несколько секунд видео не начинает отображаться - пишем в комментариях, либо создаем новую тему в GitHub Discussions, либо создаем issue на GitHub
Запись видео с IP камеры на сервер (Cloud NVR)
Роутер(NAT/Firewall)
┌─┐
│ │ WebRTSP ┌───────────────────┐
┌────────────┐ │ │(WebSocket)│ │ ┌───────────┐
│ ReStreamer │◄─┼─┼───────────┤ Record Streamer │ RTSP │ │
│ на │ │ │ WebRTC │ агент на ├───────►│ IP камера │
│ VPS/VDS │◄─┼─┼──────────►│ Raspberry Pi │ │ │
└────────────┘ │ │ │ │ └───────────┘
│ │ └───────────────────┘
└─┘
-
Настраиваем серверную часть как указано в пунктах с 1. по 4. в предыдущей главе, но используем следующее содержимое для
restreamer.confфайла:loopback-only: true streamers: ( { name: "NVR" type: "record" restream: false record-token: "любая очень длинная строка из случайных символов" recordings-dir: "recordings" recordings-dir-max-size: 1024 // Mb recording-chunk-size: 100 // Mb } ) users: ( { login: "user", pass: "pass" } ) Устанавливаем Record Streamer на Raspberry Pi (или другом устройстве) находящемся в одной локальной сети с IP камерой:
sudo snap install webrtsp-record-streamer-
Открываем конфигурационный файл для редактирования:
sudoedit /var/snap/webrtsp-record-streamer/common/record-streamer.confи заменяем его содержимое следующимtarget: { host: "your.server.dns.name" port: 5555 tls: true uri: "NVR" token: "любая очень длинная строка из случайных символов" } source: { url: "rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream" }где значение
uriдолжно совпадать со значениемnameна стороне сервера, а значениеtokenсоответственно со значениемrecord-token Перезапускаем приложение на Raspberry Pi:
sudo snap restart webrtsp-record-streamerС этого момента агент начнет отправку видео 24*7 на сервер, где он будет разбиваться на части(файлы) максимального размера заданного в
recording-chunk-size, при этом максимальный размер записанных файлов не будет превышатьrecordings-dir-max-size. Для поддержания максимального размера будут удаляться самые старые файлы (что логично). Сохраненные файлы можно найти в директории/var/snap/rtsp-to-webrtsp/common/recordings/NVR/
Запись видео с ONVIF IP камеры на сервер при обнаружении движения в кадре (Cloud NVR)
Роутер(NAT/Firewall)
┌─┐
│ │ WebRTSP ┌───────────────────┐ ┌───────────┐
┌────────────┐ │ │(WebSocket)│ │ ONVIF │ │
│ ReStreamer │◄─┼─┼───────────┤ Record Streamer ├──────►│ │
│ на │ │ │ WebRTC │ агент на │ RTSP │ IP камера │
│ VPS/VDS │◄─┼─┼──────────►│ Raspberry Pi ├──────►│ │
└────────────┘ │ │ │ │ │ │
│ │ └───────────────────┘ └───────────┘
└─┘
Настраиваем серверную часть и агента идентично предыдущей главе, за исключением конфигурационного файла на стороне агента:
target: {
host: "your.server.dns.name"
port: 5555
tls: true
uri: "NVR"
token: "любая очень длинная строка из случайных символов"
}
source: {
onvif: "http://your.ip.cam.address:port"
track-motion-event: true
motion-record-time: 15 // seconds
}
с приведенной конфигурацией, Record Streamer будет отправлять видео только при обнаружении камерой движения, и осуществлять отправку в течении как минимум 15 секунд (или более, при получении дополнительных оповещений о движении, пока отправка активна)
Воспроизведение записей
┌─────────┐ HTTPS ┌────────────┐
│ ├─────────────────►│ │
│ │WebRTSP(WebSocket)│ │
│ Браузер ├─────────────────►│ ReStreamer │
│ │ WebRTC │ │
│ │◄────────────────►│ │
└─────────┘ └────────────┘
Для добавления функционала воспроизведения ранее записанных файлов необходимо использовать следующий конфигурационный файл на стороне сервера:
loopback-only: true
streamers: (
{
name: "NVR"
type: "record"
restream: false
record-token: "любая очень длинная строка из случайных символов"
recordings-dir: "recordings"
recordings-dir-max-size: 1024 // Mb
recording-chunk-size: 100 // Mb
},
{
name: "Recordings",
type: "player",
dir: "recordings/NVR",
force-h264-profile-level-id: "42c015",
}
)
users: (
{
login: "user",
pass: "pass"
}
)
Аппаратный видео монитор для дверной камеры с отображением видео при обнаружении движения
┌───────────────────┐
│ Video Monitor │ ┌───────────┐
│ на │ ONVIF │ │
│ Raspberry Pi ├───────►│ IP камера │
│ с подключенным │ │ │
│ HDMI монитором │ └───────────┘
└───────────────────┘
Важно! На Raspberry Pi необходимо использовать lite вариант Raspberry Pi OS (т.е. только с консолью, без графической оболочки)
Устанавливаем Video Monitor на Raspberry Pi находящемся в одной локальной сети с IP камерой:
sudo snap install video-monitor --edge-
Открываем конфигурационный файл для редактирования:
sudoedit /var/snap/video-monitor/common/monitor.confи заменяем его содержимое следующим:source: { onvif: "http://your.ip.cam.address:port" track-motion-event: true motion-preview-time: 15 // seconds } Перезапускаем Raspberry Pi:
sudo restartС приведенной выше конфигурацией, при обнаружении движения на экране будет отображено видео в течении 15 секунд (или более, при получении дополнительных оповещений о движении, пока отображение активно). При этом видео будет отображаться поверх приглашения входа, т.е. для работы приложения нет необходимости вводить имя пользователя и пароль после запуска Raspberry Pi.
Замечание: на данный момент мне не удалось найти способа перевода монитора подключенного к HDMI выходу Raspbery Pi в спящий режим. В связи с чем пока видео не отображается будет на экране будет отображаться приглашение входа системы. Для того чтоб это выглядело более менее прилично, я настраивал запуск заставки для текстового режима сразу после запуска Raspberry Pi. В качестве заставки я использовал приложение cmatrix.
Для получения аналогичного эффекта нужно выполнить следующие действия:
Установить cmatrix:
sudo apt install cmatrix-
Создать файл замены конфигурации первой консоли (она отображается сразу после запуска Raspberry Pi):
sudo mkdir -p /etc/systemd/system/getty@tty1.service.d sudoedit /etc/systemd/system/getty@tty1.service.d/override.confи добавить в него следующее содержимое:
[Service] ExecStart= ExecStartPre=/bin/sleep 10 ExecStart=-/usr/bin/cmatrix -u 8 -
Перезапустить Raspberry Pi:
sudo restartТеперь через 10 секунд после запуска Raspberry Pi на экране будет появляться заставка из фильма "Матрица"
Заключение
Собственно это все что я хотел рассказать о той системе видеонаблюдения что мне удалось создать за последние годы. Я прекрасно понимаю что текущая реализация далека от идеальной, и необходимо вложить еще достаточно большое количество усилий и времени для доведения ее до приличного состояния. Но тем не менее ее вполне достаточно для использования. Надеюсь система пригодится не только мне.
Если у вас возникли вопросы, буду рад их услышать в комментариях к статье или Issues/Discussions проекта на GitHub.
Спасибо за внимание.
tklim
Надо было начинать первую статью с картинками и сценариями использования.
Что насчёт нескольких камер? Можно добавить в один конфиг или несколько экземпляров служб поднимать?
RSATom Автор
Да, ReStreamer поддерживает возможность создания нескольких элементов в конфиге, но Record Streamer на данный момент поддерживает только подключение к одной камере. Технически добавить поддержку нескольких подключений в Record Streamer не сильно большая проблема - у меня просто руки не дошли. Если лично вам есть необходимость - можете создать issue на GitHub - отработаю пока есть свободное время.
RSATom Автор
Как оно выглядит можно посмотреть в демке, но боюсь свалится оно под натиском хабр эффекта...
Viktor-T
Очень здорово! Спасибо большое. Такое прямо сейчас возможно получить используя WebRTSP ReStreamer для просмотра нескольких камер в локальной сети?
RSATom Автор
Да, без проблем, достаточно иметь секцию
streamersв конфигурационном файле следующего вида:раздел
streamersможет содержать произвольное количество элементов произвольного типа. Причем работать это будет как для режима сервера, так и для режима агента.Один момент который может оказаться полезным, ReStreamer может одновременно работать и в режиме агента и в режиме сервера. Для этого необходимо добавить опцию
disable-own-server: trueв секциюsignalling-server.Еще один момент, если вы не планируете использовать HTTPS/WSS доступ к серверу, то необходимо убрать опцию
loopback-only: true(либо заменить значение наfalse). В этом случае сервер будет доступен на порту5080(т.е. URL будет иметь видhttp://192.168.0.x:5080/, но при этом заданные в конфигурационном файле пользователи и пароли работать не будут.С полным списком опций конфигурационного файла можно ознакомиться здесь.
RSATom Автор
Опечатка, для одновременной работы в режиме агента и сервера нужно использовать
disable-own-server: falseViktor-T
Спасибо, всё получилось.
Один момент омрачает - долгая загрузка видео на 1-2 камерах и очень долгая загрузка видео на других 1-2 камерах. У меня 4 камеры в одной сети с компом, добавил все и настроил вид, чтобы сразу 4 были на одном экране. При запуске более менее быстро появляется видео на одной камере, через несколько секунд (до 15 примерно) на второй, а две оставшиеся нужно ощутимо подождать (до минуты). Каждый раз очерёдность загрузки видео разная - любая из камер может загрузиться быстрее и любая медленнее в разные запуски программы.
Когда одна камера на странице, а слева список камер, то видео загружается быстрее, до 10 секунд.
Не знаю, связано это или нет, в логах появляется сообщение о невозможности найти TURN-сервер и об использовании гугловского.