2016-02-11 39 views
6

Sto provando a convertire stream udp in frame usando ffmpeg. Corro seguente comando:Buffering durante la conversione di stream in frame con ffmpeg

ffmpeg -loglevel debug -strict 2 -re -i "udp://192.168.15.50:3200?fifo_size=1000000&overrun_nonfatal=1" -r 8 -vf scale=432:243 -f image2pipe -vcodec ppm pipe:1 

accade con diversi tipi di flusso, mpeg2video e H264. Carico di CPU per l'elaborazione del core questo flusso specifico è inferiore al 30%, il suo flusso sd di bassa qualità con risoluzione di 640x576.

Funziona bene per la maggior parte del tempo, tuttavia a volte, una volta ogni tanto, la latenza si verifica ei frame arrivano più tardi. Quindi voglio esattamente 8 fps ma a volte ottengo meno, a volte di più.

Perché si verifica questa latenza e come posso ridurla?

Aggiornamento: Ho provato a cambiare a:

ffmpeg -loglevel debug -i "udp://192.168.15.50:3200?fifo_size=1000000&overrun_nonfatal=1" -r 8 -preset ultrafast -fflags nobuffer -vf scale=432:243 -f image2pipe -vcodec ppm pipe:1 

Ma ho ancora ottenere il problema. Ad esempio, nel registro ffmpeg ottengo:

[2016/02/11 13:32:30] frame= 7477 fps=8.0 q=-0.0 size= 2299638kB time=00:15:34.62 bitrate=20156.4kbits/s dup=7 drop=15867 ^M*** dropping frame 7477 from stream 0 at ts 7475 
[2016/02/11 13:32:30] ***dropping frame 7477 from stream 0 at ts 7476 
[2016/02/11 13:32:30] ***dropping frame 7478 from stream 0 at ts 7476 
[2016/02/11 13:32:32] Last message repeated 1 times 
[2016/02/11 13:32:32] frame= 7479 fps=8.0 q=-0.0 size= 2300253kB time=00:15:34.87 bitrate=20156.4kbits/s dup=7 drop=15871 ^M*** dropping frame 7479 from stream 0 at ts 7477 

Come si può vedere, durante il secondo 31, non cornici sono in uscita ... e ffmpeg segnalati tempo tra due fotogrammi è il comando 0.25s

risposta

10

ffmpeg ha scritto in la domanda viene normalmente convogliata in un altro binario. Quel binario salva i frame forniti da ffmpeg e fa qualche elaborazione su di essi.

All'inizio ho provata "fifo_size = 1000000 & overrun_nonfatal = 1" opzioni, e mi è stato sempre seguente errore da ffmpeg

[udp @ 0x4ceb8a0] Circular buffer overrun. To avoid, increase fifo_size URL option. To survive in such case, use overrun_nonfatal option 
udp://192.168.15.50:3200: Input/output error 

e poi ffmpeg potrebbe andare in crash. Per evitarlo ho aggiunto "fifo_size = 1000000 & overrun_nonfatal = 1", come suggerisce ffmpeg.

Tuttavia, dopo aver utilizzato questi parametri, otterrei il timeshift come descritto in questione, ea volte anche con gli artefatti nei frame.

Come accennato, non ci sono stati problemi con la CPU. quindi inizialmente, si sospetta il flusso UDP, specificamente udp dimensione del buffer:

https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups-perf-udpbuffer.html

quindi abbiamo cambiato dimensione del buffer UDP con:

sysctl -w net.core.rmem_max=26214400 

e cambiato comando ffmpeg per "udp: //231.20 .20.8: 2005? Buffer_size = 26214400 "

tuttavia, questo non ha risolto il problema. ffmpeg otterrebbe ancora "sovraccarico del buffer circolare" e crash. E non potevo riprodurre questo sovraccarico di buffer circolare, stava accadendo casualmente.

mio pensiero successivo è stato la dimensione del buffer del tubo in quanto ho trovato seguendo:

http://blog.dataart.com/linux-pipes-tips-tricks/ La dimensione del buffer dal kernel versione 2.6.11 è 65536 byte (64K) ed è uguale alla memoria di pagina in vecchi kernel. Quando si tenta di leggere da un buffer vuoto, il processo di lettura è bloccato fino alla visualizzazione dei dati. Allo stesso modo, se si tenta di scrivere su un buffer completo, il processo di registrazione verrà bloccato fino a quando non sarà disponibile la quantità di spazio necessaria. http://ffmpeg.gusari.org/viewtopic.php?f=12&t=624 Poster1: Che cosa causa questi sovraccarichi di buffer circolare? La mia ipotesi è che ffmpeg stia leggendo il flusso di input nel buffer circolare sopra menzionato, e il codice quindi generi il flusso di output che legge dallo stesso buffer. L'overrun si verifica quando il codice che genera l'output non tiene il passo con la velocità con cui viene scritto nel buffer, giusto? Poster2: Osservando il codice sorgente, sembra che il buffer trabocchi sia dall'input troppo veloce sia dall'output troppo lento (cpu? Lento). La tua ipotesi è corretta.

Quindi la teoria era che il nostro file binario non legge abbastanza veloce. Come risultato la pipe viene bloccata e ffmpeg non può scrivere su di essa, e QUESTO risulta in overpump del buffer udp fifo (ffmpeg continua a leggere udp INTO FIFO, ma non può scrivere da esso nella nostra pipe)

Sono riuscito a dimostrare questa teoria con in esecuzione (in terminali separati):

mkfifo mypipe 
ffmpeg -loglevel debug -i "udp://192.168.15.50:3200?fifo_size=1000000&overrun_nonfatal=1" -r 8 -preset ultrafast -fflags nobuffer -vf scale=432:243 -f image2pipe -vcodec ppm pipe:1 > mypipe 
cat <mypipe> /dev/null # run this for 10 seconds, allowing ffmpeg to start. then pause it with CTRL-Z and see ffmpeg crashing because it cannot read more udp stream 

quindi la prossima è stata la ricerca del perché il nostro file binario a un certo punto smette di leggere la pipe. sembrava che non ci fosse alcun motivo, perché normalmente si limitava a leggere in memoria immediatamente dopo che qualcosa era finito.

tuttavia, è stato anche salvare i frame sul disco rigido. ea SOME POINT (a volte 12 minuti, a volte 15 ore), le operazioni del disco rallentavano a causa delle operazioni di lettura/scrittura (era bcache (SSD e HDD ibrido, utilizza SSD come cache). alcuni milioni di file da questa unità paralelly per il debug.

così la scrittura di file sul disco rigido occupato potrebbe bloccare temporaneamente il nostro binario dalla lettura del tubo di ingresso.

così motivo per UDP buffer circolare problema superamento e l'eventuale timeshift è stato un L'HDD e la soluzione teorica è SSD

Questa indagine è durata circa 3 settimane, quindi postare tutto questo nella speranza che almeno in parte possa aiutare qualcuno in futuro

aggiornamento a questo:

ho anche rilevato un altro strozzatura provocando lo stesso problema più avanti (sostituzione HDD non era sufficiente), che era tcp buffer overflow presa causata da postgres inserzioni sul back-end.

l'intera pipeline sembra che:

udp_videostream-> ffmpeg-> linux_pipe-> our_client_side_binary-> TCP-> our_server_side_binary-> Postgres

Postgres domande erano volte lento, che provocava il nostro server per leggere il socket TCP più lentamente di quanto our_binary ci stesse spingendo. di conseguenza, il socket TCP sarebbe stato bloccato (era massimo 4Mb), e come risultato, il client avrebbe bloccato la sua pipe di input, e come risultato di tale ffmpeg si sarebbe bloccato con questo errore CBO.