Streaming de Video con Java en Raspberry Pi
Hay dos modos de crear streming, uno es capturando las fotos (jpeg) que se toman con raspistill, el otro modo es capturando el vídeo (h264) generado con raspivid, como se observa en el tutorial de: Streaming Video desde el Raspberry Pi, ahora se va generar este streaming con Java.
Como funciona?
Proyectos necesarios vía GitHub:
git clone https://github.com/andrexweb/raspberry-pi.git
Proyecto Maven: StreamingPi
Proyecto Maven: StreamingPi
git clone https://github.com/andrexweb/java.git
Proyecto Maven: H264J
Proyecto Maven: H264J
El server, es un servidor de paquetes UDP (Datagrama) que esta en el proyecto StreamingPi, el cual solo recibe el flujo de datos, dependiendo de la opción que se incluya jpeg o h264 se activa el reproductor correspondiente, para el caso de h264, es un codec escrito en java que es un "port" de la libreria ffmpeg-libavcodec (pero solo la parte de h264). El proyecto original esta en Google Code h264j, pero copie el proyecto y agregue unas mínimas modificaciones para que reciba el streaming de forma directa, proyecto H264J.
Proyecto disponible en:
GitHub: https://github.com/andrexweb/java
Original: https://code.google.com/p/h264j/
En el momento el reproductor de fotos/vídeo (jpeg/h264) es básico, solo muestra imágenes, próximamente mas opciones.
Para el lado del cliente, es UDP, solo envía lo que genera los aplicativos raspistill y raspisvid, no se usa el modo normal de "pipe" (|), el api de Java cuenta con con una clase que permite la ejecución de comandos y obtener el "stdout" vía inputStreaming.
Ejemplo:
//command: lista de parametros, primero parametro es el comando a ejecutar.
ProcessBuilder processBuilder = new ProcessBuilder(command);
//Se incia el proceso y se obtiene el inpuStream de la ejecucion, esto es lo que se envía por UDP.
Process process = processBuilder.start();
InputStream inputStream = process.getInputStream();
Ver Clase para ver implementación completa: org.avpsoft.streaming.net.DatagramCommandClient.java
ProcessBuilder processBuilder = new ProcessBuilder(command);
//Se incia el proceso y se obtiene el inpuStream de la ejecucion, esto es lo que se envía por UDP.
Process process = processBuilder.start();
InputStream inputStream = process.getInputStream();
Ver Clase para ver implementación completa: org.avpsoft.streaming.net.DatagramCommandClient.java
Uso
Opción con raspistill
Primero ejecutamos el servidor (en windows), quien recibe el streaming:
D:\GitHub\raspberry-pi\StreaminPi>java -cp ./target/StreamingPi-1.0-SNAPSHOT.jar org.avpsoft.streaming.main.Streaming 4445 jpeg
Esto nos abre una ventana, donde se mostrara las imágenes.
Ahora ejecutamos el servidor (Raspberry Pi):
pi@raspberrypi ~ $ java -cp ./StreamingPi-1.0-SNAPSHOT.jar org.avpsoft.streaming.main.Streaming 192.168.1.2 4445 raspistill -n -t 0 -tl 150 -th 0:0:0 -w 640 -h 480 -q 5 -o -
Las primeras dos opciones es la ip del servidor y el puerto son fijas, no puede cambiar el orden.
Ejemplo del "lag" (retraso generado) al usar este metodo, 4 segundos, el mejor tiempo que pude registrar estuvo en 3 segundos.
Opción con raspivid
Se requiere este jar adicional H264J-1.0-SNAPSHOT.jar, para el codec h264.
Primero ejecutamos el servidor (en windows), quien recibe el streaming:
D:\GitHub\raspberry-pi\StreaminPi>java -cp ./*.jar org.avpsoft.streaming.main.Streaming 4445 h264
Esto nos abre una ventana, donde se mostrara las imágenes.
Ahora ejecutamos el servidor (Raspberry Pi):
pi@raspberrypi ~ $ java -cp ./StreamingPi-1.0-SNAPSHOT.jar org.avpsoft.streaming.main.Streaming 192.168.1.2 4445 raspivid -n -t 0 -w 640 -h 480 -fps 10 -o -
Las primeras dos opciones es la ip del servidor y el puerto son fijas, no puede cambiar el orden.
Ejemplo del "lag" (retraso generado) al usar este método, es de menos de 1 segundo, mas o menos 300 milisegundos.
Problemas:
* Debido a que se usa UDP y no TCP, es posible que las imágenes se distorsionen, pero es causado por la fiabilidad de la red, si tiene mala señal WIFI eso pasara.
* Cuando se ejecuta el server con h264, es posible que salga errores, pero el streaming sigue funcionando.
* Para terminan la ejecución use Ctrl+C