Un MP4 è una scatola di scatole
Un file MP4 è costruito a partire da scatole («box»). (Il nome più antico che la specifica dà loro, atomi, è quello che ha attecchito nei messaggi di errore.) Ogni scatola inizia con la stessa intestazione di 8 byte: 4 byte che indicano quanto è grande la scatola, poi 4 caratteri che dicono di che tipo di scatola si tratta. Questa è tutta la grammatica. Le scatole possono contenere altre scatole, e un analizzatore percorre il file leggendo un'intestazione, decidendo se guardarci dentro e saltando in avanti, in base alla dimensione dichiarata, fino alla successiva.
Apri una qualsiasi registrazione terminata (da un telefono, una GoPro, OBS, un drone) e al livello superiore troverai le stesse tre scatole a fare tutto il lavoro:
Dichiara «questo è un MP4» e quale variante del formato i lettori devono aspettarsi. La prima cosa presente nel file.
I fotogrammi audio e video compressi, impacchettati uno di seguito all'altro nell'ordine in cui sono stati registrati. Senza etichette, senza marche temporali, senza confini di fotogramma visibili dall'esterno, solo carico utile.
La mappa di tutto ciò che c'è sopra: dove inizia ogni fotogramma, quanto occupa, quando viene riprodotto. Scatole dentro scatole:
I file MOV, il formato QuickTime da cui l'MP4 deriva, condividono questa stessa identica struttura, ed è per questo che un MOV che non si apre e un MP4 che non si apre sono quasi sempre lo stesso problema con un'estensione diversa.
L'atomo moov è la mappa
Ecco la parte che sorprende le persone: il blocco dati è opaco. I fotogrammi compressi stanno uno di seguito all'altro in mdatsenza nulla a separarli, senza marcatori che dicano «il fotogramma 412 inizia qui». Ogni domanda a cui un lettore ha bisogno di rispondere vive invece nell'atomo moov, in un insieme di strutture chiamate tabelle dei campioni:
- Dove si trova ogni fotogramma? La tabella degli offset dei chunk (
stco) registra le posizioni in byte dentro il file. - Quanto occupa ogni fotogramma? La tabella delle dimensioni dei campioni (
stsz) elenca la lunghezza di ogni fotogramma, una voce per fotogramma. - Quando viene riprodotto ogni fotogramma? La tabella tempo-per-campione (
stts) fa corrispondere i fotogrammi all'orologio del filmato, così che audio e video restino perfettamente sincronizzati. - A quali punti può saltare la riproduzione? La tabella dei campioni di sincronizzazione (
stss) elenca i fotogrammi chiave, gli unici da cui un decodificatore può partire, ed è ciò che rende possibile il posizionamento rapido.
Persino la configurazione del decodificatore (i parametri che gli dicono come è stato compresso il video) è memorizzata nell'atomo moov, non nel flusso. A un lettore senza l'atomo moov non mancano solo i marcatori di capitolo; non sa dove inizia un singolo fotogramma, quanto dura il video né come impostare il suo decodificatore. Pensa a una biblioteca dove i libri sono a scaffale senza dorsi, senza titoli e senza catalogo: l'informazione esiste tutta, e nessuna di essa è raggiungibile. Questo èmdat senza moov, ed è per questo che i lettori si arrendono del tutto invece di riprodurre «la maggior parte» di un file danneggiato.
Perché l'indice viene scritto per ultimo
L'atomo moov descrive ogni fotogramma: la sua posizione, la sua dimensione, i suoi tempi. Mentre registri, nulla di tutto ciò è conoscibile: la fotocamera non ha idea se ti fermerai fra dieci secondi o fra due ore, e l'offset in byte di un fotogramma non può essere registrato prima che il fotogramma esista. Perciò ogni registratore fa l'unica cosa che può. Riversa i fotogrammi compressi in mdat man mano che vengono codificati, tiene la contabilità in corso in memoria e scrive l'indice in un'unica passata nel momento in cui premi «stop».
Durante la registrazione: i fotogrammi vengono aggiunti man mano che si codificano. L'indice non può ancora esistere; il suo contenuto non è noto finché non viene scritto l'ultimo fotogramma.
Finalizzazione: il registratore misura tutto ciò che ha scritto e aggiunge l'atomo moov. Solo ora il file è riproducibile.
Questo progetto è efficiente e sicuro, giusto fino a quando la registrazione non raggiunge il passaggio di finalizzazione. Una batteria scarica, un crash di OBS, un drone in un lago: il processo che scrive il file si ferma e l'indice non viene mai scritto. Ciò che resta sul disco è un file con una dimensione sana, ore di immagini intatte inmdat e nessuna mappa. Ogni lettore lo rifiuta; ffmpeg stampamoov atom not found. Le immagini non sono sparite; sono arenate. (Gli ultimissimi secondi, ancora nel buffer di memoria della fotocamera e non ancora scaricati sull'archivio, sono spariti. Gli strumenti onesti lo dicono.) Quello stato «arenato ma intatto» è esattamente ciò per cui esiste la riparazione dell'atomo moov, ed è il modo di guasto tipico delle registrazioni di OBS che vanno in crash.
faststart e MP4 frammentato
Il progetto con l'indice alla fine ha due conseguenze ben note, e l'industria ha costruito una soluzione per ciascuna.
faststart: spostare l'indice all'inizio, a posteriori
Un browser che riproduce in streaming un video dal web legge il file dal principio alla fine. Se l'atomo moov è alla fine, la riproduzione non può iniziare finché non è stato scaricato l'intero file; il lettore ha il libro in mano e aspetta il catalogo. La soluzione è una passata di post-elaborazione (il -movflags +faststart di ffmpeg) che riscrive il file terminato con l'atomo moov spostato all'inizio:
Un file «faststart»: prima l'indice, così che la riproduzione in streaming possa iniziare immediatamente. È per questo che alcuni video web partono all'istante e altri si bloccano.
Nota bene cosa faststart non è: protezione dai crash. Viene eseguito su un file completo e sano dopo che la codifica è terminata. Una registrazione che muore a metà scrittura non raggiunge mai quel passaggio.
MP4 frammentato: tanti piccoli indici al posto di uno grande
La seconda conseguenza (se perdi la finalizzazione, perdi il file) è risolta dall'MP4 frammentato. Invece di unmdat e un moov alla fine, il file viene scritto come una catena di brevi segmenti autodescrittivi, ciascuno una porzione di dati con il proprio mini-indice (una scatola moof). In termini di ffmpeg, -movflags frag_keyframe+empty_moov: un moov scheletro all'inizio, poi frammento dopo frammento. Se il registratore muore, perdi al massimo l'ultimo frammento, e tutto ciò che lo precede è già indicizzato e riproducibile. I servizi di streaming distribuiscono il video in questo modo per la stessa ragione. Il compromesso è la compatibilità: alcuni editor e i lettori più vecchi gestiscono male i file frammentati, ed è per questo che le fotocamere continuano a scrivere la disposizione classica. La risposta di OBS (in OBS 30.2 e versioni successive) è l'«MP4 ibrido», che mantiene la resistenza ai crash in stile frammentato pur finalizzando in un file ampiamente compatibile, qualcosa che vale la pena attivare se i crash di OBS ti hanno già scottato in passato.
Come funziona la ricostruzione del moov
Dunque un crash ti ha lasciato con ftyp, unmdat gigantesco e nessun indice. Ricostruirlo è possibile perché il blocco dati «opaco» non è del tutto opaco per un analizzatore che conosce i codec. Dentro mdat, i fotogrammi video sono memorizzati come unità con prefisso di lunghezza, e il flusso di bit di ogni codec ha schemi riconoscibili: intestazioni che marcano il tipo, le dimensioni e i confini di un fotogramma. Gli strumenti di ricostruzione (il progetto open source untrunc ha consolidato l'approccio, ed è la classe di riparazione che esegue il motore video di IntactFile) percorrono i dati grezzi byte per byte:
- Individuare i confini dei fotogrammi. Scansionare
mdat, usando i prefissi di lunghezza e le firme del codec per identificare dove inizia e finisce ogni fotogramma video e audio. - Classificare e misurare. Assegnare ogni fotogramma al suo flusso e registrarne dimensione e posizione, ricostruendo campione dopo campione la materia prima di
stszestco. - Ricostruire i tempi. Dedurre la durata dei fotogrammi dalle impostazioni del codificatore. È per questo che
untruncchiede un file di riferimento in buono stato registrato con le stesse impostazioni, per imparare com'è il «normale» per il tuo dispositivo. - Scrivere un nuovo moov e finalizzare. Assemblare le tabelle dei campioni in un indice nuovo e scrivere un file corretto secondo la specifica.
Il risultato riproduce tutto ciò che è sopravvissuto fisicamente, terminando dove terminano i dati. Le limitazioni oneste derivano direttamente dal meccanismo: le registrazioni con tempi di fotogramma molto irregolari possono tornare con un lieve disallineamento tra audio e video, e se lo stesso mdat è composto di zeri (ha ceduto l'archivio, non il registratore) non ci sono fotogrammi da trovare, e nessuno strumento può evocarli. Per il quadro più ampio su quale danno sia quale, vedi come si corrompono i file video e cosa è davvero riparabile.
Domande frequenti
Cos'è l'atomo moov in un file MP4?
L'atomo moov è l'indice dell'MP4: un blocco strutturato che registra dove si colloca nel file ogni fotogramma video e audio, quanto occupa ciascuno, quando deve essere mostrato e come si sincronizzano i flussi. Contiene anche la configurazione del decodificatore. Il lettore legge per primo l'atomo moov e lo usa come mappa verso i dati multimediali. Senza un atomo moov valido, il file non si apre, anche quando le immagini in sé sono intatte.
Perché l'atomo moov si trova alla fine del file?
Perché il suo contenuto non è noto finché la registrazione non termina. L'atomo moov elenca la dimensione, la posizione e i tempi di ogni fotogramma, informazioni che esistono solo una volta scritto l'ultimo fotogramma. Perciò i registratori aggiungono i fotogrammi man mano e scrivono l'indice in un'unica passata alla finalizzazione, il che lo colloca dopo i dati multimediali. I file preparati per lo streaming web hanno spesso il moov spostato all'inizio a posteriori («faststart»), ma questo è un passaggio di post-elaborazione, non il modo in cui il file nasce.
Un atomo moov mancante può essere ricostruito?
Di solito sì, a condizione che i dati multimediali (il blocco mdat) siano sopravvissuti. Gli strumenti di ricostruzione scansionano il flusso grezzo, rilevano i confini di ogni fotogramma, misurano dimensioni e posizioni e ricostruiscono le tabelle dei campioni che l'atomo moov avrebbe contenuto. Il risultato è un file riproducibile che copre tutto fino al punto dell'interruzione. Se il blocco mdat manca, è azzerato o è stato sovrascritto, non c'è nulla da indicizzare, e nessuno strumento può ricostruire il file. Puoi controllare un file nel tuo browser per vedere in quale dei casi si trova il tuo.
Qual è la differenza tra moov e mdat?
Il mdat contiene il carico utile: i fotogrammi audio e video compressi, impacchettati uno di seguito all'altro, tipicamente il 99% della dimensione del file. Il moov contiene i metadati: l'indice che descrive dove inizia ogni fotogramma dentro il mdat, la sua dimensione, i suoi tempi e le impostazioni del decodificatore necessarie per riprodurlo. Un mdat senza moov sono immagini senza mappa: i dati ci sono, ma nessun lettore può navigarci. Un moov senza mdat è la mappa di un territorio che non esiste più.
Cosa fa movflags faststart?
In ffmpeg, -movflags +faststart sposta l'atomo moov dalla fine di un file finito all'inizio, subito dopo l'intestazione del tipo di file. I lettori possono così avviare la riproduzione mentre il resto del file è ancora in download, ed è per questo che è lo standard per il video web. Richiede la riscrittura del file (ffmpeg esegue una seconda passata) e funziona solo su un file sano e completo. Non protegge una registrazione dai crash e non può riparare un file il cui moov non è mai stato scritto.
Anche in questa serie: come si corrompono i file video — e cosa è davvero riparabile.