Neste tutorial, veremos como enviar um fluxo de vídeo de uma máquina para outra usando FFMPEG. O envio de dados entre dois dispositivos, sejam eles quais forem, é um dos principais problemas dos objectos ligados (IoT). Se pretende criar uma câmara ligada que envia vídeo para uma máquina remota, este artigo deve interessar-lhe.
Instalando o ffmpeg
Numa máquina Linux
sudo apt-get install ffmpeg
Numa máquina Windows, siga este procedimento.
N.B.: se necessário numa máquina Linux sudo apt-get install v4l-utils
Obtenha as informações necessárias para a transmissão de vídeo
Para criar um fluxo de vídeo de uma máquina para outra, as máquinas devem estar ligadas à mesma rede (Wifi ou Ethernet).
Em primeiro lugar, é necessário obter o endereço IP da máquina cliente (que recebe o fluxo)
Introduzir um terminal de comando
ifconfig #pour une machine linux
ip addr # si ifconfig n'est pas disponible
ou
ipconfig #pour une machine windows
Deve obter um endereço com o formato 192.168.X.X (no nosso caso 192.168.1.67)
Em seguida, recupere a fonte de vídeo. Para listar todas as entradas de vídeo numa máquina Linux
ls -l /dev/video*
lsusb #list usb devices
v4l2-ctl --list-devices #list video devices
Estes comandos devem ajudá-lo a identificar a fonte de vídeo. No nosso caso,
Para listar fontes de vídeo numa máquina Windows, pode utilizar o ffmpeg
ffmpeg -list_devices true -f dshow -i dummy
No nosso caso, video=”USB2.0 HD UVC WebCam “
Recuperar as opções e verificar os formatos e resoluções aceites pela câmara
no Linux
v4l2-ctl -d /dev/video0 --list-formats
no Windows
ffmpeg -f dshow -list_options true -i video="USB2.0 HD UVC WebCam"
Uma vez registados estes dados, podemos configurar o streaming.
Criar um fluxo de vídeo com o ffmpeg
Para criar um fluxo de vídeo, é necessário um emissor (servidor) e um recetor (cliente) que será reproduzido por dois terminais executados em dois computadores diferentes.
- lado do servidor linux
ffmpeg -re -f v4l2 -i /dev/video5 -r 10 -f mpegts udp://192.168.1.67:8554?pkt_size=1316
- Lado do servidor Windows
ffmpeg -f dshow -i video="USB2.0 HD UVC WebCam" -r 10 -f mpegts udp://192.168.1.67:8554?pkt_size=1316
- lado do cliente
ffplay udp://127.0.0.1:8554
Nota: Pode testar o streaming numa única máquina utilizando o endereço IP da máquina em que está a trabalhar e utilizando dois terminais, um para o servidor e outro para o cliente.
Para obter estatísticas de vídeo, pode utilizar o comando ffprobe
ffprobe udp://127.0.0.1:8554
ou, para mais pormenores,
ffprobe -show_format -show_streams udp://127.0.0.1:8554
Reduzir o tempo necessário para receber fluxos de vídeo entre duas máquinas
Existe um atraso de cerca de 15 segundos entre a transmissão e a receção do vídeo. Pode valer a pena reduzir este atraso, consoante a aplicação.
No lado do servidor, os parâmetros que afectam a velocidade de transmissão são:
- o tamanho da imagem (por exemplo, -s 800×600)
- conversão do formato do codec (por exemplo, -c:v libx264)
- o número de fotogramas por segundo ou framerate (por exemplo, -r 10)
Experimente jogar com estes parâmetros para reduzir o atraso, mantendo a qualidade suficiente.
ffmpeg -re -thread_queue_size 64 -s800x600 -i
No lado do cliente, existem várias opções que podem ser testadas a partir da documentação incluída nesta discussão.
ffplay -fflags nobuffer -probesize 32 -sync ext -vf setpts=0 udp:
Estas alterações às opções dos comandos ffmpeg e ffplay reduzem o atraso do fluxo de vídeo de 15 para cerca de 2 segundos.
Criar um fluxo HTTP com o ffmpeg
É possível criar um servidor de vídeo HTTP utilizando o VLC. A vantagem deste método é que o fluxo de vídeo pode ser transmitido para qualquer dispositivo.
- lado do servidor linux
ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#std{access=http,mux=ts,dst=:8554}'
- lado do cliente, é necessário especificar o endereço IP do servidor
ffplay http://192.168.1.9:8554
Criar um fluxo RTSP com o ffmpeg
É possível criar um servidor de vídeo HTTP utilizando o VLC. A vantagem deste método é que o fluxo de vídeo pode ser transmitido para qualquer dispositivo.
- lado do servidor linux
ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#rtp{sdp=rtsp://:8554/} --sout-all --sout-keep'
- lado do cliente, é necessário especificar o endereço IP do servidor
ffplay rtsp://192.168.1.9:8554/
Script Python para iniciar o streaming
Aqui está um script Python que lhe permitirá testar os diferentes métodos de streaming e os parâmetros do ffmpeg.
import subprocess #UDP #input client ip address here 192.168.1.9 stream_video="ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts udp://192.168.1.9:8554?pkt_size=1316" #on client side ffplay udp://127.0.0.1:8554 #HTTP stream_video="ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#std{access=http,mux=ts,dst=:8554}'" #on client side ffplay http://192.168.1.73:8554 #RSTP stream_video="ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vcodec copy -f mpegts -|vlc -I dummy - --sout='#rtp{sdp=rtsp://:8554/} --sout-all --sout-keep'" #on client side ffplay rtsp://192.168.1.73:8554/ # don't forget / at the end try: subprocess.call(stream_video,shell=True) except: pass print("Done")
Bónus: Apresentar o fluxo de vídeo FFMPEG com OpenCV
Uma vez que o fluxo de vídeo tenha sido estabelecido entre as duas máquinas, o OpenCV pode ser usado para ler e exibir as imagens do fluxo UDP.
import cv2 def main(args): #cap = cv2.VideoCapture(0) #default camera cap = cv2.VideoCapture('udp://127.0.0.1:8554') #cap = cv2.VideoCapture('http://192.168.1.9:8554') #cap = cv2.VideoCapture('rtsp://192.168.1.9:8554/') while(True): ret, frame = cap.read() if ret: #necessary if packet is lost frame=cv2.resize(frame, (800, 600)) cv2.imshow('Capturing',frame) if cv2.waitKey(1) & 0xFF == ord('q'): #click q to stop capturing break cap.release() cv2.destroyAllWindows() return 0 if __name__ == '__main__': import sys sys.exit(main(sys.argv))
Bónus2 : Mostrar a hora no vídeo
Para mostrar a hora no vídeo, vamos utilizar o filtro drawtext do ffmpeg, que utiliza um determinado parâmetro de texto
- fontfile: tipo de letra utilizado
- fontsize: tamanho do texto
- fontcolor: cor do texto
"drawtext=fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf: text='%{localtime\:%T}': fontsize=24: fontcolor=white@0.8: x=7: y=460"
O filtro é aplicado com a etiqueta -vf. Aqui está o comando completo
ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vf "drawtext=fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf: text='%{localtime\:%T}': fontsize=24: fontcolor=white@0.8: x=7: y=460" -vcodec copy -f mpegts udp://192.168.1.9:8554?pkt_size=1316
Em python
stream_cmd="""ffmpeg -input_format h264 -video_size 1280x720 -framerate 30 -i /dev/video0 -vf "drawtext=fontfile=/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans-Bold.ttf: text='%{localtime\:%T}': fontsize=24: fontcolor=white@0.8: x=7: y=460" -vcodec copy -f mpegts udp://192.168.1.9:8554?pkt_size=1316"""
Útil para imitar uma câmara CCTV ou para comparar tempos de câmaras diferentes