@matteocontrini piccolo OT perché volevo scrivere in PVT ma non ho riferimenti:
Sei per caso esperto di FFMPEG? Hai per caso qualche riferimento su siti/forum attendibili su problematiche di streaming da IP Camera, NVS, Onvif etc?
Grazie.
(dopo puoi anche cancellare questa discussione)
Riferimenti riguardo ffmpeg e RTSP
LennyKrost sì conosco piuttosto bene ffmpeg e in generale la codifica video, IP camera un po' meno. Se esponi il problema vedo se riesco ad aiutarti.
Per problematiche strettamente legate a ffmpeg ci sono /r/ffmpeg e Video StackExchange, dove ci sono anche alcuni sviluppatori di ffmpeg (e ogni tanto contribuisco anche io).
Poi dipende dal problema però...
Infatti ho notato qualche tuo contributo su StackExchange.
Il quesito riguarda la registrazione da IPCamera attraverso flusso RTSP (video + eventuale audio) utilizzando appunto FFMPEG (per Windows). Il problema è trovare un giusto compromesso codec video - container che supporti il "segmentation", ossia la frammentazione dei file durante la registrazione per evitare la creazione di files da diversi GIGA ciascuno.
Che ne pensi?
LennyKrost la segmentazione la può fare ffmpeg durante la registrazione, e il container non ha importanza perché ffmpeg chiude semplicemente il file dopo X secondi e ne apre un altro. Ad esempio così:
ffmpeg -i rtsp://ecc -c copy -f segment -segment_time 600 -segment_format mp4 "output-%04d.mp4"
I file in uscita sono MP4 di max 10 minuti ciascuno. Come codec viene mantenuto quello trasmesso dalla videocamera (-c copy
), che se è H.264 non ci sono problemi di compatibilità.
Se c'è la necessità di ricodifica/compressione, questo è un caso in cui è adatta la codifica x264 CRF (a qualità costante e bitrate variabile):
ffmpeg -i rtsp://ecc -crf 23 -c:a copy -f segment -segment_time 600 -segment_format mp4 "output-%04d.mp4"
Se il file è troppo grande si può alzare il valore CRF e vedere fino a che punto la qualità è accettabile (fino a 27-30 la qualità è ancora ok). Un valore più alto sacrifica la qualità ottenendo un bitrate medio più basso, un CRF più l'opposto. Il default è 23, mentre sotto il 18 la qualità è considerata "placebo".
Per ricodificare anche l'audio (molte IP cam trasmettono audio PCM, che non è il massimo) basta togliere -c:a copy
e di default ricodifica in aac.
Buongiorno Matteo,
grazie per la spiegazione esauriente; finalmente ho capito il significato del parametro crf.
E niente, non si scappa: il container mp4 è l'unico utilizzabile in tutti i contesti (devo gestire diverse IPCamera con marchi differenti), per cui userò il template che mi hai suggerito.
Infine altra cosa importante è che la segmentazione in mp4 permette comunque la riproduzione dei singoli file ma bisogna fare attenzione con l'ultimo, perché se si "killa" ffmpeg per interrompere la registrazione, l'ultimo file non è chiuso correttamente e la riproduzione non va.
LennyKrost il container mp4 è l'unico utilizzabile in tutti i contesti
Con il comando sopra però il muxing (cioè l'operazione di mettere il flusso video nel container) la fa ffmpeg ed è indipendente dalla sorgente. Quindi puoi anche scegliere altro.
LennyKrost bisogna fare attenzione con l'ultimo, perché se si "killa" ffmpeg per interrompere la registrazione, l'ultimo file non è chiuso correttamente e la riproduzione non va.
Se lo killi di brutto sì, ma se premi "q" sulla tastiera chiude (o dovrebbe chiudere) il file correttamente. In alternativa puoi usare MPEG-2 Transport Stream come contenitore, che è tollerante alle interruzioni forzate perché ogni pacchetto interno al file è indipendente dagli altri. È il formato container usato dalla televisione digitale ad esempio, perché il segnale che arriva tramite l'antenna è un flusso continuo che non ha inizio né fine, quindi una cosa come MP4 non andrebbe bene.
Diventerebbe così:
ffmpeg -i rtsp://ecc -c copy -f segment -segment_time 600 "output-%04d.ts"
- Modificato
Come tesi di laurea ho portato avanti un progetto che tra le varie cose prevedeva la registrazione di una IP Camera, e uno dei problemi era appunto che in caso di mancanza di corrente il file risultava corrotto. Con Transport Stream o Program Stream (è un po' più leggero, ha meno overhead) il problema si risolve.
- Modificato
matteocontrini Se lo killi di brutto sì, ma se premi "q" sulla tastiera chiude (o dovrebbe chiudere) il file correttamente.
Il problema è quello, far premere "q" non da utente ma da un programma che gira in background. Il tutto deve essere automatizzato. Mi inventerò qualcosa.
Nel frattempo grazie per i consigli.
Poi se nel frattempo ffmpeg avesse la piena compatibilità anche col formato DAV, sarebbe perfetto.
LennyKrost in quel caso bisogna inviare il segnale di stop SIGINT o SIGTERM, da verificare.
Prego
Se interessa qualche altro spunto a riguardo, qui un mio post del 2014 (!)
https://lucatnt.com/2014/08/record-and-archive-video-from-ip-cameras/
LucaTNT
Ti ringrazio per il contributo.
Buongiorno.
@matteocontrini hai per caso esperienze di utilizzo di VLC come server di streaming (HTTP/RTSP ecc.)?
Ciao @matteocontrini,
rispolvero questo post per una domanda su ffmpeg, sempre che tu voglia/possa supportarmi.
Ho un flusso in ingresso RTSP da telecamera, con un unico comando ffmpeg vorrei scrivere su file e contemporaneamente reindirizzare il flusso su un altro server RTSP che si occupi del broadcasting verso altri clients.
Ho visto il formato "tee" e "fifo" per la gestione della cosa e tutto funzionerebbe alla perfezione se non fosse che, nel caso in cui il server RTSP di destinazione si bloccasse/riavviasse, lo stream non si riprenderebbe autonomamente. Dovrei in quel caso interrompere tutto il comando ffmpeg, quindi anche la registrazione, per ripristinare il flusso verso il server RTSP.
Hai qualche suggerimento in merito?
Ti ringrazio e scusa per il disturbo.
LennyKrost ciao, una cosa che mi viene in mente al volo (e che pare funzionare facendo un rapido test) è quella di usare due istanze di ffmpeg e passare i dati da una all'altra, ad esempio tramite UDP su localhost.
La prima istanza farebbe ffmpeg -i INPUT -c copy -f mpegts udp://localhost:1234
(ovviamente adatta con tutti i tuoi eventuali parametri di codifica e aggiungi la registrazione su file).
La seconda: ffmpeg -i udp://localhost:1234 -c copy rtsp://output
(ho testato con ffplay ma dovrebbe funzionare allo stesso modo con ffmpeg).
La seconda istanza probabilmente muore quando il server di destinazione va KO e a quel punto dovresti riavviare il comando. Puoi farlo con un semplice script che mette il comando in "loop" (o ancora più brutalmente con un cron che controlla se il comando è ancora su).
Se il secondo comando non è in esecuzione il primo se ne frega, trattandosi di UDP (manda quindi i dati verso il nulla).
Un'alternativa sono forse le named pipe su Linux (mkfifo
) ma ho dei dubbi possano funzionare per il fatto che se nessuno legge dalla pipe chi ci scrive a un certo punto esaurirà il buffer e probabilmente si bloccherà.
matteocontrini Ciao. Grazie per la risposta. Questa che mi hai suggerito è la soluzione migliore per quello che devo fare. Sfortunatamente rimane un problema irrisolto che riguarda l'avvio della seconda istanza di ffmpeg quando il server di destinazione non è raggiungibile.
Come hai specificato, la seconda istanza si chiude automaticamente (broken pipe) nel momento in cui arresto il server RTSP.
Ma se la seconda istanza si avvia "mentre" il server non è attivo, questa rimane in stato freeze e non si chiude automaticamente.
Credo che dovrò per forza dirottare l'output su un file e monitorarne la crescita per capire se c'è qualcosa che non va. Purtroppo a quanto pare non esiste un controllo di errore se un flusso in output di ffmpeg non funziona.
LennyKrost potresti inviare un esempio di output?