Etiquetas: , ,

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 
raspi-ifconfig Transmitir vídeo entre duas máquinas com FFMPEG

ou

ipconfig #pour une machine windows
window-ipconfig-ip-subnet-gateway Transmitir vídeo entre duas máquinas com FFMPEG

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,

debian-v4l2-list-devices Transmitir vídeo entre duas máquinas com FFMPEG

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 “

ffmpeg-list-devices-windows Transmitir vídeo entre duas máquinas com FFMPEG

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.

ffmpeg-streaming-between-machines-result Transmitir vídeo entre duas máquinas com FFMPEG

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))
streaming-between-ffmpeg-opencv-result Transmitir vídeo entre duas máquinas com FFMPEG

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

ffmpeg-timestamp-videox2 Transmitir vídeo entre duas máquinas com FFMPEG

Aplicações

Fontes