Стриминг видео c USB камеры через SSH
Было такое дело, собрался я в отпуск. При этом, хотелось иногда поглядывать «что дома творится». Благо, небольшой безголовый сервер на базе моноплатного компьютера имелся, а найти в домашних завалах пару USB-камер тоже не составило труда.
Linux и другие Unix-like: Один из вариантов подключения
Итак, имеем:
Моноплатный ПК на базе Cubieboard Cubietruck, с подключенными USB камерами, ОС на базе одной из дебиановских сборок Linux под arm.
Хотим:
Максимально простое удалённое подключение к видеокамере.
Рассматриваемых вариантов подключения к камерам было несколько:
Первый вариант
Запустить X приложение через ssh (проброс событий X-сервера, ssh -X и т.д.), в принципе, это раньше работало без проблем из коробки, когда я подключался к удалённому рабочему столу на Linux и хотел посмотреть веб-камеру. (Или почти из коробки, такой вариант весьма сильно подтормаживает). Но в данном случае это решение не работало, т. к. на моноплатном компе X-сервер отсутствовал, и приложения, работающие с ним, тоже.
Второй вариант
Веб-стриминг. Можно было запустить что-то вроде VLC без интерфейса, чтобы он передавал данные на определённом порту через какой-то протокол вроде RTSP, но это выглядело не очень безопасным по сравнению с SSH, да и захламлять память моноплатного компа тяжелыми приложениями не хотелось.
В итоге, мне внезапно пришла следующая идея: а что если читать видеоустройство в stdout по SSH, а потом этот stdout будет обрабатывать уже программа на локальном компе? Ведь SSH позволяет локальным приложениям читать вывод удалённых приложений, если задать правильную команду. И я приступил к экспериментам.
Для начала, необходимо предоставить доступ к видеоустройству на удалённом компьютере (с видеокамерами) для текущего пользователя, не root. Устройства /dev/video* имеют группу video, членом которой мой пользователь по умолчанию не являлся. Исправляем:
sudo usermod -a -G video user
где user — имя текущего пользователя.
Особенность видеоустройств в том, что просто через cat или dd их содержимое в stdout не отправишь, они выдадут ошибку. Нужна программа, которая сделает видеопоток пригодным к «потреблению». Сначала мой выбор пал на ffmpeg. В качестве локального плеера я использовал VLC, но подойдёт любой другой, умеющий читать stdin.
Ставим ffmpeg на компьютер с видеокамерами, и на удалённом компе запускаем:
ssh user@server ffmpeg -an -f video4linux2 -s 320x240 -i /dev/video0 -r 12 -b:v 30k -f ogg — | vlc -
где user — имя текущего пользователя, server — сервер для подключения.
Вкратце, эта команда использует драйвер video4linux2 для чтения видеовывода /dev/video0 (у вас может быть другой), и жмет его в ogg с размером кадра 320х240 12 кадров в секунду, а затем направляет его в stdout, который, в свою очередь, читается локальным плеером VLC. Схема рабочая, но на arm-компе немного подтормаживающая.
И тут я вспомнил об утилите streamer. Она позволяет создавать легковесные видеофайлы с камеры, при этом не сильно занимая процессорное время. Проблема в том, что данная программа не умеет писать в stdout, но мы можем ее научить :)
Для начала создадим именованный pipe для нашей программы, через команду mkfifo.
mkfifo dummyavi.avi
Эта команда создает такой «файл», при записи в который приложение блокируется до тех пор, пока этот файл кто-то не начнет читать, при этом на диске ничего сохраняться не будет, данные пойдут от пишущего приложения в читающее напрямую.
Теперь запускаем наш конвеер (не забыв установить streamer). Streamer пишет данные в наш fifo pipe, оттуда их забирает cat, который, в свою очередь, гонит их в stdout для локального плеера VLC.
ssh user@server '(streamer -c /dev/video0 -t 0:30 -r 24 -o dummyavi.avi -f jpeg > /dev/null & cat dummyavi.avi)' | vlc -
В данной команде интересен параметр -t — это время записи. Де-факто, он означает, что файл будет писаться в течение 30 секунд. Если мы хотим непрерывное наблюдение, этот параметр стоит попробовать сделать очень большим. Кстати, в принимающем плеере не стоит выбирать видеовывод VDPAU — он с выводом streamer не справится.
Качество видео не очень хорошее, зато не тормозит даже на слабом компе при достаточно медленной связи.
Linux и другие Unix-like: Один из вариантов подключения
Итак, имеем:
Моноплатный ПК на базе Cubieboard Cubietruck, с подключенными USB камерами, ОС на базе одной из дебиановских сборок Linux под arm.
Хотим:
Максимально простое удалённое подключение к видеокамере.
Рассматриваемых вариантов подключения к камерам было несколько:
Первый вариант
Запустить X приложение через ssh (проброс событий X-сервера, ssh -X и т.д.), в принципе, это раньше работало без проблем из коробки, когда я подключался к удалённому рабочему столу на Linux и хотел посмотреть веб-камеру. (Или почти из коробки, такой вариант весьма сильно подтормаживает). Но в данном случае это решение не работало, т. к. на моноплатном компе X-сервер отсутствовал, и приложения, работающие с ним, тоже.
Второй вариант
Веб-стриминг. Можно было запустить что-то вроде VLC без интерфейса, чтобы он передавал данные на определённом порту через какой-то протокол вроде RTSP, но это выглядело не очень безопасным по сравнению с SSH, да и захламлять память моноплатного компа тяжелыми приложениями не хотелось.
В итоге, мне внезапно пришла следующая идея: а что если читать видеоустройство в stdout по SSH, а потом этот stdout будет обрабатывать уже программа на локальном компе? Ведь SSH позволяет локальным приложениям читать вывод удалённых приложений, если задать правильную команду. И я приступил к экспериментам.
Для начала, необходимо предоставить доступ к видеоустройству на удалённом компьютере (с видеокамерами) для текущего пользователя, не root. Устройства /dev/video* имеют группу video, членом которой мой пользователь по умолчанию не являлся. Исправляем:
sudo usermod -a -G video user
где user — имя текущего пользователя.
Особенность видеоустройств в том, что просто через cat или dd их содержимое в stdout не отправишь, они выдадут ошибку. Нужна программа, которая сделает видеопоток пригодным к «потреблению». Сначала мой выбор пал на ffmpeg. В качестве локального плеера я использовал VLC, но подойдёт любой другой, умеющий читать stdin.
Ставим ffmpeg на компьютер с видеокамерами, и на удалённом компе запускаем:
ssh user@server ffmpeg -an -f video4linux2 -s 320x240 -i /dev/video0 -r 12 -b:v 30k -f ogg — | vlc -
где user — имя текущего пользователя, server — сервер для подключения.
Вкратце, эта команда использует драйвер video4linux2 для чтения видеовывода /dev/video0 (у вас может быть другой), и жмет его в ogg с размером кадра 320х240 12 кадров в секунду, а затем направляет его в stdout, который, в свою очередь, читается локальным плеером VLC. Схема рабочая, но на arm-компе немного подтормаживающая.
И тут я вспомнил об утилите streamer. Она позволяет создавать легковесные видеофайлы с камеры, при этом не сильно занимая процессорное время. Проблема в том, что данная программа не умеет писать в stdout, но мы можем ее научить :)
Для начала создадим именованный pipe для нашей программы, через команду mkfifo.
mkfifo dummyavi.avi
Эта команда создает такой «файл», при записи в который приложение блокируется до тех пор, пока этот файл кто-то не начнет читать, при этом на диске ничего сохраняться не будет, данные пойдут от пишущего приложения в читающее напрямую.
Теперь запускаем наш конвеер (не забыв установить streamer). Streamer пишет данные в наш fifo pipe, оттуда их забирает cat, который, в свою очередь, гонит их в stdout для локального плеера VLC.
ssh user@server '(streamer -c /dev/video0 -t 0:30 -r 24 -o dummyavi.avi -f jpeg > /dev/null & cat dummyavi.avi)' | vlc -
В данной команде интересен параметр -t — это время записи. Де-факто, он означает, что файл будет писаться в течение 30 секунд. Если мы хотим непрерывное наблюдение, этот параметр стоит попробовать сделать очень большим. Кстати, в принимающем плеере не стоит выбирать видеовывод VDPAU — он с выводом streamer не справится.
Качество видео не очень хорошее, зато не тормозит даже на слабом компе при достаточно медленной связи.
0 комментариев