Il “contenitore” di WebP: struttura, idea, e limiti

Nel precedente articolo su WebP abbiamo analizzato le motivazioni che hanno portato Google a tirare fuori dal cilindro questo nuovo formato per memorizzare le immagini, in che modo sono stati realizzati i test, e la qualità dei file generati col nuovo arrivato.

Oltre all’algoritmo che determina in maniera preponderante lo spazio occupato, a contribuire allo scopo è anche il cosiddetto “contenitore” necessario per memorizzare in maniera opportuna i dati compressi, e di cui avevamo accennato prima.

In realtà la scelta del contenitore cela anche l’operazione che è stata fatta per arrivare a definire il WebP, per cui l’argomento non meritava di essere liquidato in poche righe ma, al contrario, sviscerato per comprenderne meglio la portata e le implicazioni.

Sappiamo che Google ha deciso di sfruttare l’esistente RIFF (nato, fra l’altro, dal famosissimo IFF onnipresente su Amiga) introducendo appositi tag (“chunk” nel gergo IFF/RIFF) per identificare correttamente WebP, e permetterne il corretto parsing e/o manipolazione.

Lo schema è estremamente semplice:

Come si può vedere, occupa appena 20 byte, di cui 12 dedicati ai 3 chunk (ognuno occupa sempre 4 byte) necessari a identificarlo. A RIFF e VP8 seguono sempre 4 byte che specificano la lunghezza del chunk (rispettivamente quella dell’intero file, e dei dati dell’immagine compressa), mentre soltanto WEBP non è dotato del campo lunghezza e serve esclusivamente a specificare il tipo di file RIFF che si sta leggendo (WEBP, appunto).

Dopo i dati del chunk VP8 possono essere presenti i chunk ICMT, ICOP, IART, e INAM, utilizzati per memorizzare i metadati opzionali relativi ai commenti, al copyright, al nome dell’artista e al titolo.

Ciò che balza immediatamente all’occhio è l’assenza dei metadati fondamentali, quelli che descrivono le caratteristiche intrinseche dell’immagine: risoluzione, profondità (numero di bit per componente cromatica), spazio colore utilizzato, e numero di componenti cromatiche (eventualmente incluso l’alpha channel). Eventualmente anche il formato di compressione utilizzato, per poterne specificarne altri in futuro.

Queste informazioni sono generalmente disponibili nella struttura del contenitore, come si può verificare facilmente andando ad analizzare altri formati grafici:

Appare chiara e netta la suddivisione fra i metadati e i dati dell’immagine effettivamente codificati. Questo anche nel PNG, che è un formato molto simile a WEBP (poiché basato anch’esso sull’idea dei chunk).

Anche volendosi sforzare, cercando nei 20 byte del RIFF non esiste nessun metadato disponibile. Per cui è chiaro, a questo punto, che l’unico posto in cui si possano trovare è all’interno dei dati del chunk VP8. Come suggerisce la FAQ, bisogna conoscere la struttura dello stream di dati VP8, che si trova a pagina 10 e seguenti.

Scopriamo, così, che i dati degli intra-frame (o key-frame) sono costituiti da un header di 10 byte, a cui seguono i dati (suddivisi in macroblocchi). Poiché WebP memorizza una sola immagine VP8, di tipo intra-frame, sappiamo che i primi 10 byte del chunk VP8 forniranno le informazioni sui metadati che cerchiamo, che troviamo, infatti, a partire da pagina 28.

Da qui emergono, oltre a quelli cercati (risoluzione, eventuale scaling orizzontale e/o verticale dell’immagine, filtro di postprocessing da utilizzare, spazio colore), diversi attributi che riguardano esclusivamente il segnale video, segno di come questo formato sia giustamente stato pensato per questo tipo di applicazioni.

La cosa più importante di cui prendere atto è che i metadati sono confluiti nei dati dello stream codificato, anziché essere messi a disposizione nella struttura del file RIFF. Questo significa che, se in futuro si dovesse adottare una nuova codifica (una VP9, ad esempio), un’applicazione che fornisce informazioni sul file dovrà necessariamente essere aggiornata per parserizzare il relativo chunk ed estrarre ciò che le serve.

Se, invece, fossero state disponibili nella struttura RIFF, l’astrazione fornita avrebbe consentito di leggerle e mostrarle a prescindere dalla codifica utilizzata per i dati, similmente a quanto avviene, ad esempio, coi JPEG, dove i dati possono essere codificati in maniera diversa (compressione di Huffman o aritmetica) ma i metadati sono disponibili a prescindere da ciò. La separazione fra metadati e dati ha un vantaggio non indifferente.

A conti fatti, inoltre, l’overhead del contenitore scelto non può certo limitarsi ai 20 byte sbandierati, ma deve necessariamente includere anche le strutture che conservano i citati metadati, per cui vanno conteggiati almeno 30 byte (più diversi altri bit utilizzati a seguire). Rimane indubbiamente una quantità effimera, ma per correttezza va messa in evidenza.

Come va sottolineato il fatto che l’utilizzo di strutture dati così piccole e già ampiamente utilizzate (sono pochi i bit rimasti liberi, quindi senza aggiungere ulteriori strutture che produrrebbero stream incompatibili con l’esistente VP8) pone serii problemi all’espandibilità futura, già minata da forti limitazioni, come l’uso di un solo spazio colore (cioè lo YUV), il sampling delle componenti cromatiche fissato a 4:2:0, e la presenza di tre componenti fisse (Y, U, e V appunto). Sarà interessante vedere, a questo punto, in che modo introdurranno l’alpha channel (magari come chunk a parte).

In conclusione, la mia impressione è che la scelta del contenitore rifletta una banale operazione di copia & incolla. Google aveva già tra le mani la libreria in grado di codificare un’immagine in uno stream VP8 di tipo key-frame, e non ha fatto altro che prenderne il risultato e copiarlo integralmente, senza alcuna modifica, subito dopo il contenitore RIFF fisso di 20 byte. Idem per il processo di decodifica, in maniera speculare.

Un esercizietto di poca roba, insomma. Nulla di trascendentale e, soprattutto, che abbia richiesto tempi di sviluppo consistenti. WebP nasce, quindi, da un’idea che si è concretizzata molto velocemente e, da quanto detto finora, altrettanto in fretta ha mostrato già diversi limiti, mentre di altri ne discuteremo prossimamente.

Press ESC to close