Estou usando o ffmpeg para ler de uma placa de captura de quatro entradas e gerar 3 fluxos simultâneos:
- Sobreposição HDMI1+2 -> rtsp://localhost:5545/hud1
- Sobreposição HDMI1+3 -> rtsp://localhost:5545/hud2
- Somente HDMI1 -> rtsp://localhost:5545/vis
Este comando de entrada 1+2 levou algum tempo, mas funciona muito bem.
SOURCE1=(-f decklink -i 'DeckLink Quad HDMI Recorder (1)')
SOURCE2=(-f decklink -i 'DeckLink Quad HDMI Recorder (2)')
# Scale inputs, and transpose black pixels to alpha on the overlay
FILTER=(-filter_complex "
[0:v]scale=960:540[base];
[1:v]scale=540:540,colorkey=black:0.1:0.1[overlay];
[base][overlay]overlay=(W-w)/2:(H-h)/2
")
ENCODING_OPTIONS=(
-c:v libx264 # x264 codec
-preset fast # Balances latency, quality, bandwidth
-crf 18 # 18 = visually lossless. That's good enough
-an # Strip out audio
)
STREAMING_OPTIONS=(
-b:v 5000k # Target 5000 kbps bitrate
-maxrate 5500k # Should be a little higher than target to allow catchup
-bufsize 4000k # Bigger buffer is better for stability but reduces latency
-r30 # Don't need 60fps,
-tune zerolatency
)
SINK=(-f rtsp rtsp://localhost:5545/hud1)
ffmpeg \
"${SOURCE1[@]}" \
"${SOURCE2[@]}" \
"${FILTER[@]}" \
"${ENCODING_OPTIONS[@]}" \
"${STREAMING_OPTIONS[@]}" \
"${SINK[@]}"
O problema:
O driver não permitirá que duas instâncias ffmpeg ouçam o mesmo canal. Se eu estiver executando HDMI1+2 e, em seguida, tentar transmitir somente HDMI1, obtenho:
Error opening input: Input/output error
Error opening input file DeckLink Quad HDMI Recorder (1)
Tentativa 1: faça um loopback do RTSP:
FUNCIONA se eu executar "Input 1 only" primeiro, depois usar para executar e . No entanto , com minha configuração, cada salto RTSP adiciona ~2s de latência. Isso significa que o Input 1 fica atrás da sobreposição em ~2s.SOURCE1=(-i rtsp://localhost/base)
Input 1+2
Input 1+3
Tentativa 2: /dev/shm
Tentei gerar "Input 1 only" para SINK=(-f shm /dev/shm/base)
, esperando ler isso dos fluxos Input1+2 e Input1+3. Eu esperava que manter isso local eliminaria a latência.
Requested output format 'shm' is not known.
Tentativa 3: unix://
Eu tentei soquetes de domínio unix definindo o SINK=(-f mpegts -listen 1 unix:/run/user/1000/base.socket)
com a intenção de usar SOURCE1=(-i unix:/run/user/1000/base.socket)
, mas acabei com :
Unable to choose an output format for 'unix:/run/user/1000/base.socket'; use a standard extension for the filename or specify the format manually.
Então tentei usar uma extensão diferente:
SINK=(-f mpegts -listen 1 unix:/run/user/1000/base.mkv)
Mas quando tento ler com Input1+2, obtenho:
Could not find codec parameters for stream 1 ...: unspecified frame size
...
Output file does not contain any stream
Tentativa nº 4: Tudo em um:
Sinto que essa é provavelmente a solução, mas não está bem lá. Tentei usar o split=3
filtro e -map
o recurso para fazer tudo em uma instância ffmpeg, mas a resolução da imagem base quando há uma sobreposição é muito, muito pior. Não tenho certeza se minhas opções de streaming são por stream ou talvez compartilhadas entre todos os três streams.
VISUAL_SOURCE=(-f decklink -i 'DeckLink Quad HDMI Recorder (1)' )
HUD1_SOURCE=( -f decklink -i 'DeckLink Quad HDMI Recorder (2)' )
HUD2_SOURCE=( -f decklink -i 'DeckLink Quad HDMI Recorder (3)' )
FILTER_PAIR=(-filter_complex "
[0:v]scale=960:540,split=3[vis0][vis1][vis2];
[1:v]scale=540:540,colorkey=black:0.1:0.1[hud1];
[2:v]scale=540:540,colorkey=black:0.1:0.1[hud2];
[vis1][hud1]overlay=(W-w)/2:(H-h)/2[hud1overlay];
[vis2][hud2]overlay=(W-w)/2:(H-h)/2[hud2overlay]
")
ENCODING_OPTIONS=(
-c:v libx264
-preset fast
-crf 18
-an
)
STREAMING_OPTIONS=(
-b:v 5000k
-maxrate 5500k
-bufsize 4000k
-r 30
-tune zerolatency
-xerror
)
SINK1=(-map '[vis0]' -f rtsp rtsp://localhost:5545/vis)
SINK2=(-map '[hud1overlay]' -f rtsp rtsp://localhost:5545/hud1)
SINK3=(-map '[hud2overlay]' -f rtsp rtsp://localhost:5545/hud2)
ffmpeg \
"${VISUAL_SOURCE[@]}" \
"${HUD1_SOURCE[@]}" \
"${HUD2_SOURCE[@]}" \
"${FILTER_PAIR[@]}" \
"${ENCODING_OPTIONS[@]}" \
"${STREAMING_OPTIONS[@]}" \
"${SINK1[@]}" \
"${SINK2[@]}" \
"${SINK3[@]}"
A primeira saída rtsp://.../base
(a FONTE1 bruta) parece ótima (semelhante à minha tentativa original com apenas 2 entradas e uma saída), mas rtsp://.../hud1
( rtsp://.../hud2
FONTE 2/3 sobre FONTE 1) tem uma resolução terrível.
A tentativa nº 4 é a abordagem correta.
O problema é que as opções de streaming
-b:v 5000k -maxrate 5500k -bufsize 4000k
são aplicadas globalmente (compartilhadas entre todos os três streams). Portanto, o primeiro stream monopoliza esse recurso, deixando sobras para os outros dois. Mesmo ao triplicar os parâmetros, o primeiro stream ainda pega o máximo que pode usar.A resposta é especificar as opções de streaming por fluxo: