En el artículo "Cámara 4G y WiFi con Raspberry Pi" expliqué como configurar Motion para detectar movimientos y ver la imagen de la cámara remotamente. En el artículo "Detección de ruido con ARecord" expliqué como utilizar un micrófono para monitorizar el sonido y detectar ruidos. En este artículo voy a transmitir el vídeo de la cámara junto al audio de un micrófono mediante el software VLC.
Con el comando cvlc podemos ver desde la línea de comandos cualquier dispositivo de vídeo V4L. Con los parámetros width y height podemos fijar el ancho y alto de la imagen. Con el parámetro --input-slave podemos añadir el audio de un dispositivo ALSA, como por ejemplo un micrófono. En el artículo "Detección de ruido con ARecord" ya expliqué como utilizar micrófonos. Si estamos ejecutando Motion u otro programa que acceda al dispositivo de vídeo será necesario utilizar V4L2Loopback, como expliqué en el artículo "Grabación Continua de Vídeo con Motion".
# cvlc v4l2:///dev/video0:width=320:height=240 --input-slave=alsa://hw:1,0
Con cvlc, además de ver y escuchar fuentes de vídeo y audio, podemos usar el parámetro --sout para transmitirlas a través de la red mediante diferentes codificaciones y protocolos. Por ejemplo podemos codificar el vídeo con H.264, codificar el audio con ACC, mezclar el vídeo y el audio con MPEG TS y transmitirlo por HTTP. cvlc tiene un servidor HTTP que recibe conexiones en la dirección y puerto que le indiquemos. Si no se le indica la dirección, escucha en todos los interfaces de red.
# cvlc v4l2:///dev/video0:width=320:height=240 --input-slave=alsa://hw:1,0 --sout="#transcode{vcodec=h264,venc=x264{qp=35},fps=15,acodec=mp4a,ab=128,channels=1,samplerate=22050}:standard{access=http,mux=ts,dst=:8080/}"
Si como expliqué en el artículo "Cámara 4G y WiFi con Raspberry Pi", creamos una redirección de puerto en el router de acceso a internet y utilizamos DNS dinámico para asignar un nombre de equipo y dominio, podremos ver y oír la transmisión desde cualquier equipo conectado a internet. Podemos utilizar cualquier puerto que tengamos libre.
# cvlc http://camera.example.com:25827/
Si queremos limitar quien puede acceder a la transmisión podemos utilizar el protocolo HTTPS para cifrar la comunicación y HTTP Basic Auth para requerir un usuario y contraseña.
# cvlc v4l2:///dev/video0:width=320:height=240 --input-slave=alsa://hw:1,0 --sout="#transcode{vcodec=h264,venc=x264{qp=35},fps=15,acodec=mp4a,ab=128,channels=1,samplerate=22050}:standard{access=https{user=user,pwd=abc},mux=ts,dst=8443/}" --http-cert="cert.pem" --http-key="key.pem" # cvlc https://user:[email protected]:25827/
Podemos usar un certificado digital firmado por una autoridad de certificación o crear un certificado autofirmado. Si utilizamos un certificado autofirmado, en la primera conexión recibiremos una alerta de que el certificado no es de confianza y tendremos que añadir una excepción a este certificado para las siguientes conexiones.
# openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ES State or Province Name (full name) [Some-State]:Madrid Locality Name (eg, city) []:Madrid Organization Name (eg, company) [Internet Widgits Pty Ltd]:Cameras Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:camera.example.com Email Address []:[email protected]
El servidor HTTP que incorpora cvlc tiene capacidades limitadas. Por ejemplo solo permite un usuario y contraseña. Además hay que incluir la contraseña en la ejecución del comando, por lo que puede ser vista por otros usuarios del sistema ejecutando ps -Af. Si necesitamos más usuarios y seguridad es posible realizar la trasmisión a través de un servidor HTTP configurado como proxy inverso.
Podemos utilizar cvlc para transmitir por HTTP localmente y un servidor como Apache para la comunicación HTTPS y la autenticación. Al utilizar VLC como reproductor también es conveniente usar la versión gráfica para no tener que escribir la contraseña en la línea de comandos. Para evitar que se pueda conectar directamente al servidor HTTP de cvlc podemos hacer que no acepte conexiones desde otros equipos utilizando localhost como dirección de escucha.
cvlc v4l2:///dev/video0:width=320:height=240 --input-slave=alsa://hw:1,0 --sout="#transcode{vcodec=h264,venc=x264{qp=35},fps=15,acodec=mp4a,ab=128,channels=1,samplerate=22050}:standard{access=http,mux=ts,dst=localhost:8080/}"
Las siguientes instrucciones son para Debian GNU/Linux. En otros sistemas operativos puede ser necesario utilizar otros comandos y editar otros archivos. Para configurar Apache como proxy inverso debemos activar los módulos proxy y proxy_http con el comando a2enmod o creando enlaces simbólicos en el directorio /etc/apache2/mods-enabled/.
# apt-get install apache2 # a2enmod proxy # a2enmod proxy_http
Si queremos que la comunicación sea con el protocolo HTTPS también debemos activar el módulo ssl. En Debian hay dos hosts virtuales: 000-default para HTTP y default-ssl para HTTPS. Para utilizar HTTPS podemos activar el host default-ssl o crear un nuevo host. La activación se puede hacer con el comando a2ensite o creando enlaces simbólicos en el directorio /etc/apache2/sites-enabled/.
También podemos desactivar el host 000-default con el comando a2dissite o eliminando su enlace simbólico. El certificado y la clave privada se deben copiar a un directorio accesible por el usuario que ejecuta el servidor (www-data). La clave privada no debe estar accesible a otros usuarios.
# a2enmod ssl # a2ensite default-ssl # a2dissite 000-default # cp cert.pem /etc/ssl/certs/camera.example.com-cert.pem # cp key.pem /etc/ssl/private/camera.example.com-key.pem
En el archivo /etc/apache2/ports.conf se le indica al servidor los puertos en los que debe aceptar conexiones. Podemos comentar la línea del puerto 80 para que no acepte conexiones HTTP y solo dejar la del puerto 443 para conexiones HTTPS. Si ya utilizamos el puerto 443 para otro servidor podemos indicar un puerto diferente.
# vi /etc/apache2/ports.conf #Listen 80 <IfModule ssl_module> #Listen 443 Listen 25827 </IfModule>
En el archivo de configuración del host virtual default-ssl es necesario indicar el puerto de escucha y la dirección de los archivos del certificado y la clave privada. Mediante las directivas ProxyPass y ProxyPassReverse se configura la conexión al servidor de transmisión de vídeo y audio. En primer lugar se indica la dirección donde mostrar los datos recibidos del servidor. En segundo lugar se indica la dirección del servidor. Podemos utilizar varias directivas ProxyPass/ProxyPassReverse para mostrar varias cámaras.
# vi /etc/apache2/sites-enabled/default-ssl.conf <VirtualHost *:25827> SSLCertificateFile /etc/ssl/certs/camera.example.com-cert.pem SSLCertificateKeyFile /etc/ssl/private/camera.example.com-key.pem ProxyPass /camera http://localhost:8080/ ProxyPassReverse /camera http://localhost:8080/ </VirtualHost>
Al utilizar un servidor HTTP también tenemos la posibilidad de añadir una página HTML con reproductor para poder ver y escuchar la transmisión con un navegador web. Dependiendo de la codificación que hayamos utilizado necesitaremos un reproductor diferente. Para H.264/AAC/MPEGTS podemos usar MPEGTS.JS. Debemos descargar los archivos mpegts.js y mpegts.js.map y copiarlos al directorio raíz del host virtual.
# vi /var/www/html/index.html # cp mpegts.js /var/www/html/ # cp mpegts.js.map /var/www/html/
En el archivo HTML hay que incluir un elemento video y asignarle el reproductor MPEGTS.JS. Este se encarga de leer los datos de la transmisión y mostrarlos en el elemento video. Al reproductor hay que indicarle la URL de la cámara.
<!DOCTYPE html> <html> <body> <h1>Camera</h1> <script src="mpegts.js"></script> <video id="camera" width="320" height="240"></video> <script> var camera = document.getElementById("camera"); var player = mpegts.createPlayer({type: "mpegts", isLive: true, url: "/camera"}); player.attachMediaElement(camera); player.load(); player.play(); </script> </body> </html>
Para que la transmisión esté protegida mediante HTTP Basic Auth hay que activar los módulos authn_file y authz_groupfile. authn_file permite almacenar en un archivo usuarios y sus contraseñas encriptadas. Con el comando htpasswd se añaden usuarios al archivo. La primera vez que se ejecuta es necesario utilizar el parámetro -c para indicarle que tiene que crear el archivo. Es necesario dar permiso de lectura sobre el archivo al grupo del usuario que ejecuta el servidor Apache (www-data) y quitárselo al resto de usuarios.
# a2enmod authn_file # a2enmod authz_groupfile # htpasswd -c /etc/apache2/users user1 New password: Re-type new password: Adding password for user user1 # htpasswd /etc/apache2/users user2 New password: Re-type new password: Adding password for user user2 # htpasswd /etc/apache2/users user3 New password: Re-type new password: Adding password for user user3 # cat /etc/apache2/users user1:$apr1$xonOu45i$ym2OB5VXPK5au.MWdDirK0 user2:$apr1$Y7F03ID6$NDi3v063gg8IMJNsqnck70 user3:$apr1$997WdGEG$htmA7fuLqnEx6RCDW0/l2. # chgrp www-data /etc/apache2/users # chmod 640 /etc/apache2/users
El módulo authz_groupfile permite crear un archivo con grupos de usuarios. Esto hace posible dar permisos a todos los usuarios de un grupo en lugar de tener que dar permisos a cada uno de los usuarios. La configuración de autentificación la podemos hacer en una directiva Directory para el directorio raíz y en una directiva Proxy para el proxy. Si queremos aplicar la misma configuración al directorio raíz y al proxy podemos utilizar una directiva Location para todas las direcciones. Una vez configurado Apache debemos reiniciarlo.
# vi /etc/apache2/groups camera: user1 user2 user3 # vi /etc/apache2/sites-enabled/default-ssl.conf <Location /> AuthType Basic AuthName "Camera" AuthBasicProvider file AuthUserFile "/etc/apache2/users" AuthGroupFile "/etc/apache2/groups" Require group camera </Location> # systemctl restart apache2
Para que cvlc se ejecute automáticamente al iniciar el sistema es necesario crear un servicio de Systemd y activarlo. El usuario que ejecute el servicio debe pertenecer a los grupos video y audio para acceder a la cámara y el micrófono. El comando a ejecutar dependerá de si queremos transmitir directamente con cvlc o a través de un servidor HTTP.
# useradd streaming -G video,audio # vi /lib/systemd/system/streaming.service [Unit] Description=Streaming [Service] Type=simple User=streaming ExecStart=cvlc v4l2:///dev/video0:width=320:height=240 --input-slave=alsa://hw:1,0 --sout="#transcode{vcodec=h264,venc=x264{qp=35},fps=15,acodec=mp4a,ab=128,channels=1,samplerate=22050}:standard{access=http,mux=ts,dst=localhost:8080/}" [Install] WantedBy=multi-user.target # systemctl enable streaming
Cuando tengamos todo configurado y funcionando podemos conectar a la página con un navegador web o a la cámara con un reproductor de vídeo que permita utilizar HTTPS Y HTTP Basic Auth. Si hemos utilizado un certificado autofirmado también necesitamos que el reproductor permita añadir excepciones a certificados no firmados por una autoridad de certificación. En el caso de VLC es necesario utilizar la versión gráfica. En el navegador debemos dar permiso a la página para reproducir vídeo y audio.
# firefox https://camera.example.com:25827 # vlc https://camera.example.com:25827/camera
Esto nos permite ver el vídeo de la cámara y escuchar el audio del micrófono a través de internet de forma segura con cualquier navegador o reproductor de vídeo. En un próximo articulo añadiré al archivo HTML la posibilidad de enviar el audio del micrófono del cliente a un altavoz conectado al servidor para poder realizar una comunicación de audio bidireccional.