Riprendere una codifica parzialmente completata con FFmpeg

Sep 26 2020

Sommario

Data una codifica parzialmente completata che:

  • È stato codificato utilizzando h264 nel contenitore Matroska
  • È stato interrotto interrompendo manualmente FFmpeg digitando "q" nella console

... quali sono i modi per riprendere la codifica di questo file, preferibilmente aggiungendo il file esistente?

Dettagli

Ho alcuni grandi progetti di codifica che faccio che in alcuni casi possono richiedere fino a una settimana di codifica. In circostanze ideali, il computer che esegue la codifica può rimanere acceso, senza interruzioni e lasciato a fare il lavoro. In situazioni realistiche, tuttavia, a volte quel computer deve interrompere la codifica ed essere spento o riavviato per una moltitudine di motivi. Per questo motivo, sto cercando un modo per rendere la codifica utilizzando FFmpeg su quel computer più "a prova di proiettile" anticipando possibili interruzioni e avendo un modo per usare FFmpeg da solo per riprendere da dove si era interrotto in seguito.

Quello che sto facendo adesso

Quando ciò accade, recupero quello che posso del file codificato, lo esamino in un software di editing video, trovo un buon punto di giunzione, quindi uso AviSynth per creare uno script che inizierà a codificare un nuovo segmento da dove si era interrotto il precedente. Quindi uso altro software per tagliare la codifica esistente in modo che la giunzione sia perfetta, quindi uso il demuxer di FFmpeg per combinare i singoli segmenti h264 in un secondo momento in un file completato.

Questo è tutto un sacco di lavoro manuale che può essere molto lento che vorrei evitare se esiste una soluzione più automatizzata.

Idee

Segmentazione: questa sembra la soluzione più promettente, ma ci sono delle lacune che non so come colmare. Questa risposta sembra coprirne molto. Puoi dire a FFmpeg di produrre segmenti, suddivisi in I-Frame a intervalli approssimativi, che possono essere rimossi in seguito. Quello che non so guardando quella risposta e la documentazione di FFmpeg è come ricomincerei a codificare in un segmento specifico. Sembra che ci possa essere un modo per dare a FFmpeg un file che gli dice dove dovrebbe iniziare ogni segmento tramite frame o timecode, ma come faccio a farlo iniziare da qualche parte nel mezzo di quella lista?

Questa opzione non è l'ideale, tuttavia, in quanto dovrò avere effettivamente il doppio dello spazio della codifica risultante (che sarà spesso di dimensioni pari a centinaia di gigabyte) disponibile poiché avrò bisogno di mux i segmenti in un singolo file. Sarebbe bello se potessi in qualche modo tagliare in modo netto una codifica in corso e fare in modo che FFmpeg riaprisse quel file e continuasse da dove era stato interrotto.

Macchine virtuali: questo ha il potenziale per funzionare dal momento che potrei semplicemente bloccare lo stato della macchina prima di un riavvio, ma tutto il mio spazio di codifica esiste sullo storage collegato alla rete, che non sono sicuro funzionerà nel contesto di una macchina virtuale sospeso e ripreso, poiché la VM non controlla effettivamente le unità.

Risposte

1 ZachF. Oct 02 2020 at 13:44

Ho trovato una soluzione "abbastanza buona" a questo problema, poiché al momento della scrittura non sembra possibile prendere effettivamente una codifica parziale che è stata tagliata arbitrariamente e concatenarvi accuratamente il resto del video .

Una soluzione che utilizza la segmentazione

Innanzitutto, usa la funzionalità di segmentazione di FFmpeg per generare segmenti in un intervallo per il quale la perdita di tale intervallo è una perdita accettabile. Produce anche un file .csv con l'ora di inizio e di fine del segmento. Un comando di esempio che ottiene ciò è:

ffmpeg.exe -i .\source.avi -c:v libx264 -crf 20 -c:a aac -pix_fmt yuv420p -f segment -segment_time 30 -segment_list segments.csv -reset_timestamps 1 seg%03d.mkv

Supponiamo che durante la codifica del quarto segmento (seg003.mkv), sia necessario arrestare l'encoder e resettare la macchina. L'invio di una qsequenza di tasti a FFMpeg durante la codifica di un segmento lo interrompe arbitrariamente a un certo punto e lascia quel segmento incompleto.

Il segmento che è stato interrotto viene effettivamente perso e può essere eliminato. L'apertura del file segment.csv rivela

seg000.mkv,0.000000,33.390000
seg001.mkv,33.390000,62.586000
seg002.mkv,62.586000,91.782000
seg003.mkv,91.782000,98.655000

Usando queste informazioni, sappiamo che seg003.mkv è iniziato a 91,782 secondi nel sorgente. Per riprendere da dove avevamo lasciato, usiamo lo stesso comando di cui sopra per codificare l'output segmentato, ma anche seek ( -ss) all'inizio del nostro quarto segmento e cambiamo la numerazione ( -segment_start_number):

ffmpeg.exe -ss 91.782000 -i source.avi -c:v libx264 -crf 20 -c:a aac -pix_fmt yuv420p -f segment -segment_time 30 -segment_list segments2.csv -segment_start_number 3 -reset_timestamps 1 seg%03d.mkv

FFmpeg riprenderà all'inizio del quarto segmento e lo chiamerà correttamente seg003.mkv. Si noti che il nome del file .csv di output è stato modificato in modo che l'originale non venga sovrascritto. Questo nuovo file .csv inizierà a 0.00, quindi ulteriori interruzioni richiederanno l'aggiunta di volte in questo file al file precedente per trovare un punto di partenza.

Infine, quando tutti i segmenti sono pronti per essere concatenati, costruiamo un file .ffcat come delineato negli esempi sulla pagina wiki :

file seg000.mkv
file seg001.mkv
file seg002.mkv
file seg003.mkv
file seg004.mkv
file seg005.mkv

ed esegui questo comando:

ffmpeg.exe -f concat -i .\segments.ffcat -c copy output.mkv

Questo restituisce la codifica completa e concatenata. L'opzione -fflags +genptsè menzionata nella risposta collegata alla domanda e potrebbe essere necessaria per ottenere un output perfetto, ma non ho trovato che faccia alcuna differenza nei miei test.