NEWS
Просмотр видеокамер,DVR
-
Исходные данные:
Есть IP камера, выдающая RTSP поток, типа:
"rtsp://user:password@192.168.2.20:554/Streaming/Channels/1?tcp"
Задача:
получить видео-поток с этой камеры на веб-странице ioBroker не разглашая пароль в сетевом трафике.
Решение:
Так как поток rtsp не понимает ни один браузер конвертируем его в более дружелюбный rtmp. Для этого понадобится скомпилировать nginx с поддержкой rtmp (https://github.com/arut/nginx-rtmp-module). Также в nginx понадобится поддержка secure_link.
Поэтому собираем nginx так:
./configure --add-module=/path/to/nginx-rtmp-module --with-http_secure_link_module make make install
В конфиге nginx меняем номер порта (опция listen) в http секции на любой свободный, например 65080 и создаём секцию "location /on_play" в секции "server":
location /on_play { # set connection secure link secure_link $arg_st,$arg_e; secure_link_md5 mysecretkey$arg_app/$arg_name$arg_e; # bad hash if ($secure_link = "") { return 501; } # link expired if ($secure_link = "0") { return 502; } return 200; }
и секцию "rtmp" как в примере http://helping-squad.com/nginx-rtmp-how … ure-links/ :
rtmp { server { listen 1935; notify_method get; # protected application application camera1 { live on; wait_video on; on_play http://localhost:65080/on_play; exec_pull /usr/local/bin/ffmpeg -thread_queue_size 5120 -i rtsp://user:password@192.168.2.20:554/Streaming/Channels/1?tcp -thread_queue_size 5120 -f alsa -ac 1 -i hw:1 -map 0 -map 1 -vcodec copy -acodec libfdk_aac -ab 24k -ar 22050 -f flv rtmp://localhost:1935/camera2/stream ; } } }
Nginx настроен. Опция exec_pull означает что поток rtsp будет браться с камеры только при запросе.
Можно добавить аудиопоток с микрофона, как в моём примере. Буфер "-thread_queue_size 5120" сглаживает данные при перекодировке и микшировании со звуком. В этом примере перекодировки video нет (опция -vcodec copy).
Теперь надо создать url в iobroker к rtmp-потоку.
В настройке драйвера js добавляем библиотеку "crypto".
Создаём скрипт:
createState('rtmp1',url_1); createState('rtmp1_local',url_local_1); schedule("*/15 * * * *", function () { var crypto = require('crypto'); var time = Math.round(Date.now()/1000) + 3600; var md5_1 = crypto.createHash('md5').update("mysecretkeycamera1/stream" + time).digest('binary'); var hash_1 = new Buffer(md5_1, "binary").toString('base64'); hash_1 = hash_1.replace(/\+/g, '-'); hash_1 = hash_1.replace(/\//g, '_'); hash_1 = hash_1.replace(/=/g, ''); var url_1 = "rtmp://www.mydnsurl.ru:8095/camera1/stream?e=" + time + "&st=" + hash_1; var url_local_1 = "rtmp://192.168.2.200:1935/camera1/stream?e=" + time + "&st=" + hash_1; setState("javascript.0.rtmp1",url_1); setState("javascript.0.rtmp1_local",url_local_1); });
Один url для локального доступа, второй для внешнего. При внешнем доступе на роутере настраиваем проброс портов на нужный сервер:порт.
Обратите внимание что первая часть пароля "mysecretkeycamera1/stream" состоит из собственно пароля "mysecretkey" и присоединённой части образованной из "camera1/stream" : "camera1" это имя приложения в конфиге nginx, а "stream", используется при создании потока ffmpeg: "-f flv rtmp://localhost:1935/camera2/stream". Время действия ссылки в этом примере - 3600 сек.
В редакторе vis создаём кнопку элементом basic html:
Здесь в зависимости от типа вход (lan/wan) , а также в зависимости от клиента (андроид или десктоп) выбираем урл.
Для IOS тоже можно приготовить поток в формате hls, nginx это умеет.
Для андроида нужно установить vlc, mx-player или иное приложение, понимающее rtmp. При клике андроид спросит чем открыть.
Для десктопа открывается страница cam1:
RTMP player
-
Заткнулся на
./configure --add-module=/path/to/nginx-rtmp-module --with-http_secure_link_module make make install
После сборки не запускается nginx````
Failed to start nginx.service: Unit nginx.service failed to load: No such file or directory.Не силен в linuxe. А нет готового пакета nginx с rtmp-module для debian ?
-
Заткнулся на
./configure --add-module=/path/to/nginx-rtmp-module --with-http_secure_link_module make make install
После сборки не запускается nginx````
Failed to start nginx.service: Unit nginx.service failed to load: No such file or directory.Не силен в linuxe. А нет готового пакета nginx с rtmp-module для debian ? `
Скорее всего если до этого стоял пакет из репозитария linux (debian/ubuntu или что у вас там) то пути в стартовом скрипте остались старые, не соответствующие откомпиленной версии. Если ещё актуально дам стартовый скрипт.
-
В связи со скорым прекращением поддержки flash в браузерах предлагаю более современный вариант стриминга видео в vis,
пока для локальной сети (без секурных ссылок), работает в браузерах Chrome и FireFox на pc и android .
Исходные данные:
IP камера (адрес 10.10.10.10), отдающая поток в формате rtsp.
Задача:
Получить видео на странице iobroker без использования flash.
Решение:
1. Компилируем nginx с поддержкой rtmp, как было описано ранее.
2. Правим конфиг nginx для отдачи видео в формате mpeg-dash:
worker_processes 2; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; keepalive_timeout 65; server { listen 80; add_header 'Access-Control-Allow-Origin' '*'; location /dash { root /usr/html; add_header 'Access-Control-Allow-Origin' '*'; add_header Cache-Control no-cache; } location /dash.js { root /usr/html; } } include /etc/nginx/conf.d/*.conf; } rtmp { access_log /var/log/nginx/rtmp_access.log; server { listen 1935; ping 30s; notify_method get; # генерация dash-манифеста и фрагментов application cam1 { live on; dash on; dash_path /usr/html/dash; exec_static ffmpeg -i rtsp://admin:password@10.10.10.10:554/Streaming/Channels/2 -an -vcodec copy -f flv rtmp://127.0.0.1:1935/cam1/stream; } } }
3. Как описано на https://habrahabr.ru/post/204666/
` > Скачиваем и устанавливаем dash.js из форка
скачаем dash.js в /usr/html
cd /usr/html
git clone https://github.com/arut/dash.js.git
cd dash.js
git checkout live
Открываем в редакторе baseline.html и находим строчку со стандартным урлом
url = "http://dash.edgesuite.net/envivio/dashp … nifest.mpd",
Заменяем на наш урл
url = "http://172.16.1.120:80/dash/stream.mpd". `
Теперь можно проверить воспроизведение видео до встраивание его в iobroker:
http://172.16.1.120/dash.js/baseline.html
4. В vis-е в элементе basic-HTML согласно инструкции https://github.com/Dash-Industry-Forum/ … /README.md :
<title>Auto-player instantiation example, single videoElement, using src attribute</title>
5. Пробуем открыть страницу в режиме просмотра и видим ошибку (правая кнопка мыши-посмотреть код):
Refused to load media from 'blob:http://172.16.1.120:8082/f75ba73c-3f5e- … 389bfdca45' because it violates the following Content Security Policy directive: "media-src 'self' 'unsafe-inline' *".
6. До обновления vis или придумывания обходного решения правим файл /home/iobroker/node_modules/iobroker.vis/www/index.src.html:
Находим строку media-src 'self' 'unsafe-inline' *
и добавляем параметр blob:
В итоге должно быть:
media-src 'self' 'unsafe-inline' * blob:
7. Выполняем команду: iobroker upload vis
8. Видео отображается.
P.S. Для уменьшения задержки (только при хорошем канале) в конфиге nginx добавляем параметры (****__dash_playlist_length 10s;
dash_fragment 2s;__****):
application cam1 { live on; dash on; dash_playlist_length 10s; dash_fragment 2s; dash_path /usr/html/dash; exec_static ffmpeg -i rtsp://admin:password@10.10.10.10:554/Streaming/Channels/2 -an -vcodec copy -f flv rtmp://127.0.0.1:1935/cam1/stream; }
P.P.S. Каталог с фрагментами dash (в данном случае "/usr/html/dash") рекомендуется размещать на ram-disk, чтобы не насиловать hdd/sdd.
-
Протестировав HLS и mpeg-dash пришёл к заключению что HLS-поток лучше справляется с передачей видео на медленном и нестабильном канале связи. Поэтому оставляю у себя HLS. Плюс у него ещё в том, что поток можно смотреть с любого устройства - android, apple, desktop с Windows.
Привожу настройки с секурными ссылками (актуально при просмотре через интернет) :
1. Nginx надо будет скомпилировать с такими ключами:
./configure –with-http_sub_module --with-http_secure_link_module --add-module=/path/to/nginx-rtmp-module
make; make install
2. Конфиг nginx (проверяется переданный пароль (mypassword)
` > user www-data;worker_processes 1;
pid /var/run/nginx.pid;
error_log /var/log/nginx/error.log;
events {
worker_connections 1024;
}
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
access_log /var/log/nginx/access.log;
server {
client_max_body_size 12M;
listen 65080;
root /var/www;
index main.php;
rewrite_log on;
uninitialized_variable_warn on;
server_name http://www.mysite.ru;
add_header 'Access-Control-Allow-Origin' '*';
location / {
rtmp_control all;
auth_basic "closed site";
auth_basic_user_file /etc/apache2/htpasswd.cfg;
}
location ~* .(?:ico|jpg|jpeg)$ {
expires 10m;
add_header Pragma public;
add_header Cache-Control "public";
}
location /hls1/ {
add_header 'Access-Control-Allow-Origin' '*';
root /mnt/ramdisk;
add_header Cache-Control no-cache;
secure_link $arg_sth1,$arg_expiresh1;
secure_link_md5 mypassword$arg_expiresh1;
sub_filter .ts .ts?sth1=$arg_sth1&expiresh1=$arg_expiresh1;
sub_filter_once off;
sub_filter_types *;
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
}
}
}
rtmp {
access_log /var/log/nginx/rtmp_access.log;
server {
listen 1935;
ping 30s;
notify_method get;
application hlscamera1 {
live on;
hls on;
hls_playlist_length 20s;
hls_fragment 4s;
hls_path /mnt/ramdisk/hls1;
exec_static /usr/bin/ffmpeg -thread_queue_size 5120 -i rtsp://user:password@192.168.2.30:554/Streaming/Channels/2 -thread_queue_size 5120 -f alsa -i default -map 0 -map 1 -vcodec copy -acodec libfdk_aac -ab 24k -ar 22050 -f flv rtmp://localhost:1935/hlscamera1/stream1;
}
} `
3. Скрипт, генерирующий безопасные ссылки (1 при web доступе, другая при ЛВС-доступе), задаётся пароль (mypassword) в iobroker:
schedule("* * * * *", function () { var crypto = require('crypto'); var time = Math.round(Date.now()/1000) + 10*3600; var md5_hls1 = crypto.createHash('md5').update("mypassword"+time).digest('binary'); var hash_hls1 = new Buffer(md5_hls1, "binary").toString('base64'); hash_hls1 = hash_hls1.replace(/\+/g, '-'); hash_hls1 = hash_hls1.replace(/\//g, '_'); hash_hls1 = hash_hls1.replace(/=/g, ''); var url_hls1 = "http://www.mysite.ru:65080/hls1/stream1.m3u8?sth1=" + hash_hls1 + "&expiresh1=" + time; var url_local_hls1 = "http://192.168.2.200:65080/hls1/stream1.m3u8?sth1=" + hash_hls1 + "&expiresh1=" + time; createState('hls1',url_hls1); createState('hls1_local',url_local_hls1); setState("javascript.0.hls1",url_hls1); setState("javascript.0.hls1_local",url_local_hls1); });
4. В vis - редакторе создаём кнопку :
5. И страницу cam1:
-
Протестировав HLS и mpeg-dash пришёл к заключению что HLS-поток лучше справляется с передачей видео на медленном и нестабильном канале связи. Поэтому оставляю у себя HLS. Плюс у него ещё в том, что поток можно смотреть с любого устройства - android, apple, desktop с Windows.
Привожу настройки с секурными ссылками (актуально при просмотре через интернет) :
1. Nginx надо будет скомпилировать с такими ключами:
./configure –with-http_sub_module --with-http_secure_link_module --add-module=/path/to/nginx-rtmp-module
make; make install
2. Конфиг nginx (проверяется переданный пароль (mypassword)
` > user www-data;worker_processes 1;
pid /var/run/nginx.pid;
error_log /var/log/nginx/error.log;
events {
worker_connections 1024;
}
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
access_log /var/log/nginx/access.log;
server {
client_max_body_size 12M;
listen 65080;
root /var/www;
index main.php;
rewrite_log on;
uninitialized_variable_warn on;
server_name http://www.mysite.ru;
add_header 'Access-Control-Allow-Origin' '*';
location / {
rtmp_control all;
auth_basic "closed site";
auth_basic_user_file /etc/apache2/htpasswd.cfg;
}
location ~* .(?:ico|jpg|jpeg)$ {
expires 10m;
add_header Pragma public;
add_header Cache-Control "public";
}
location /hls1/ {
add_header 'Access-Control-Allow-Origin' '*';
root /mnt/ramdisk;
add_header Cache-Control no-cache;
secure_link $arg_sth1,$arg_expiresh1;
secure_link_md5 mypassword$arg_expiresh1;
sub_filter .ts .ts?sth1=$arg_sth1&expiresh1=$arg_expiresh1;
sub_filter_once off;
sub_filter_types *;
if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
return 410;
}
}
}
}
rtmp {
access_log /var/log/nginx/rtmp_access.log;
server {
listen 1935;
ping 30s;
notify_method get;
application hlscamera1 {
live on;
hls on;
hls_playlist_length 20s;
hls_fragment 4s;
hls_path /mnt/ramdisk/hls1;
exec_static /usr/bin/ffmpeg -thread_queue_size 5120 -i rtsp://user:password@192.168.2.30:554/Streaming/Channels/2 -thread_queue_size 5120 -f alsa -i default -map 0 -map 1 -vcodec copy -acodec libfdk_aac -ab 24k -ar 22050 -f flv rtmp://localhost:1935/hlscamera1/stream1;
}
} `
3. Скрипт, генерирующий безопасные ссылки (1 при web доступе, другая при ЛВС-доступе), задаётся пароль (mypassword) в iobroker:
schedule("* * * * *", function () { var crypto = require('crypto'); var time = Math.round(Date.now()/1000) + 10*3600; var md5_hls1 = crypto.createHash('md5').update("mypassword"+time).digest('binary'); var hash_hls1 = new Buffer(md5_hls1, "binary").toString('base64'); hash_hls1 = hash_hls1.replace(/\+/g, '-'); hash_hls1 = hash_hls1.replace(/\//g, '_'); hash_hls1 = hash_hls1.replace(/=/g, ''); var url_hls1 = "http://www.mysite.ru:65080/hls1/stream1.m3u8?sth1=" + hash_hls1 + "&expiresh1=" + time; var url_local_hls1 = "http://192.168.2.200:65080/hls1/stream1.m3u8?sth1=" + hash_hls1 + "&expiresh1=" + time; createState('hls1',url_hls1); createState('hls1_local',url_local_hls1); setState("javascript.0.hls1",url_hls1); setState("javascript.0.hls1_local",url_local_hls1); });
4. В vis - редакторе создаём кнопку :
5. И страницу cam1:
-
Протестировав HLS и mpeg-dash пришёл к заключению что HLS-поток лучше справляется с передачей видео на медленном и нестабильном канале связи. Поэтому оставляю у себя HLS. Плюс у него ещё в том, что поток можно смотреть с любого устройства - android, apple, desktop с Windows.
Привожу настройки с секурными ссылками (актуально при просмотре через интернет) :
1. Nginx надо будет скомпилировать с такими ключами:
./configure –with-http_sub_module --with-http_secure_link_module --add-module=/path/to/nginx-rtmp-module
make; make install
2. Конфиг nginx - nginx.conf (проверяется переданный пароль (mypassword)
3. Скрипт - script.txt, генерирующий безопасные ссылки (1 при web доступе, другая при ЛВС-доступе), задаётся пароль (mypassword) в iobroker.
4. В vis - редакторе создаём кнопку - but1.txt.
5. И страницу cam1 - cam1.txt.
1444_video-hls.rar -
Добрый день.
Решил заморочится тоже выводом видео с камер в IoBroker.
По инструкции выше от andrey99986 скомпилировал nginx с модулем rmtp.
Для проверки настроек пришлось выкинуть все секурные ссылки, а то не было понятно что не работает и подобрать параметры ffmpeg.
На данный момент nginx на малинке принимает поток с камеры в rstp и отдает ее rmtp.
Настроил трансляцию в HLS. С самим ngnix вроде все пока.
Добрался до iobroker, и вот тут две странности на которых я завис.
1. Первая - если урл на hls напрямую вставить в скрипт в строку hls.loadSource("http://192.168.13.232:65080/hls/stream1.m3u8"); то видео есть, если его передавать через переменную как в оригинале hls.loadSource("{javascript.0.hls1}"); то видео нет
В переменной правильный урл есть, проверял.
2. Вторая, самая странная - если указываем hls.loadSource("http://192.168.13.232:65080/hls/stream1.m3u8") то в редакторе видео есть, а на странице - нет
Почему ?
!
! -
С второй проблемой стало понятнее, после внимательного чтения темы.
Но все равно не работает..
После правки index.src.html
в результате в коде станицы blob все равно отсутствует.
и даже если в его прямо в хроме вставить , имеем ошибку :
> Refused to load media from 'blob:[http://192.168.13.232:8082/1b359eb4-402 … 01580bc8e1](http://192.168.13.232:8082/1b359eb4-4027-454c-8b65-9d01580bc8e1)' because it violates the following Content Security Policy directive: "media-src 'self' 'unsafe-inline' * blob".
Куда копать , подскажите ?
p.s. Докопался, пропустил двоеточие после blob.
-
Не придумалось случайно ничего нового? )