В чем главная проблема современных недорогих IP-камер? Вы не можете просто так добавить их на свой сайт! Они выдают видео совсем не в том формате, который понимают браузеры. Да, конечно, можно зайти напрямую на камеру (и часто только с IE), и у многих моделей есть «облако». Но проблема остается — я не могу просто так взять и поместить камеру на сайт, как например, простую картинку!
Я рассмотрел множество решений для организации трансляций с IP-камер от разных поставщиков, в том числе и OpenSource решения. У большинства один недостаток, очень критичный для меня: система постоянно захватывает поток с камеры, даже если нет зрителей.
В моем случае нужно было вывести картинку на сайт с удаленных камер, подключенных по 4G каналу в глухом районе. Скорость на отдачу не поднималась выше 10 Мбит/с в лучшие времена, но обычно она была 2-3 Мбит/с. Трафик хоть и неограничен, но провайдер неофициально предупредил, что расход выше 200 ГБ трафика непременно скажется негативным образом, такой вот условный «безлимит». Предполагаю, просто «порежут» скорость.
Некоторые решения, найденные на просторах GitHub, практически подходили, но не обладали хорошей документацией или казались просто сложными и громоздкими.
А была мне нужна система онлайн-трансляций с такими свойствами:
-
не расходующая трафик в отсутствие зрителей;
-
среднедневное одновременное число зрителей — 1-3 человека;
-
поддержка если не всех, то большинства популярных интернет-браузеров, в том числе мобильных;
-
максимально простая и понятная;
-
недорогая;
-
желательно OpenSource.
Имея богатый опыт работы с программой FFMpeg, весь этот функционал я решил попробовать реализовать самостоятельно. В конце концов, чем плох «велосипед», сделанный своими руками, если есть желание и время?
Но тут вы наверняка скажете «зачем на свой сайт, ведь есть iVideon?» и будете правы. Действительно, этот сервис практически не потребляет трафик, когда трансляция неактивна, очень простой в развертывании и вообще классный. А еще весьма дорогой, когда камер много и много зрителей, которым нужно передать права (никаких публичных ссылок). И забавно, зрителю тоже нужно оплачивать подключение каждой новой камеры сверх лимита (во всяком случае, год назад было именно так). Постепенно условия сервиса менялись, и вот теперь на бесплатном аккаунте можно разместить лишь одну камеру, и передать права лишь одному пользователю. И это уже не говоря о том, что в идеале потребуются камеры или видеорегистраторы с «iVideon-овской» прошивкой.
По моим наблюдениям, оказалось, что такие браузеры, как Google Chrome и Mozilla Firefox, спокойно воспроизводят правильно подготовленный H.264-поток с камеры. Под «правильной подготовкой» имеется ввиду переупаковка потока программой FFMpeg со следующими параметрами:
-movflags +frag_keyframe+separate_moof+omit_tfhd_offset+empty_moov
Эти опции подсказывают FFMpeg, что на выходе мы хотим получить фрагментированный MP4-файл с наличием атома moov в начале файла и последовательность атомов moof с интервалом в один ключевой кадр.
Из прочих параметров я задавал еще такие:
«-c copy
» для копирования потока без перекодировки;
«-an
» — без аудио (почему-то всё ломается, если камера не передает аудиопоток, а таких камер много);
«-t лимит
» для ограничения времени одного сеанса (конкретно у меня трафик ограничен, экономим на всём);
«-rtsp_transport tcp
» — проще тем, что не требуется пробрасывать RTP-порты, если камера находится за NAT (поддерживается практически всеми камерами);
«-probesize 32
» — эта команда ускоряет воспроизведение видео;
«-stimeout 5000000
» — тайм-аут чтения потока (5 секунд).
Хорошо, а причем тогда здесь PHP? А нужен он вот зачем. Посылаем необходимые заголовки:
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header('Accept-Ranges:bytes');
header('Connection:keep-alive');
header('Content-type: video/mp4');
И средствами PHP запускаем FFMpeg с перенаправлением потока напрямую в браузер зрителя:
passthru("ffmpeg <параметры кодирования и ссылка на поток> -f mp4 pipe:");
И все было бы отлично, но видео грузится несколько секунд, и не воспроизводится в Safari на Mac и iOS. То ли особенность реализации кодека там такая, то ли просто фрагментированные MP4 толком не поддерживаются, не знаю — перепробовал все варианты. Еще заметил, что видео начинает «моргать» в браузере Google Chrome, если не обождать пару секунд перед стартом воспроизведения.
Самый простой способ решения проблемы, который пришел мне в голову — а почему бы не пустить сначала перекодированный в MJPEG поток, а после, когда прогрузится основной MP4, — сделать замену? У этого формата масса плюсов — простой, поддерживается наверно вообще всеми браузерами, очень нетребователен к ресурсам сервера, но … очень прожорлив в плане размера выходного файла, и как следствие, расходуемого трафика. Поэтому по максимуму урежем качество картинки, лишь бы работало.
И знаете, получилось весьма сносно. Я доработал первоначальный скрипт, и теперь он:
-
умеет выводить видео и в других форматах: OGV и WEBM;
-
умеет выдавать по запросу статичную картинку (снимок);
-
если видит, что вкладка с ранее открытым видео была в фоне при запуске браузера, то переадресует на указанный вами сайт (например, каталог камер), таким образом, экономя ресурсы;
-
не стопорится в Яндекс-браузере на Mac. Там кодек тоже как-то хитро работает — до второго ключевого кадра воспроизводит, а потом всё. Для него пришлось делать дополнительную проверку, вдруг видео «сломалось». Safari поступает более мудро — просто не воспроизводит и всё.
Кажется, получилось уже много текста, поэтому перейдем к самому интересному — как его установить на свой сервер. Установка скрипта проста:
-
берете сервер, например, с Debian, ставите Apache+PHP7 и FFMpeg;
-
получаете SSL-сертификат для своего сервера;
-
копируете файлы моего скрипта в любую доступную по www папку;
-
открываете camera.php и указываете свой ключ (придумываете; допустима латиница и цифры) в переменной $key, а в $redirectToIfBackground указываете, куда переадресовывать из фоновых вкладок;
-
размещаете на страницах своего сайта трансляций ссылки на camera.php в таком формате: camera.php?a=<rtsp-ссылка в base64>&b=<ключ>&c=<rtsp-ссылка на второй поток в base64>. При этом параметр «c» необязательный, но очень желательный.
Риску предположить, что на шаге 4 у вас могут возникнуть затруднения. Но здесь нет ничего сложного, можно взять любой онлайн base64 конвертер, например http://base64.ru/, и сконвертировать вашу ссылку на RTSP-поток.
И вроде бы на этом всё, но без одной маленькой детали рассказ был бы неполным. Если вы планируете сайт с камерами сделать на MODX Revolution, то используйте приложенный плагин, упрощающий работу по размещению ссылок. Инструкция по установке плагинов есть в документации к этой CMS. После установки плагина откройте его на редактирование и в начале файла подставьте свои значения в $key и $camera_server_url (иными словами — замените текст, выделенный заглавными буквами, своим ключом и адресом сервера).
После его установки, в тексте ваших страниц ссылки на камеры теперь можно указывать в таком виде:
{camera*НАЗВАНИЕ*RTSP-ССЫЛКА*RTSP-ССЫЛКА НА ВТОРОЙ ПОТОК}
Название и RTSP-ссылки подставляете свои. Если нет ссылки на второй поток, то дублируете ссылку основного потока. Если есть затруднения с поиском RTSP-ссылок на вашу камеру, то можно использовать программу Onvif Device Manager. Она покажет ссылку снизу слева, по клику на «Живое видео».
По поводу безопасности. В принципе, если сервис будет непубличным, для чего и задумывался скрипт, то всё нормально. В противном случае, любой кто «подсмотрит» ссылку на camera.php, может вытащить исходную RTSP-ссылку, пароль на камеру (он прописывается в RTSP-ссылке), и сам секретный ключ $key. Пароль на камеру дает доступ к её админке, если вы пренебрегли созданием отдельной учетной записи на этой камере специально для RTSP. Секретный же ключ даст возможность через ваш сервер «крутить» сторонние камеры. Поэтому, данный скрипт только для частного доступа. Я мог бы реализовать шифрование параметров, но… при размещении в публичный доступ ввиду отсутствия кэширования видеоряда интернет-канал быстро «забьется», как и ресурсы на сервере.
Кстати, лично у меня все камеры посредством VPN (я люблю Wireguard) связаны в одну сеть, все ссылки я прописываю с «серыми IP». Удобно, безопасно, радует.
Мой код публикуется под лицензией MIT.
В проекте используется библиотека ifvisible.js, разработанная Serkan Yerşen, лицензия MIT.
ссылка на оригинал статьи https://habr.com/ru/post/545888/
Добавить комментарий